]> jfr.im git - solanum.git/commitdiff
[svn] - the new plan:
authornenolod <redacted>
Thu, 25 Jan 2007 06:40:21 +0000 (22:40 -0800)
committernenolod <redacted>
Thu, 25 Jan 2007 06:40:21 +0000 (22:40 -0800)
  + branches/release-2.1 -> 2.2 base
  + 3.0 -> branches/cxxconversion
  + backport some immediate 3.0 functionality for 2.2
  + other stuff

430 files changed:
.cvsignore [new file with mode: 0644]
.indent.pro [new file with mode: 0644]
BUGS [new file with mode: 0644]
CREDITS [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
INSTALL [new file with mode: 0644]
LICENSE [new file with mode: 0644]
Makefile.in [new file with mode: 0644]
NEWS [new file with mode: 0644]
README.FIRST [new file with mode: 0644]
SVN-Access [new file with mode: 0644]
aclocal.m4 [new file with mode: 0644]
configure [new file with mode: 0755]
configure.ac [new file with mode: 0644]
doc/.cvsignore [new file with mode: 0644]
doc/CIDR.txt [new file with mode: 0644]
doc/Hybrid-team [new file with mode: 0644]
doc/Makefile.in [new file with mode: 0644]
doc/README.cidr_bans [new file with mode: 0644]
doc/Ratbox-team [new file with mode: 0644]
doc/Tao-of-IRC.940110 [new file with mode: 0644]
doc/challenge.txt [new file with mode: 0644]
doc/collision_fnc.txt [new file with mode: 0644]
doc/example.conf [new file with mode: 0755]
doc/extban.txt [new file with mode: 0644]
doc/hooks.txt [new file with mode: 0644]
doc/index.txt [new file with mode: 0644]
doc/ircd.8 [new file with mode: 0644]
doc/ircd.motd [new file with mode: 0644]
doc/logfiles.txt [new file with mode: 0644]
doc/modeg.txt [new file with mode: 0644]
doc/modes.txt [new file with mode: 0644]
doc/monitor.txt [new file with mode: 0644]
doc/old/Authors [new file with mode: 0644]
doc/operguide.txt [new file with mode: 0644]
doc/opermyth.txt [new file with mode: 0644]
doc/reference.conf [new file with mode: 0755]
doc/server-version-info [new file with mode: 0644]
doc/services.txt [new file with mode: 0644]
doc/sgml/oper-guide/charybdis-oper-guide.sgml [new file with mode: 0644]
doc/sgml/oper-guide/cmodes.sgml [new file with mode: 0644]
doc/sgml/oper-guide/commands.sgml [new file with mode: 0644]
doc/sgml/oper-guide/config.sgml [new file with mode: 0644]
doc/sgml/oper-guide/intro.sgml [new file with mode: 0644]
doc/sgml/oper-guide/oprivs.sgml [new file with mode: 0644]
doc/sgml/oper-guide/stylesheet.dsl [new file with mode: 0644]
doc/sgml/oper-guide/ucommands.sgml [new file with mode: 0644]
doc/sgml/oper-guide/umodes.sgml [new file with mode: 0644]
doc/technical/README.TSora [new file with mode: 0644]
doc/technical/capab.txt [new file with mode: 0644]
doc/technical/cluster.txt [new file with mode: 0644]
doc/technical/euid.txt [new file with mode: 0644]
doc/technical/event.txt [new file with mode: 0644]
doc/technical/fd-management.txt [new file with mode: 0644]
doc/technical/file-management.txt [new file with mode: 0644]
doc/technical/hostmask.txt [new file with mode: 0644]
doc/technical/index.txt [new file with mode: 0644]
doc/technical/linebuf.txt [new file with mode: 0644]
doc/technical/network.txt [new file with mode: 0644]
doc/technical/rfc1459.txt [new file with mode: 0644]
doc/technical/send.txt [new file with mode: 0644]
doc/technical/ts5.txt [new file with mode: 0644]
doc/technical/ts6.txt [new file with mode: 0644]
doc/tgchange.txt [new file with mode: 0644]
doc/whats-new-2.0.txt [new file with mode: 0644]
doc/whats-new-2.1.txt [new file with mode: 0644]
extensions/.cvsignore [new file with mode: 0644]
extensions/.indent.pro [new file with mode: 0644]
extensions/Makefile.in [new file with mode: 0644]
extensions/README [new file with mode: 0644]
extensions/createauthonly.c [new file with mode: 0644]
extensions/example_module.c [new file with mode: 0644]
extensions/extb_account.c [new file with mode: 0644]
extensions/extb_canjoin.c [new file with mode: 0644]
extensions/extb_channel.c [new file with mode: 0644]
extensions/extb_extgecos.c [new file with mode: 0644]
extensions/extb_oper.c [new file with mode: 0644]
extensions/extb_realname.c [new file with mode: 0644]
extensions/extb_server.c [new file with mode: 0644]
extensions/hurt.c [new file with mode: 0644]
extensions/ip_cloaking.c [new file with mode: 0644]
extensions/m_42.c [new file with mode: 0644]
extensions/m_findforwards.c [new file with mode: 0644]
extensions/m_identify.c [new file with mode: 0644]
extensions/m_mkpasswd.c [new file with mode: 0644]
extensions/m_ojoin.c [new file with mode: 0644]
extensions/m_okick.c [new file with mode: 0644]
extensions/m_olist.c [new file with mode: 0644]
extensions/m_omode.c [new file with mode: 0644]
extensions/m_opme.c [new file with mode: 0644]
extensions/m_webirc.c [new file with mode: 0644]
extensions/no_oper_invis.c [new file with mode: 0644]
extensions/sno_farconnect.c [new file with mode: 0644]
extensions/sno_globalkline.c [new file with mode: 0644]
extensions/sno_globaloper.c [new file with mode: 0644]
extensions/spy_admin_notice.c [new file with mode: 0644]
extensions/spy_info_notice.c [new file with mode: 0644]
extensions/spy_links_notice.c [new file with mode: 0644]
extensions/spy_motd_notice.c [new file with mode: 0644]
extensions/spy_stats_notice.c [new file with mode: 0644]
extensions/spy_stats_p_notice.c [new file with mode: 0644]
extensions/spy_trace_notice.c [new file with mode: 0644]
extensions/spy_whois_notice.c [new file with mode: 0644]
extensions/spy_whois_notice_global.c [new file with mode: 0644]
help/.cvsignore [new file with mode: 0644]
help/Makefile.in [new file with mode: 0644]
help/opers/accept [new file with mode: 0644]
help/opers/admin [new file with mode: 0644]
help/opers/away [new file with mode: 0644]
help/opers/capab [new file with mode: 0644]
help/opers/challenge [new file with mode: 0644]
help/opers/chantrace [new file with mode: 0644]
help/opers/close [new file with mode: 0644]
help/opers/cmode [new file with mode: 0644]
help/opers/cnotice [new file with mode: 0644]
help/opers/connect [new file with mode: 0644]
help/opers/cprivmsg [new file with mode: 0644]
help/opers/credits [new file with mode: 0644]
help/opers/die [new file with mode: 0644]
help/opers/dline [new file with mode: 0644]
help/opers/error [new file with mode: 0644]
help/opers/etrace [new file with mode: 0644]
help/opers/gline [new file with mode: 0644]
help/opers/help [new file with mode: 0644]
help/opers/index [new file with mode: 0644]
help/opers/info [new file with mode: 0644]
help/opers/invite [new file with mode: 0644]
help/opers/ison [new file with mode: 0644]
help/opers/join [new file with mode: 0644]
help/opers/kick [new file with mode: 0644]
help/opers/kill [new file with mode: 0644]
help/opers/kline [new file with mode: 0644]
help/opers/knock [new file with mode: 0644]
help/opers/links [new file with mode: 0644]
help/opers/list [new file with mode: 0644]
help/opers/locops [new file with mode: 0644]
help/opers/lusers [new file with mode: 0644]
help/opers/map [new file with mode: 0644]
help/opers/masktrace [new file with mode: 0644]
help/opers/modlist [new file with mode: 0644]
help/opers/modload [new file with mode: 0644]
help/opers/modrestart [new file with mode: 0644]
help/opers/modunload [new file with mode: 0644]
help/opers/motd [new file with mode: 0644]
help/opers/names [new file with mode: 0644]
help/opers/nick [new file with mode: 0644]
help/opers/notice [new file with mode: 0644]
help/opers/oper [new file with mode: 0644]
help/opers/operspy [new file with mode: 0644]
help/opers/operwall [new file with mode: 0644]
help/opers/part [new file with mode: 0644]
help/opers/pass [new file with mode: 0644]
help/opers/ping [new file with mode: 0644]
help/opers/pong [new file with mode: 0644]
help/opers/post [new file with mode: 0644]
help/opers/privmsg [new file with mode: 0644]
help/opers/quit [new file with mode: 0644]
help/opers/rehash [new file with mode: 0644]
help/opers/restart [new file with mode: 0644]
help/opers/resv [new file with mode: 0644]
help/opers/scan [new file with mode: 0644]
help/opers/server [new file with mode: 0644]
help/opers/set [new file with mode: 0644]
help/opers/sjoin [new file with mode: 0644]
help/opers/snomask [new file with mode: 0644]
help/opers/squit [new file with mode: 0644]
help/opers/stats [new file with mode: 0644]
help/opers/svinfo [new file with mode: 0644]
help/opers/testgecos [new file with mode: 0644]
help/opers/testline [new file with mode: 0644]
help/opers/testmask [new file with mode: 0644]
help/opers/time [new file with mode: 0644]
help/opers/topic [new file with mode: 0644]
help/opers/trace [new file with mode: 0644]
help/opers/uhelp [new file with mode: 0644]
help/opers/umode [new file with mode: 0644]
help/opers/undline [new file with mode: 0644]
help/opers/ungline [new file with mode: 0644]
help/opers/unkline [new file with mode: 0644]
help/opers/unreject [new file with mode: 0644]
help/opers/unresv [new file with mode: 0644]
help/opers/unxline [new file with mode: 0644]
help/opers/user [new file with mode: 0644]
help/opers/userhost [new file with mode: 0644]
help/opers/users [new file with mode: 0644]
help/opers/version [new file with mode: 0644]
help/opers/wallops [new file with mode: 0644]
help/opers/who [new file with mode: 0644]
help/opers/whois [new file with mode: 0644]
help/opers/whowas [new file with mode: 0644]
help/opers/xline [new file with mode: 0644]
help/users/index [new file with mode: 0644]
help/users/info [new file with mode: 0644]
help/users/notice [new file with mode: 0644]
help/users/privmsg [new file with mode: 0644]
help/users/stats [new file with mode: 0644]
help/users/umode [new file with mode: 0644]
include/.cvsignore [new file with mode: 0644]
include/.indent.pro [new file with mode: 0644]
include/blacklist.h [new file with mode: 0644]
include/cache.h [new file with mode: 0644]
include/channel.h [new file with mode: 0644]
include/charybdis.h [new file with mode: 0644]
include/class.h [new file with mode: 0644]
include/client.h [new file with mode: 0644]
include/common.h [new file with mode: 0644]
include/config.h [new file with mode: 0644]
include/config.h.dist [new file with mode: 0644]
include/defaults.h [new file with mode: 0644]
include/hash.h [new file with mode: 0644]
include/hook.h [new file with mode: 0644]
include/hostmask.h [new file with mode: 0644]
include/irc_string.h [new file with mode: 0644]
include/ircd.h [new file with mode: 0644]
include/ircd_defs.h [new file with mode: 0644]
include/ircd_getopt.h [new file with mode: 0644]
include/ircd_linker.h [new file with mode: 0644]
include/ircd_signal.h [new file with mode: 0644]
include/ircd_state.h [new file with mode: 0644]
include/listener.h [new file with mode: 0644]
include/m_info.h [new file with mode: 0644]
include/modules.h [new file with mode: 0644]
include/monitor.h [new file with mode: 0644]
include/msg.h [new file with mode: 0644]
include/newconf.h [new file with mode: 0644]
include/numeric.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/patricia.h [new file with mode: 0644]
include/reject.h [new file with mode: 0644]
include/res.h [new file with mode: 0644]
include/reslib.h [new file with mode: 0644]
include/restart.h [new file with mode: 0644]
include/s_auth.h [new file with mode: 0644]
include/s_conf.h [new file with mode: 0644]
include/s_gline.h [new file with mode: 0644]
include/s_log.h [new file with mode: 0644]
include/s_newconf.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/scache.h [new file with mode: 0644]
include/send.h [new file with mode: 0644]
include/serno.h [new file with mode: 0644]
include/setup.h.in [new file with mode: 0644]
include/snomask.h [new file with mode: 0644]
include/sprintf_irc.h [new file with mode: 0644]
include/stdinc.h [new file with mode: 0644]
include/supported.h [new file with mode: 0644]
include/whowas.h [new file with mode: 0644]
install-sh [new file with mode: 0644]
libcharybdis/Makefile.in [new file with mode: 0644]
libcharybdis/balloc.c [new file with mode: 0644]
libcharybdis/balloc.h [new file with mode: 0644]
libcharybdis/commio.c [new file with mode: 0644]
libcharybdis/commio.h [new file with mode: 0644]
libcharybdis/devpoll.c [new file with mode: 0644]
libcharybdis/epoll.c [new file with mode: 0644]
libcharybdis/event.c [new file with mode: 0644]
libcharybdis/event.h [new file with mode: 0644]
libcharybdis/kqueue.c [new file with mode: 0644]
libcharybdis/libcharybdis.c [new file with mode: 0644]
libcharybdis/libcharybdis.h [new file with mode: 0644]
libcharybdis/linebuf.c [new file with mode: 0644]
libcharybdis/linebuf.h [new file with mode: 0644]
libcharybdis/memory.c [new file with mode: 0644]
libcharybdis/memory.h [new file with mode: 0644]
libcharybdis/poll.c [new file with mode: 0644]
libcharybdis/ports.c [new file with mode: 0644]
libcharybdis/select.c [new file with mode: 0644]
libcharybdis/snprintf.c [new file with mode: 0644]
libcharybdis/tools.c [new file with mode: 0644]
libcharybdis/tools.h [new file with mode: 0644]
modules/.cvsignore [new file with mode: 0644]
modules/.depend [new file with mode: 0644]
modules/.indent.pro [new file with mode: 0644]
modules/Makefile.in [new file with mode: 0644]
modules/core/m_die.c [new file with mode: 0644]
modules/core/m_error.c [new file with mode: 0644]
modules/core/m_join.c [new file with mode: 0644]
modules/core/m_kick.c [new file with mode: 0644]
modules/core/m_kill.c [new file with mode: 0644]
modules/core/m_message.c [new file with mode: 0644]
modules/core/m_mode.c [new file with mode: 0644]
modules/core/m_nick.c [new file with mode: 0644]
modules/core/m_part.c [new file with mode: 0644]
modules/core/m_quit.c [new file with mode: 0644]
modules/core/m_server.c [new file with mode: 0644]
modules/core/m_sjoin.c [new file with mode: 0644]
modules/core/m_squit.c [new file with mode: 0644]
modules/m_accept.c [new file with mode: 0644]
modules/m_admin.c [new file with mode: 0644]
modules/m_away.c [new file with mode: 0644]
modules/m_cap.c [new file with mode: 0644]
modules/m_capab.c [new file with mode: 0644]
modules/m_challenge.c [new file with mode: 0644]
modules/m_chghost.c [new file with mode: 0644]
modules/m_close.c [new file with mode: 0644]
modules/m_cmessage.c [new file with mode: 0644]
modules/m_connect.c [new file with mode: 0644]
modules/m_dline.c [new file with mode: 0644]
modules/m_encap.c [new file with mode: 0644]
modules/m_etrace.c [new file with mode: 0644]
modules/m_gline.c [new file with mode: 0644]
modules/m_help.c [new file with mode: 0644]
modules/m_info.c [new file with mode: 0644]
modules/m_invite.c [new file with mode: 0644]
modules/m_ison.c [new file with mode: 0644]
modules/m_kline.c [new file with mode: 0644]
modules/m_knock.c [new file with mode: 0644]
modules/m_links.c [new file with mode: 0644]
modules/m_list_ratbox.c [new file with mode: 0644]
modules/m_list_safelist.c [new file with mode: 0644]
modules/m_locops.c [new file with mode: 0644]
modules/m_lusers.c [new file with mode: 0644]
modules/m_map.c [new file with mode: 0644]
modules/m_monitor.c [new file with mode: 0644]
modules/m_motd.c [new file with mode: 0644]
modules/m_names.c [new file with mode: 0644]
modules/m_oper.c [new file with mode: 0644]
modules/m_operspy.c [new file with mode: 0644]
modules/m_pass.c [new file with mode: 0644]
modules/m_ping.c [new file with mode: 0644]
modules/m_pong.c [new file with mode: 0644]
modules/m_post.c [new file with mode: 0644]
modules/m_rehash.c [new file with mode: 0644]
modules/m_restart.c [new file with mode: 0644]
modules/m_resv.c [new file with mode: 0644]
modules/m_sasl.c [new file with mode: 0644]
modules/m_scan.c [new file with mode: 0644]
modules/m_services.c [new file with mode: 0644]
modules/m_set.c [new file with mode: 0644]
modules/m_signon.c [new file with mode: 0644]
modules/m_snote.c [new file with mode: 0644]
modules/m_stats.c [new file with mode: 0644]
modules/m_svinfo.c [new file with mode: 0644]
modules/m_tb.c [new file with mode: 0644]
modules/m_testline.c [new file with mode: 0644]
modules/m_testmask.c [new file with mode: 0644]
modules/m_time.c [new file with mode: 0644]
modules/m_topic.c [new file with mode: 0644]
modules/m_trace.c [new file with mode: 0644]
modules/m_unreject.c [new file with mode: 0644]
modules/m_user.c [new file with mode: 0644]
modules/m_userhost.c [new file with mode: 0644]
modules/m_users.c [new file with mode: 0644]
modules/m_version.c [new file with mode: 0644]
modules/m_wallops.c [new file with mode: 0644]
modules/m_who.c [new file with mode: 0644]
modules/m_whois.c [new file with mode: 0644]
modules/m_whowas.c [new file with mode: 0644]
modules/m_xline.c [new file with mode: 0644]
modules/sno_routing.c [new file with mode: 0644]
modules/static_modules.c.SH [new file with mode: 0644]
servlink/.cvsignore [new file with mode: 0644]
servlink/.indent.pro [new file with mode: 0644]
servlink/Makefile.in [new file with mode: 0644]
servlink/README [new file with mode: 0644]
servlink/TODO [new file with mode: 0644]
servlink/control.c [new file with mode: 0644]
servlink/control.h [new file with mode: 0644]
servlink/io.c [new file with mode: 0644]
servlink/io.h [new file with mode: 0644]
servlink/servlink.c [new file with mode: 0644]
servlink/servlink.h [new file with mode: 0644]
src/.cvsignore [new file with mode: 0644]
src/.depend [new file with mode: 0644]
src/.indent.pro [new file with mode: 0644]
src/Makefile.in [new file with mode: 0644]
src/blacklist.c [new file with mode: 0644]
src/cache.c [new file with mode: 0644]
src/channel.c [new file with mode: 0644]
src/chmode.c [new file with mode: 0644]
src/class.c [new file with mode: 0644]
src/client.c [new file with mode: 0644]
src/extban.c [new file with mode: 0644]
src/fnvhash.s [new file with mode: 0644]
src/getopt.c [new file with mode: 0644]
src/hash.c [new file with mode: 0644]
src/hook.c [new file with mode: 0644]
src/hostmask.c [new file with mode: 0644]
src/irc_string.c [new file with mode: 0644]
src/ircd.c [new file with mode: 0644]
src/ircd_lexer.l [new file with mode: 0644]
src/ircd_parser.y [new file with mode: 0644]
src/ircd_signal.c [new file with mode: 0644]
src/ircd_state.c [new file with mode: 0644]
src/kdparse.c [new file with mode: 0644]
src/listener.c [new file with mode: 0644]
src/match.c [new file with mode: 0644]
src/messages.tab [new file with mode: 0644]
src/modules.c [new file with mode: 0644]
src/monitor.c [new file with mode: 0644]
src/newconf.c [new file with mode: 0644]
src/numeric.c [new file with mode: 0644]
src/packet.c [new file with mode: 0644]
src/parse.c [new file with mode: 0644]
src/patricia.c [new file with mode: 0644]
src/reject.c [new file with mode: 0644]
src/res.c [new file with mode: 0644]
src/reslib.c [new file with mode: 0644]
src/restart.c [new file with mode: 0644]
src/s_auth.c [new file with mode: 0644]
src/s_conf.c [new file with mode: 0644]
src/s_gline.c [new file with mode: 0644]
src/s_log.c [new file with mode: 0644]
src/s_newconf.c [new file with mode: 0644]
src/s_serv.c [new file with mode: 0644]
src/s_stats.c [new file with mode: 0644]
src/s_user.c [new file with mode: 0644]
src/scache.c [new file with mode: 0644]
src/send.c [new file with mode: 0644]
src/snomask.c [new file with mode: 0644]
src/supported.c [new file with mode: 0644]
src/version.c.SH [new file with mode: 0644]
src/whowas.c [new file with mode: 0644]
tools/.cvsignore [new file with mode: 0644]
tools/Makefile.in [new file with mode: 0644]
tools/README [new file with mode: 0644]
tools/README.mkpasswd [new file with mode: 0644]
tools/convertilines.c [new file with mode: 0644]
tools/convertklines.c [new file with mode: 0644]
tools/mkkeypair [new file with mode: 0755]
tools/mkpasswd.c [new file with mode: 0644]
tools/untabify [new file with mode: 0755]
tools/viconf.c [new file with mode: 0644]
unsupported/Makefile.in [new file with mode: 0644]
unsupported/m_clearchan.c [new file with mode: 0644]
unsupported/m_force.c [new file with mode: 0644]

diff --git a/.cvsignore b/.cvsignore
new file mode 100644 (file)
index 0000000..b303797
--- /dev/null
@@ -0,0 +1,8 @@
+config.log
+config.cache
+config.status
+autom4te.cache
+Makefile
+lint.out
+rsa_respond.tar.gz
+.depend
diff --git a/.indent.pro b/.indent.pro
new file mode 100644 (file)
index 0000000..1b1a956
--- /dev/null
@@ -0,0 +1,49 @@
+/* $Id: .indent.pro 238 2005-09-21 05:26:03Z nenolod $ */
+
+/* copy this file to the source dir then run indent file.c */
+
+--gnu-style
+
+/* This is the indent before the brace not inside the block. */
+--brace-indent0
+
+/* Indent case: by 2 and braces inside case by 0(then by 0)... */
+--case-brace-indentation0
+--case-indentation2
+
+--indent-level8
+
+/* Put while() on the brace from do... */
+--cuddle-do-while
+
+/* Disable an annoying format... */
+--no-space-after-function-call-names
+
+/* Disable an annoying format... */
+--dont-break-procedure-type
+
+/* Disable an annoying format... */
+--no-space-after-casts
+
+--line-length200
+
+/* typedefs */
+-T boolean_t
+-T node_t
+-T list_t
+-T tld_t
+-T kline_t
+-T EVH
+-T sra_t
+-T server_t
+-T user_t
+-T channel_t
+-T chanuser_t
+-T myuser_t
+-T mychan_t
+-T chanacs_t
+-T CONFIGENTRY
+-T CONFIGFILE
+-T Block
+-T MemBlock
+-T BlockHeap
diff --git a/BUGS b/BUGS
new file mode 100644 (file)
index 0000000..3ef29d0
--- /dev/null
+++ b/BUGS
@@ -0,0 +1,27 @@
+ Known Bugs worthy of a mention:
+--------------------------------------------------------------------------------
+  
+1.  /MODUNLOAD causes cores:
+    - If a module is modified before being unloaded, /MODUNLOAD (and
+      therefore /MODRELOAD) may cause a core.
+
+      This problem is caused by the behaviour of the OS, which treats
+      shared libraries differently to executables (modifying the ircd
+      binary whilst it is running would also cause a core, but is denied
+      by the OS).
+
+      A workaround to avoid coring is possible however.  To install new
+      modules, first remove or rename the old module, then copy/move the
+      new file into place.  install or make install is also safe.
+      /MODUNLOAD will then work successfully.
+
+      We will likely have a workaround implemented in the next version.
+
+BUG REPORTS: If you run this code and encounter problems, you must report
+ the bug via IRC, irc.atheme.net #athemenet-dev.
+
+ Please include a gdb backtrace and keep your binaries, modules and core file
+ in case the developers need more information.
+
+--------------------------------------------------------------------------------
+$Id: BUGS 1634 2006-06-04 13:26:04Z jilles $
diff --git a/CREDITS b/CREDITS
new file mode 100644 (file)
index 0000000..ce3dd9a
--- /dev/null
+++ b/CREDITS
@@ -0,0 +1,24 @@
+$Id: CREDITS 3133 2007-01-21 15:38:16Z jilles $
+Charybdis started as an evolution from ircd-ratbox-2.1.5+datadrain. Its
+development is led by a team of dedicated developers who have put a lot
+of time into the project.
+The charybdis core team is listed in nick-alphabetical order:
+gxti, Michael Tharp <gxti -at- partiallystapled.com>
+jilles, Jilles Tjoelker <jilles -at- stack.nl>
+nenolod, William Pitcock <nenolod -at- nenolod.net>
+twincest, River Tarnell <river -at- attenuate.org>
+The following people have made contributions to the Charybdis release,
+in nick-alphabetical order:
+AndroSyn, Aaron Sethman <androsyn -at- ratbox.org>
+anfl, Lee Hardy <lee -at- leeh.co.uk>
+beu, Elfyn McBratney <elfyn.mcbratney -at- gmail.com>
+Entrope, Michael Poole <mdpoole -at- trolius.org> 
+ThaPrince, Jon Christopherson <jon -at- vile.com>
+w00t, Robin Burchell <surreal.w00t -at- gmail.com>
+Visit the Charybdis website at: http://www.ircd-charybdis.org 
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..05fbb75
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,13271 @@
+jilles      2007/01/23 23:48:50 UTC    (20070123-3139)
+  Log:
+  Merged revisions 3135,3137 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  
+  ........
+    r3135 | jilles | 2007-01-23 22:19:14 +0100 (Tue, 23 Jan 2007) | 3 lines
+    
+    - Expand TRACE description
+    - Mention expiry time in TESTLINE
+  ........
+    r3137 | jilles | 2007-01-23 22:20:30 +0100 (Tue, 23 Jan 2007) | 2 lines
+    
+    Update copyright year for sgml docs to 2007.
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  +1 -1                branches/release-2.1/doc/sgml/oper-guide/charybdis-oper-guide.sgml (File Modified) 
+  +77 -3       branches/release-2.1/doc/sgml/oper-guide/commands.sgml (File Modified) 
+
+
+jilles      2007/01/21 15:38:16 UTC    (20070121-3133)
+  Log:
+  Merged revisions 1999 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  Add river to CREDITS
+  
+  ........
+    r1999 | river | 2006-09-02 05:15:18 +0200 (Sat, 02 Sep 2006) | 2 lines
+    
+    vanity
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  +1 -0                branches/release-2.1/CREDITS (File Modified) 
+
+
+jilles      2007/01/21 15:36:31 UTC    (20070121-3131)
+  Log:
+  Merged revisions 1995,1997,2019-2020,2023-2028,2031-2032,2055-2058,2061,2063 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  
+  ........
+    r1995 | river | 2006-09-02 05:06:52 +0200 (Sat, 02 Sep 2006) | 3 lines
+    
+    add "use_forward" option from +malfunc, lets admins disable chanmode +QFf
+  ........
+    r1997 | river | 2006-09-02 05:09:57 +0200 (Sat, 02 Sep 2006) | 3 lines
+    
+    - add use_forward to /info
+  ........
+    r2061 | jilles | 2006-09-23 13:51:11 +0200 (Sat, 23 Sep 2006) | 5 lines
+    
+    Call channel_modes() with &me instead of source_p when
+    sending out a JOIN and SJOIN for a local user. This
+    saves checking whether they are on the channel they
+    have just joined.
+  ........
+    r2063 | jilles | 2006-09-23 14:17:00 +0200 (Sat, 23 Sep 2006) | 6 lines
+    
+    If use_forward is disabled:
+    - hide +fFQ in 005
+    - hide +f in /mode #channel (/mode #channel f still shows it)
+    - do not send any mode changes adding +f to local clients
+      (-f ones are still sent)
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  +1 -0                branches/release-2.1/doc/example.conf (File Modified) 
+  +5 -0                branches/release-2.1/doc/reference.conf (File Modified) 
+  +1 -0                branches/release-2.1/include/s_conf.h (File Modified) 
+  +4 -3                branches/release-2.1/modules/core/m_join.c (File Modified) 
+  +1 -1                branches/release-2.1/modules/core/m_sjoin.c (File Modified) 
+  +6 -0                branches/release-2.1/modules/m_info.c (File Modified) 
+  +1 -1                branches/release-2.1/src/channel.c (File Modified) 
+  +11 -1       branches/release-2.1/src/chmode.c (File Modified) 
+  +1 -0                branches/release-2.1/src/newconf.c (File Modified) 
+  +1 -0                branches/release-2.1/src/s_conf.c (File Modified) 
+  +5 -0                branches/release-2.1/src/s_user.c (File Modified) 
+  +4 -2                branches/release-2.1/src/supported.c (File Modified) 
+
+
+jilles      2007/01/02 13:23:04 UTC    (20070102-3121)
+  Log:
+  OPME/OMODE/OJOIN: Use get_oper_name() in log message.
+  
+
+  Changes:     Modified:
+  +3 -2                branches/release-2.1/extensions/m_ojoin.c (File Modified) 
+  +2 -2                branches/release-2.1/extensions/m_omode.c (File Modified) 
+  +3 -2                branches/release-2.1/extensions/m_opme.c (File Modified) 
+
+
+jilles      2007/01/02 13:11:04 UTC    (20070102-3117)
+  Log:
+  Add accountability (wallops, log) to OKICK.
+  
+
+  Changes:     Modified:
+  +14 -0       branches/release-2.1/extensions/m_okick.c (File Modified) 
+
+
+jilles      2006/12/27 00:47:45 UTC    (20061227-3063)
+  Log:
+  Allow kline ipv6:address, unkline some.host and unkline ipv6:address without *@.
+  Similar to branches/release-2.2 r3061.
+  
+
+  Changes:     Modified:
+  +2 -2                branches/release-2.1/modules/m_kline.c (File Modified) 
+
+
+jilles      2006/12/27 00:36:54 UTC    (20061227-3059)
+  Log:
+  - Write xline to file after instead of before notifying opers and source
+  - Also notify source of failure to add xline
+  Similar to branches/release-2.2 r3057.
+  
+
+  Changes:     Modified:
+  +4 -2                branches/release-2.1/modules/m_xline.c (File Modified) 
+
+
+jilles      2006/12/27 00:25:50 UTC    (20061227-3055)
+  Log:
+  If a dline/kline/resv cannot be added to the file, send
+  the regular notices to local opers and source anyway,
+  and also warn the source (local opers were already warned).
+  Similar to branches/release-2.2 r3053.
+  
+
+  Changes:     Modified:
+  +44 -42      branches/release-2.1/src/s_conf.c (File Modified) 
+
+
+jilles      2006/12/27 00:02:32 UTC    (20061227-3051)
+  Log:
+  Port over fixes from unkline/unxline/unresv to undline.
+  Similar to branches/release-2.2 r3049.
+  
+
+  Changes:     Modified:
+  +7 -2                branches/release-2.1/modules/m_dline.c (File Modified) 
+
+
+jilles      2006/12/26 23:18:05 UTC    (20061226-3047)
+  Log:
+  Merged revisions 2915 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  
+  ........
+    r2915 | jilles | 2006-12-17 01:40:54 +0100 (Sun, 17 Dec 2006) | 3 lines
+    
+    In usage message, show kline.conf and xline.conf instead
+    of klines.conf and xlines.conf.
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  +2 -2                branches/release-2.1/src/ircd.c (File Modified) 
+
+
+jilles      2006/12/26 23:16:57 UTC    (20061226-3045)
+  Log:
+  Merged revisions 2831,2833,2853 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  
+  ........
+    r2831 | jilles | 2006-12-14 00:19:51 +0100 (Thu, 14 Dec 2006) | 5 lines
+    
+    unkline/unxline/unresv:
+    - if fclose on the output returns an error, treat this as a
+      write error too
+    - check if the rename from the temp file to the ban conf failed
+  ........
+    r2833 | jilles | 2006-12-14 00:39:25 +0100 (Thu, 14 Dec 2006) | 3 lines
+    
+    When adding a permanent dline/kline/xline/resv, check
+    the return value of fclose().
+  ........
+    r2853 | jilles | 2006-12-16 00:24:32 +0100 (Sat, 16 Dec 2006) | 3 lines
+    
+    Do not free xline aconf if it could not be written out.
+    It will be added to the list in memory anyway.
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  +7 -2                branches/release-2.1/modules/m_kline.c (File Modified) 
+  +7 -2                branches/release-2.1/modules/m_resv.c (File Modified) 
+  +12 -5       branches/release-2.1/modules/m_xline.c (File Modified) 
+  +5 -1                branches/release-2.1/src/s_conf.c (File Modified) 
+
+
+jilles      2006/12/05 13:24:19 UTC    (20061205-2813)
+  Log:
+  NEWS: Clarify effects of ip_cloaking changes a little.
+  
+
+  Changes:     Modified:
+  +2 -0                branches/release-2.1/NEWS (File Modified) 
+
+
+jilles      2006/12/05 13:18:39 UTC    (20061205-2811)
+  Log:
+  Rerun autoconf.
+  
+
+  Changes:     Modified:
+  +9 -9                branches/release-2.1/configure (File Modified) 
+
+
+jilles      2006/12/05 13:18:19 UTC    (20061205-2809)
+  Log:
+  Version bump on 2.1 branch to 2.1.2.
+  
+
+  Changes:     Modified:
+  +1 -1                branches/release-2.1/configure.ac (File Modified) 
+
+
+jilles      2006/12/05 12:47:23 UTC    (20061205-2807)
+  Log:
+  Mention r2801/r2805.
+  
+
+  Changes:     Modified:
+  +1 -0                branches/release-2.1/NEWS (File Modified) 
+
+
+jilles      2006/12/05 12:45:43 UTC    (20061205-2805)
+  Log:
+  Merged revisions 2801 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  
+  ........
+    r2801 | jilles | 2006-12-03 20:18:59 +0100 (Sun, 03 Dec 2006) | 3 lines
+    
+    ip_cloaking: try to avoid truncation by removing more
+    components of the hostname (except the TLD).
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  +14 -2       branches/release-2.1/extensions/ip_cloaking.c (File Modified) 
+
+
+jilles      2006/12/02 20:40:54 UTC    (20061202-2793)
+  Log:
+  Update NEWS.
+  
+
+  Changes:     Modified:
+  +8 -1                branches/release-2.1/NEWS (File Modified) 
+
+
+jilles      2006/12/02 20:32:39 UTC    (20061202-2791)
+  Log:
+  Merged revisions 2781 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  
+  ........
+    r2781 | jilles | 2006-12-02 01:50:29 +0100 (Sat, 02 Dec 2006) | 5 lines
+    
+    Fix stupid bug: checked a hostmask against the found
+    ban instead of all exceptions, causing all host mangled
+    clients to be exempted if there was a single ban
+    exception in many cases.
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  +2 -2                branches/release-2.1/src/channel.c (File Modified) 
+
+
+jilles      2006/12/02 20:00:18 UTC    (20061202-2789)
+  Log:
+  Merged revisions 2773 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  
+  ........
+    r2773 | jilles | 2006-11-24 20:45:29 +0100 (Fri, 24 Nov 2006) | 3 lines
+    
+    user@host must be *@* for a shared{} block with flags=locops
+    (server should not be *).
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  +3 -1                branches/release-2.1/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+jilles      2006/11/27 11:45:31 UTC    (20061127-2775)
+  Log:
+  Tweak \s code a little.
+  
+
+  Changes:     Modified:
+  +1 -1                branches/release-2.1/modules/m_etrace.c (File Modified) 
+  +1 -1                branches/release-2.1/modules/m_testmask.c (File Modified) 
+  +1 -1                branches/release-2.1/modules/m_xline.c (File Modified) 
+
+
+jilles      2006/11/12 14:21:16 UTC    (20061112-2765)
+  Log:
+  Merged revisions 2761 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  
+  ........
+    r2761 | jilles | 2006-11-12 15:02:47 +0100 (Sun, 12 Nov 2006) | 2 lines
+    
+    The testline/no_tilde fixes are in 2.1.1.
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  +1 -1                branches/release-2.1/doc/sgml/oper-guide/commands.sgml (File Modified) 
+
+
+jilles      2006/11/10 23:02:43 UTC    (20061110-2759)
+  Log:
+  Update NEWS.
+  
+
+  Changes:     Modified:
+  +4 -1                branches/release-2.1/NEWS (File Modified) 
+
+
+jilles      2006/11/10 22:58:15 UTC    (20061110-2757)
+  Log:
+  Merged revisions 2125,2182-2183,2190-2195,2204-2205,2208-2209,2238-2239,2286-2287,2296-2297,2440-2441,2542-2547,2681-2682,2687-2690,2697,2703,2705,2707-2711 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  no_tilde fixes
+  
+  ........
+    r2125 | jilles | 2006-09-26 00:59:18 +0200 (Tue, 26 Sep 2006) | 5 lines
+    
+    If the auth{} block has no_tilde and is not kline exempt,
+    check the username without tilde against klines too.
+    This is consistent with the way klines work on spoofs
+    (klines checked on both raw and appearing-on-IRC version).
+  ........
+    r2697 | jilles | 2006-11-06 11:37:00 +0100 (Mon, 06 Nov 2006) | 4 lines
+    
+    Rework the fix for klines with no_tilde.
+    Add an extra argument to find_address_conf() for the
+    username without tilde, as that may contain one character more.
+  ........
+    r2703 | jilles | 2006-11-06 16:49:44 +0100 (Mon, 06 Nov 2006) | 3 lines
+    
+    Unbreak compile (because of r2697).
+    testline with ~ could be improved some more perhaps, but this should work.
+  ........
+    r2705 | jilles | 2006-11-06 17:42:21 +0100 (Mon, 06 Nov 2006) | 2 lines
+    
+    testline: take no_tilde and username truncation into account
+  ........
+    r2711 | jilles | 2006-11-08 14:05:14 +0100 (Wed, 08 Nov 2006) | 2 lines
+    
+    Add some information on /testline with no_tilde and username truncation.
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  +5 -0                branches/release-2.1/doc/sgml/oper-guide/commands.sgml (File Modified) 
+  +1 -0                branches/release-2.1/extensions/m_webirc.c (File Modified) 
+  +2 -1                branches/release-2.1/include/hostmask.h (File Modified) 
+  +12 -1       branches/release-2.1/modules/m_testline.c (File Modified) 
+  +16 -2       branches/release-2.1/src/hostmask.c (File Modified) 
+  +2 -2                branches/release-2.1/src/s_conf.c (File Modified) 
+
+
+jilles      2006/11/10 19:08:03 UTC    (20061110-2755)
+  Log:
+  Merged revisions 2149,2151 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  
+  ........
+    r2149 | jilles | 2006-09-27 17:32:42 +0200 (Wed, 27 Sep 2006) | 3 lines
+    
+    Move kills from services from +s to +k snomask.
+    Kills from non-service opers remain on +s.
+  ........
+    r2151 | jilles | 2006-09-27 17:41:39 +0200 (Wed, 27 Sep 2006) | 2 lines
+    
+    Update description of +s and +k snomasks.
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  +2 -1                branches/release-2.1/doc/sgml/oper-guide/umodes.sgml (File Modified) 
+  +1 -1                branches/release-2.1/help/opers/snomask (File Modified) 
+  +1 -1                branches/release-2.1/modules/core/m_kill.c (File Modified) 
+
+
+jilles      2006/11/10 19:05:25 UTC    (20061110-2753)
+  Log:
+  Merged revisions 2685 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  
+  ........
+    r2685 | jilles | 2006-11-01 18:44:01 +0100 (Wed, 01 Nov 2006) | 2 lines
+    
+    Mention that exempt{} blocks do not exempt from DNSBL (for completeness).
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  +2 -1                branches/release-2.1/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+jilles      2006/11/10 15:15:00 UTC    (20061110-2743)
+  Log:
+  Merged revisions 2693 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  
+  ........
+    r2693 | jilles | 2006-11-06 02:35:21 +0100 (Mon, 06 Nov 2006) | 6 lines
+    
+    Fix truncation (by one) of unidented usernames
+    if user registration is done because of DNSBL
+    completion (which is the usual case if a valid
+    NICK and USER are sent quickly and any DNSBLs
+    are enabled).
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  +2 -2                branches/release-2.1/src/blacklist.c (File Modified) 
+
+
+jilles      2006/11/10 01:26:27 UTC    (20061110-2739)
+  Log:
+  Update NEWS.
+  
+
+  Changes:     Modified:
+  +10 -0       branches/release-2.1/NEWS (File Modified) 
+
+
+jilles      2006/11/10 00:21:56 UTC    (20061110-2737)
+  Log:
+  Rerun autoconf.
+  
+
+  Changes:     Modified:
+  +9 -9                branches/release-2.1/configure (File Modified) 
+
+
+jilles      2006/11/10 00:15:54 UTC    (20061110-2735)
+  Log:
+  Version bump to 2.1.1.
+  
+
+  Changes:     Modified:
+  +1 -1                branches/release-2.1/configure.ac (File Modified) 
+
+
+jilles      2006/11/10 00:04:08 UTC    (20061110-2733)
+  Log:
+  Merged revisions 2186,2188,2190-2196,2204-2205,2208-2209,2224,2238-2239,2286-2287,2296-2297,2440-2441,2542-2547,2681-2682,2687-2690,2699,2701 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  
+  ........
+    r2186 | nenolod | 2006-09-28 04:24:41 +0200 (Thu, 28 Sep 2006) | 2 lines
+    
+    - fix a server notice on SID collision where the server name is mentioned twice
+  ........
+    r2188 | nenolod | 2006-09-28 04:30:37 +0200 (Thu, 28 Sep 2006) | 2 lines
+    
+    - get_server_name() is stupid
+  ........
+    r2196 | nenolod | 2006-09-28 05:03:07 +0200 (Thu, 28 Sep 2006) | 2 lines
+    
+    - fix an oops
+  ........
+    r2224 | jilles | 2006-09-28 18:23:53 +0200 (Thu, 28 Sep 2006) | 4 lines
+    
+    Do the Attempt to re-introduce SID server notice somewhat
+    differently, showing a real host again if !HIDE_SERVERS_IPS
+    and still showing the server name exactly once.
+  ........
+    r2699 | jilles | 2006-11-06 11:54:35 +0100 (Mon, 06 Nov 2006) | 2 lines
+    
+    Fix log message for Attempt to re-introduce SID (server notice was ok).
+  ........
+    r2701 | jilles | 2006-11-06 12:05:23 +0100 (Mon, 06 Nov 2006) | 4 lines
+    
+    - replace "No N line" with "no connect block" in a
+      serverlog message
+    - show attempted server name in a few serverlog messages
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  +13 -6       branches/release-2.1/modules/core/m_server.c (File Modified) 
+
+
+jilles      2006/11/09 23:53:43 UTC    (20061109-2731)
+  Log:
+  Merged revisions 2218 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  
+  ........
+    r2218 | jilles | 2006-09-28 16:06:06 +0200 (Thu, 28 Sep 2006) | 2 lines
+    
+    Fix garbage in /stats y output on 64-bit archs.
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  +1 -1                branches/release-2.1/src/messages.tab (File Modified) 
+
+
+jilles      2006/11/09 23:52:06 UTC    (20061109-2729)
+  Log:
+  Merged revisions 2438 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  
+  ........
+    r2438 | jilles | 2006-10-06 23:51:04 +0200 (Fri, 06 Oct 2006) | 2 lines
+    
+    Enable Revision keyword in addition to Id.
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  + -          branches/release-2.1/extensions/m_identify.c  (Property Modified)
+
+
+jilles      2006/11/09 23:48:45 UTC    (20061109-2727)
+  Log:
+  Merged revisions 2679 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  
+  ........
+    r2679 | jilles | 2006-10-29 14:24:28 +0100 (Sun, 29 Oct 2006) | 4 lines
+    
+    Port over ratbox 2.2 r23253 (anfl):
+    - remove the cached storage of how many +beI there are, thereby fixing a        
+      case where it can get desynced from reality
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  +0 -1                branches/release-2.1/include/channel.h (File Modified) 
+  +1 -8                branches/release-2.1/src/chmode.c (File Modified) 
+
+
+jilles      2006/11/09 23:43:35 UTC    (20061109-2725)
+  Log:
+  Merged revisions 2093,2095 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  
+  ........
+    r2093 | nenolod | 2006-09-25 08:01:01 +0200 (Mon, 25 Sep 2006) | 2 lines
+    
+    - change DNSBL licensing to BSD.
+  ........
+    r2095 | nenolod | 2006-09-25 08:04:37 +0200 (Mon, 25 Sep 2006) | 2 lines
+    
+    - change x86-assembly FNV implementation to BSD license
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  +27 -16      branches/release-2.1/src/blacklist.c (File Modified) 
+  +27 -16      branches/release-2.1/src/fnvhash.s (File Modified) 
+
+
+jilles      2006/11/09 23:35:48 UTC    (20061109-2723)
+  Log:
+  Merged revisions 2073,2075 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  
+  ........
+    r2073 | jilles | 2006-09-24 20:23:35 +0200 (Sun, 24 Sep 2006) | 3 lines
+    
+    Put full information in the squit reason when exiting
+    a server due to a servlink (ziplinks) error.
+  ........
+    r2075 | jilles | 2006-09-24 20:33:12 +0200 (Sun, 24 Sep 2006) | 3 lines
+    
+    Put full information in the squit reason when exiting
+    a server due to not enough arguments for a command.
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  +7 -5                branches/release-2.1/src/parse.c (File Modified) 
+  +4 -1                branches/release-2.1/src/s_serv.c (File Modified) 
+
+
+jilles      2006/11/09 23:30:38 UTC    (20061109-2721)
+  Log:
+  Merged revisions 2071 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  
+  ........
+    r2071 | jilles | 2006-09-24 20:21:57 +0200 (Sun, 24 Sep 2006) | 4 lines
+    
+    Don't redirect users from an existing domain to an
+    existing server in reference.conf.
+    Idea from ratbox.
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  +2 -2                branches/release-2.1/doc/reference.conf (File Modified) 
+
+
+jilles      2006/09/27 17:19:03 UTC    (20060927-2182)
+  Log:
+  Merged revisions 2053 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  
+  ........
+    r2053 | jilles | 2006-09-09 17:30:38 +0200 (Sat, 09 Sep 2006) | 5 lines
+    
+    Make find_channel_membership() choose the shortest list
+    (channel's list or user's list) to search, avoiding excessive
+    CPU usage with services which are in lots of channels.
+    From ratbox 2.2 (anfl/jilles)
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  +21 -4       branches/release-2.1/src/channel.c (File Modified) 
+
+
+jilles      2006/09/14 22:01:16 UTC    (20060914-2057)
+  Log:
+  Rerun autoconf.
+  
+
+  Changes:     Modified:
+  +9 -9                branches/release-2.1/configure (File Modified) 
+
+
+jilles      2006/09/14 22:00:30 UTC    (20060914-2055)
+  Log:
+  Version change 2.1.0rc1 -> 2.1.0 (release).
+  
+
+  Changes:     Modified:
+  +1 -1                branches/release-2.1/configure.ac (File Modified) 
+
+
+jilles      2006/09/02 23:57:18 UTC    (20060902-2031)
+  Log:
+  Merged revisions 2029 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  
+  ........
+    r2029 | jilles | 2006-09-03 01:56:06 +0200 (Sun, 03 Sep 2006) | 2 lines
+    
+    NEWS: mention m_webirc.c module
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  +1 -0                branches/release-2.1/NEWS (File Modified) 
+
+
+jilles      2006/09/02 23:50:03 UTC    (20060902-2027)
+  Log:
+  Rerun autoconf.
+  
+
+  Changes:     Modified:
+  +9 -9                branches/release-2.1/configure (File Modified) 
+
+
+jilles      2006/09/02 23:49:29 UTC    (20060902-2025)
+  Log:
+  Change version to 2.1.0rc1.
+  
+
+  Changes:     Modified:
+  +1 -1                branches/release-2.1/configure.ac (File Modified) 
+
+
+jilles      2006/09/02 23:47:27 UTC    (20060902-2023)
+  Log:
+  Merged revisions 2021 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  
+  ........
+    r2021 | jilles | 2006-09-03 01:24:17 +0200 (Sun, 03 Sep 2006) | 4 lines
+    
+    Get rid of delete_resolver_queries_f(), dnsbl_hits and
+    related flaky looking things, and instead keep a list
+    of BlacklistClients in PreClient.
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  +4 -1                branches/release-2.1/include/blacklist.h (File Modified) 
+  +1 -1                branches/release-2.1/include/client.h (File Modified) 
+  +0 -1                branches/release-2.1/include/res.h (File Modified) 
+  +17 -32      branches/release-2.1/src/blacklist.c (File Modified) 
+  +0 -24       branches/release-2.1/src/res.c (File Modified) 
+  +1 -1                branches/release-2.1/src/s_user.c (File Modified) 
+
+
+jilles      2006/09/02 19:25:05 UTC    (20060902-2019)
+  Log:
+  Merged revisions 2015,2017 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  
+  ........
+    r2015 | jilles | 2006-09-02 20:11:23 +0200 (Sat, 02 Sep 2006) | 4 lines
+    
+    Check if the name in the question section of the
+    DNS reply matches what we queried, to guard against
+    late replies to a previous query with the same id.
+  ........
+    r2017 | jilles | 2006-09-02 20:24:34 +0200 (Sat, 02 Sep 2006) | 2 lines
+    
+    res.c: add a comment summarizing our changes
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  +53 -18      branches/release-2.1/src/res.c (File Modified) 
+
+
+jilles      2006/09/01 19:43:30 UTC    (20060901-1985)
+  Log:
+  Merged revisions 1981 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  
+  ........
+    r1981 | jilles | 2006-09-01 03:21:02 +0200 (Fri, 01 Sep 2006) | 2 lines
+    
+    Alphabetize extensions and tweak the descriptions a little.
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  +5 -5                branches/release-2.1/doc/example.conf (File Modified) 
+  +13 -13      branches/release-2.1/doc/reference.conf (File Modified) 
+
+
+jilles      2006/09/01 19:42:07 UTC    (20060901-1983)
+  Log:
+  Merged revisions 1975 via svnmerge from 
+  http://svn.atheme.org/charybdis/trunk
+  
+  ........
+    r1975 | jilles | 2006-09-01 01:56:25 +0200 (Fri, 01 Sep 2006) | 4 lines
+    
+    Fix bug in WEBIRC to deal with hosts being longer than HOSTLEN.
+    We should use the IP and not truncate the hostname.
+    From ratbox 2.2 (androsyn)
+  ........
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+  +7 -1                branches/release-2.1/extensions/m_webirc.c (File Modified) 
+
+
+jilles      2006/09/01 00:01:23 UTC    (20060901-1977)
+  Log:
+  Initialized merge tracking via "svnmerge" with revisions "1-1918" from 
+  http://svn.atheme.org/charybdis/trunk
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/  (Property Modified)
+
+
+nenolod     2006/08/31 10:32:46 UTC    (20060831-1919)
+  Log:
+  - branch 2.1 release family
+  
+
+  Changes:     Modified:
+  + -          branches/release-2.1/ (File Added) 
+
+
+jilles      2006/08/30 16:20:52 UTC    (20060830-1917)
+  Log:
+  Describe new handling of host mangling in channel bans in SGML.
+  
+
+  Changes:     Modified:
+  +7 -1                trunk/doc/sgml/oper-guide/cmodes.sgml (File Modified) 
+
+
+nenolod     2006/08/29 20:24:08 UTC    (20060829-1915)
+  Log:
+  - ok, 2.1 operline brought to you by marvin the melancholy robot
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/messages.tab (File Modified) 
+
+
+nenolod     2006/08/29 19:48:43 UTC    (20060829-1913)
+  Log:
+  - change RPL_YOUREOPER to "Be sure to duck the rotten tomatoes."
+  If anybody comes up with anything better, then please let us know
+  and we will change this before 2.1 is branched.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/messages.tab (File Modified) 
+
+
+jilles      2006/08/29 19:34:39 UTC    (20060829-1911)
+  Log:
+  Add EUID to capab.txt.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/doc/technical/capab.txt (File Modified) 
+
+
+jilles      2006/08/29 19:32:44 UTC    (20060829-1909)
+  Log:
+  Update NEWS file.
+  
+
+  Changes:     Modified:
+  +3 -0                trunk/NEWS (File Modified) 
+
+
+jilles      2006/08/29 19:18:15 UTC    (20060829-1907)
+  Log:
+  Allow service{} servers to manipulate the nick delay table
+  (for "nickserv enforcement").
+  Syntax: :<server> ENCAP * NICKDELAY <duration> <nick>
+  If duration is 0, the nickdelay entry is removed, otherwise
+  it is added with the duration in seconds (maximum 24 hours).
+  It is suggested that this is used if the EUID capab is present.
+  
+
+  Changes:     Modified:
+  +42 -1       trunk/modules/m_services.c (File Modified) 
+
+
+jilles      2006/08/29 14:51:31 UTC    (20060829-1905)
+  Log:
+  HURT: strip off *@ from the start of the mask
+  reject anything else containing '@' or '!'
+  
+
+  Changes:     Modified:
+  +11 -0       trunk/extensions/hurt.c (File Modified) 
+
+
+jilles      2006/08/29 14:46:33 UTC    (20060829-1903)
+  Log:
+  ircd.c: need supported.h here
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/src/ircd.c (File Modified) 
+
+
+jilles      2006/08/29 14:45:53 UTC    (20060829-1901)
+  Log:
+  HURT: less ambiguity here
+  ips/hosts to be hurt must contain a '.' or ':' otherwise
+  they are interpreted as nicks
+  
+
+  Changes:     Modified:
+  +14 -9       trunk/extensions/hurt.c (File Modified) 
+
+
+nenolod     2006/08/29 14:40:11 UTC    (20060829-1899)
+  Log:
+  - we're now ircd-charybdis.org.
+  - properly alphabetize credits
+  
+
+  Changes:     Modified:
+  +4 -5                trunk/CREDITS (File Modified) (Property Modified)
+
+
+nenolod     2006/08/29 14:35:53 UTC    (20060829-1897)
+  Log:
+  - add additional modules to the configs
+  
+
+  Changes:     Modified:
+  +6 -0                trunk/doc/example.conf (File Modified) 
+  +12 -0       trunk/doc/reference.conf (File Modified) 
+
+
+nenolod     2006/08/29 14:26:40 UTC    (20060829-1895)
+  Log:
+  - remove hurt.h, it is pointless and confusing
+  
+
+  Changes:     Modified:
+  +27 -62      trunk/extensions/hurt.c (File Modified) 
+  + -          trunk/extensions/hurt.h (File Deleted) 
+
+
+nenolod     2006/08/29 14:24:37 UTC    (20060829-1893)
+  Log:
+  - add code to suggest a local HURT by nickname.
+  - clean up this code (use libcharybdis runtime for memory management, not system libc)
+  
+
+  Changes:     Modified:
+  +40 -10      trunk/extensions/hurt.c (File Modified) 
+  +1 -0                trunk/extensions/hurt.h (File Modified) 
+
+
+nenolod     2006/08/29 14:13:06 UTC    (20060829-1891)
+  Log:
+  - update NEWS file
+  
+
+  Changes:     Modified:
+  +2 -1                trunk/NEWS (File Modified) 
+
+
+jilles      2006/08/29 13:49:29 UTC    (20060829-1889)
+  Log:
+  MASKTRACE/TESTMASK: check orighost as well
+  
+
+  Changes:     Modified:
+  +4 -2                trunk/modules/m_etrace.c (File Modified) 
+  +3 -1                trunk/modules/m_testmask.c (File Modified) 
+
+
+jilles      2006/08/29 13:42:56 UTC    (20060829-1887)
+  Log:
+  Make RPL_ISUPPORT (005) numeric modularizable.
+  Currently it will reassemble the numeric every time
+  it needs to be sent, using a few dozen callbacks;
+  if this is too slow some caching scheme should be
+  implemented.
+  
+
+  Changes:     Modified:
+  +0 -1                trunk/include/s_user.h (File Modified) 
+  +36 -114     trunk/include/supported.h (File Modified) 
+  +1 -1                trunk/modules/m_version.c (File Modified) 
+  +1 -0                trunk/src/Makefile.in (File Modified) 
+  +1 -0                trunk/src/ircd.c (File Modified) 
+  +300 -25     trunk/src/s_user.c (File Modified) 
+  + -          trunk/src/supported.c (File Added) 
+
+
+jilles      2006/08/28 10:09:50 UTC    (20060828-1885)
+  Log:
+  EUID orighost could differ from host only in case,
+  do not mark as dynamic spoof then
+  
+
+  Changes:     Modified:
+  +2 -1                trunk/modules/core/m_nick.c (File Modified) 
+
+
+jilles      2006/08/28 09:52:57 UTC    (20060828-1883)
+  Log:
+  kline help file: clarify a bit and remove some obsolete stuff
+  partly suggested by Olin
+  
+
+  Changes:     Modified:
+  +8 -8                trunk/help/opers/kline (File Modified) 
+
+
+jilles      2006/08/28 09:51:56 UTC    (20060828-1881)
+  Log:
+  Update NEWS file.
+  
+
+  Changes:     Modified:
+  +20 -0       trunk/NEWS (File Modified) 
+
+
+jilles      2006/08/27 21:18:43 UTC    (20060827-1879)
+  Log:
+  Show real host/IP to nonopers whoising themselves.
+  The IP is not shown for auth{} spoofs, otherwise it is,
+  as it looked rather weird to me to show an auth{} spoofed
+  IP like this. (/userhost on self still shows the IP.)
+  
+
+  Changes:     Modified:
+  +13 -2       trunk/modules/m_whois.c (File Modified) 
+
+
+jilles      2006/08/27 18:30:04 UTC    (20060827-1877)
+  Log:
+  Document nick_delay stuff and move it around a bit.
+  
+
+  Changes:     Modified:
+  +1 -2                trunk/doc/example.conf (File Modified) 
+  +8 -2                trunk/doc/reference.conf (File Modified) 
+
+
+nenolod     2006/08/27 18:22:55 UTC    (20060827-1875)
+  Log:
+  - disable nickdelay by default. Needs to be documented in reference.conf.
+  
+
+  Changes:     Modified:
+  +2 -0                trunk/doc/example.conf (File Modified) 
+  +2 -0                trunk/doc/reference.conf (File Modified) 
+
+
+jilles      2006/08/27 18:05:50 UTC    (20060827-1873)
+  Log:
+  Fix RPL_WHOISLOGGEDIN (330) not being sent in TS6 form.
+  
+
+  Changes:     Modified:
+  +2 -1                trunk/modules/m_services.c (File Modified) 
+
+
+jilles      2006/08/27 15:36:00 UTC    (20060827-1871)
+  Log:
+  ip_cloaking: somewhat hackish but we need to send the
+  396 (RPL_HOSTHIDDEN) on connect if +h is in default
+  umodes
+  
+
+  Changes:     Modified:
+  +3 -0                trunk/extensions/ip_cloaking.c (File Modified) 
+
+
+jilles      2006/08/27 14:24:25 UTC    (20060827-1869)
+  Log:
+  If EUID is used, show realhost in far connect notice
+  (but not in far disconnect notice).
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/extensions/sno_farconnect.c (File Modified) 
+
+
+jilles      2006/08/27 14:21:45 UTC    (20060827-1867)
+  Log:
+  ip_cloaking:
+  - use non-ENCAP CHGHOST if possible
+  - really introduce new users with their mangled and real
+    host if +h is in default umodes
+  
+
+  Changes:     Modified:
+  +15 -3       trunk/extensions/ip_cloaking.c (File Modified) 
+
+
+jilles      2006/08/27 14:02:57 UTC    (20060827-1865)
+  Log:
+  Add non-ENCAP CHGHOST.
+  
+
+  Changes:     Modified:
+  +49 -11      trunk/modules/m_chghost.c (File Modified) 
+
+
+jilles      2006/08/27 13:40:37 UTC    (20060827-1863)
+  Log:
+  Initial addition of EUID (puts realhost/account in same
+  command as user introduction).
+  See doc/technical/euid.txt for more information.
+  At this time, EUID requires TS6, and new CHGHOST is not done yet.
+  
+
+  Changes:     Modified:
+  + -          trunk/doc/technical/euid.txt (File Added) 
+  +2 -1                trunk/include/s_serv.h (File Modified) 
+  +1 -1                trunk/include/s_user.h (File Modified) 
+  +127 -4      trunk/modules/core/m_nick.c (File Modified) 
+  +1 -34       trunk/modules/m_chghost.c (File Modified) 
+  +0 -28       trunk/modules/m_services.c (File Modified) 
+  +30 -1       trunk/src/s_serv.c (File Modified) 
+  +30 -3       trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/08/26 23:21:42 UTC    (20060826-1861)
+  Log:
+  Store the mangled host in localClient and use it for
+  ban matching (also match real host for mangled users,
+  also match mangled host for uncloaked users).
+  Improve interaction of +h with auth{} and services
+  spoofs.
+  Note that all of this only applies to clients who
+  connect after the mangling module is loaded
+  (other clients cannot even set +h).
+  The sorcerynet cloaking module has not been updated
+  for these changes.
+  
+
+  Changes:     Modified:
+  +31 -13      trunk/extensions/ip_cloaking.c (File Modified) 
+  +3 -0                trunk/include/client.h (File Modified) 
+  +64 -5       trunk/src/channel.c (File Modified) 
+  +1 -0                trunk/src/client.c (File Modified) 
+  +2 -2                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/08/25 20:20:42 UTC    (20060825-1859)
+  Log:
+  Document /stats U letters in sgml.
+  
+
+  Changes:     Modified:
+  +27 -21      trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+jilles      2006/08/25 14:33:51 UTC    (20060825-1857)
+  Log:
+  Better description of hub_mask and leaf_mask.
+  
+
+  Changes:     Modified:
+  +13 -2       trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+jilles      2006/08/25 14:24:14 UTC    (20060825-1855)
+  Log:
+  Add operspy_dont_care_user_info to sgml docs.
+  
+
+  Changes:     Modified:
+  +6 -0                trunk/doc/sgml/oper-guide/oprivs.sgml (File Modified) 
+
+
+jilles      2006/08/24 18:30:52 UTC    (20060824-1853)
+  Log:
+  Add general::operspy_dont_care_user_info.
+  This makes /who mask equivalent to /who !mask for opers
+  with the operspy flag, and removes the operspy log/notice
+  on /who mask, /masktrace and /scan.
+  The necessary privilege (operspy flag) is unchanged.
+  Behaviour for the other operspy commands (channel
+  related ones) is also unchanged.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/doc/example.conf (File Modified) 
+  +6 -0                trunk/doc/reference.conf (File Modified) 
+  +1 -0                trunk/include/s_conf.h (File Modified) 
+  +10 -8       trunk/modules/m_etrace.c (File Modified) 
+  +6 -0                trunk/modules/m_info.c (File Modified) 
+  +8 -5                trunk/modules/m_scan.c (File Modified) 
+  +1 -1                trunk/modules/m_version.c (File Modified) 
+  +6 -1                trunk/modules/m_who.c (File Modified) 
+  +1 -0                trunk/src/newconf.c (File Modified) 
+  +1 -0                trunk/src/s_conf.c (File Modified) 
+
+
+jilles      2006/08/24 17:16:53 UTC    (20060824-1851)
+  Log:
+  Show 'S' in /version if sno_farconnect.so has ever been loaded.
+  This letter will also be used for showing operspy with
+  limited accountability (show non channel related info
+  without '!' or notice).
+  
+
+  Changes:     Modified:
+  +2 -0                trunk/doc/server-version-info (File Modified) 
+  +3 -0                trunk/extensions/sno_farconnect.c (File Modified) 
+  +2 -0                trunk/include/ircd.h (File Modified) 
+  +6 -0                trunk/modules/m_info.c (File Modified) 
+  +2 -0                trunk/modules/m_version.c (File Modified) 
+  +1 -0                trunk/src/ircd_state.c (File Modified) 
+
+
+jilles      2006/08/23 12:40:21 UTC    (20060823-1849)
+  Log:
+  Add m_webirc module, allows showing real host of CGI:IRC users.
+  Differences to the version available on my web page for a while:
+  instructions on how to set it up.
+  
+
+  Changes:     Modified:
+  +137 -0      trunk/extensions/Makefile.in (File Modified) 
+  + -          trunk/extensions/m_webirc.c (File Added) 
+
+
+nenolod     2006/08/23 10:21:57 UTC    (20060823-1847)
+  Log:
+  - make I/O ports code compile on solaris 10 (tested on SunOS 5.10 sun4u sparc64)
+  
+
+  Changes:     Modified:
+  +5 -50       trunk/libcharybdis/ports.c (File Modified) 
+
+
+nenolod     2006/08/22 23:57:10 UTC    (20060822-1845)
+  Log:
+  - move beu from core to contributors
+  - adjust captialisation on gxti's nickname (he uses gxti now instead of GXTi).
+  
+
+  Changes:     Modified:
+  +2 -2                trunk/CREDITS (File Modified) 
+
+
+jilles      2006/08/22 17:57:25 UTC    (20060822-1843)
+  Log:
+  Mention that class blocks must be defined before the
+  auth or connect blocks referencing them.
+  
+
+  Changes:     Modified:
+  +4 -2                trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+jilles      2006/08/22 17:30:03 UTC    (20060822-1841)
+  Log:
+  extb_canjoin:
+  - change from "can join" to "is banned", this reverses sense
+    and removes "weird" checks like for +i, +l, +j
+  - don't allow $j to same channel
+  - +s/+p restriction removed, anyone can /mode b anyway
+  - +k check removed
+  
+
+  Changes:     Modified:
+  +12 -8       trunk/extensions/extb_canjoin.c (File Modified) 
+
+
+jilles      2006/08/22 15:25:37 UTC    (20060822-1839)
+  Log:
+  Add a few important lines from reference.conf to example.conf.
+  
+
+  Changes:     Modified:
+  +8 -1                trunk/doc/example.conf (File Modified) 
+
+
+nenolod     2006/08/22 14:05:58 UTC    (20060822-1837)
+  Log:
+  - we don't support rtsigio anymore
+  - we definately don't support VMS nor Cygwin either.
+  
+
+  Changes:     Modified:
+  +2 -2                trunk/INSTALL (File Modified) 
+  +0 -2                trunk/README.FIRST (File Modified) 
+
+
+nenolod     2006/08/22 12:59:38 UTC    (20060822-1835)
+  Log:
+  - if the channel is +k, pass the source channel's key to can_join() for the target channel.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/extensions/extb_canjoin.c (File Modified) 
+
+
+jilles      2006/08/22 12:55:22 UTC    (20060822-1833)
+  Log:
+  extb_canjoin:
+  - return EXTBAN_NOMATCH for a valid ban that does not match
+  - consider a $j ban invalid if we were already processing a
+    can_join for a $j ban
+  
+
+  Changes:     Modified:
+  +7 -2                trunk/extensions/extb_canjoin.c (File Modified) 
+
+
+jilles      2006/08/22 12:44:04 UTC    (20060822-1831)
+  Log:
+  extb_extgecos: realhost -> orighost
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/extensions/extb_extgecos.c (File Modified) 
+
+
+nenolod     2006/08/22 07:05:17 UTC    (20060822-1829)
+  Log:
+  - add $j extban type, allows entry or non-entry to a channel based on whether or not you can join another channel.
+  
+
+  Changes:     Modified:
+  +59 -0       trunk/extensions/Makefile.in (File Modified) 
+  + -          trunk/extensions/extb_canjoin.c (File Added) 
+
+
+nenolod     2006/08/22 05:06:34 UTC    (20060822-1827)
+  Log:
+  - oh right, charybdis calls that 'orighost'.
+  
+
+  Changes:     Modified:
+  +2 -2                trunk/modules/m_who.c (File Modified) 
+
+
+nenolod     2006/08/22 05:05:20 UTC    (20060822-1825)
+  Log:
+  - allow *opers* to do a /who based on realhost. Perhaps this should require operspy? TBD.
+  
+
+  Changes:     Modified:
+  +2 -0                trunk/modules/m_who.c (File Modified) 
+
+
+nenolod     2006/08/22 00:16:38 UTC    (20060822-1823)
+  Log:
+  - also check $x against realhost
+  
+
+  Changes:     Modified:
+  +12 -1       trunk/extensions/extb_extgecos.c (File Modified) 
+
+
+jilles      2006/08/20 17:16:37 UTC    (20060820-1811)
+  Log:
+  Sorcerynet people want a debugging notice moved from +s to +d.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/blacklist.c (File Modified) 
+
+
+jilles      2006/08/20 16:59:27 UTC    (20060820-1805)
+  Log:
+  Use source_p instead of client_p for free_pre_client().
+  client_p could be NULL or another client.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/client.c (File Modified) 
+
+
+nenolod     2006/08/20 16:58:04 UTC    (20060820-1803)
+  Log:
+  - revert this, I know how to fix it now
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/modules/core/m_nick.c (File Modified) 
+
+
+nenolod     2006/08/20 16:55:31 UTC    (20060820-1801)
+  Log:
+  - pass an actual valid client_p to exit_client() when dealing with Overriden condition.
+  This fix is probably suboptimal, but it does indeed fix the problem.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/modules/core/m_nick.c (File Modified) 
+
+
+nenolod     2006/08/20 10:27:33 UTC    (20060820-1799)
+  Log:
+  - add extb_extgecos extban option ($x:nick!user@host#gecos), from sorcery modules
+  
+
+  Changes:     Modified:
+  +49 -0       trunk/extensions/Makefile.in (File Modified) 
+  + -          trunk/extensions/extb_extgecos.c (File Added) 
+
+
+jilles      2006/08/10 00:00:44 UTC    (20060810-1797)
+  Log:
+  Remove undocumented and unused general::fallback_to_ip6_int config option.
+  
+
+  Changes:     Modified:
+  +0 -3                trunk/include/s_conf.h (File Modified) 
+  +0 -3                trunk/src/newconf.c (File Modified) 
+
+
+jilles      2006/08/04 20:12:47 UTC    (20060804-1795)
+  Log:
+  SGML docs:
+  - document new TESTMASK
+  - mention that TESTMASK matching is the same as MASKTRACE matching
+  - mention that gecos in TESTMASK/MASKTRACE is optional (has always
+    been that way)
+  
+
+  Changes:     Modified:
+  +23 -6       trunk/doc/sgml/oper-guide/commands.sgml (File Modified) 
+
+
+jilles      2006/08/04 19:56:03 UTC    (20060804-1793)
+  Log:
+  New testmask from ratbox 2.2.
+  Allows matches on nick, ip and gecos in addition to user
+  and host, and is fully analogous to masktrace.
+  The numeric has changed from 724 to 727 and fields in it
+  have changed.
+  
+
+  Changes:     Modified:
+  +4 -3                trunk/help/opers/testmask (File Modified) 
+  +1 -0                trunk/include/numeric.h (File Modified) 
+  +82 -9       trunk/modules/m_testmask.c (File Modified) 
+  +2 -2                trunk/src/messages.tab (File Modified) 
+
+
+jilles      2006/08/04 19:33:27 UTC    (20060804-1791)
+  Log:
+  contrib -> extensions
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/doc/sgml/oper-guide/umodes.sgml (File Modified) 
+
+
+jilles      2006/08/03 22:12:00 UTC    (20060803-1789)
+  Log:
+  CHGHOST: Check validity of new hostname.
+  If the command came from a local client (disabled by
+  default), send an error message and drop the command.
+  If the command came from a remote client or server,
+  send a notice to opers and the target user (if local).
+  
+
+  Changes:     Modified:
+  +42 -1       trunk/modules/m_chghost.c (File Modified) 
+
+
+jilles      2006/07/31 15:54:57 UTC    (20060731-1787)
+  Log:
+  Update NEWS file.
+  
+
+  Changes:     Modified:
+  +23 -1       trunk/NEWS (File Modified) 
+
+
+jilles      2006/07/31 15:24:06 UTC    (20060731-1785)
+  Log:
+  When an outgoing server connection succeeds, set
+  localClient->ip by simply copying the whole sockaddr
+  struct instead of copying certain parts only.
+  
+
+  Changes:     Modified:
+  +1 -19       trunk/src/s_serv.c (File Modified) 
+
+
+jilles      2006/07/31 15:17:19 UTC    (20060731-1783)
+  Log:
+  Give a special error message and ignore the connect block
+  if trying to add a connect block for the server's own name.
+  
+
+  Changes:     Modified:
+  +7 -0                trunk/src/newconf.c (File Modified) 
+
+
+jilles      2006/07/30 18:07:38 UTC    (20060730-1781)
+  Log:
+  Provide stubs for BlockHeapUsage(), struct MemBlock and MemBlock
+  when --disable-balloc is used, so that it compiles.
+  Obviously the BlockHeapUsage() stub returns just zeroes so
+  /stats z will be less informative.
+  
+
+  Changes:     Modified:
+  +5 -0                trunk/libcharybdis/balloc.h (File Modified) 
+
+
+jilles      2006/07/30 16:36:39 UTC    (20060730-1779)
+  Log:
+  Free and zero dns_query in DNS callback for outgoing connect.
+  This avoids double free of reslist.
+  
+
+  Changes:     Modified:
+  +4 -0                trunk/libcharybdis/commio.c (File Modified) 
+
+
+jilles      2006/07/30 16:10:50 UTC    (20060730-1777)
+  Log:
+  From ratbox, log failed outgoing connections to serverlog.
+  Added: IP address.
+  
+
+  Changes:     Modified:
+  +13 -1       trunk/src/s_serv.c (File Modified) 
+
+
+jilles      2006/07/30 15:44:50 UTC    (20060730-1775)
+  Log:
+  Change serverlog message when connecting to be more clear and show the port number.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/s_serv.c (File Modified) 
+
+
+jilles      2006/07/30 15:03:52 UTC    (20060730-1773)
+  Log:
+  Remove gethost_byname(), this is meaningless
+  since the removal of AAAA -> A fallback (r1763).
+  
+
+  Changes:     Modified:
+  +0 -1                trunk/include/res.h (File Modified) 
+  +0 -12       trunk/src/res.c (File Modified) 
+
+
+jilles      2006/07/30 14:47:53 UTC    (20060730-1771)
+  Log:
+  Remove ip6.int support and use only ip6.arpa.
+  The global ip6.int zone has disappeared on June 1
+  and a lot of other software has been removing ip6.int
+  support also.
+  This removes the second and last case where IPv6
+  support in charybdis causes extra lookups and slows
+  DNS down.
+  
+
+  Changes:     Modified:
+  +5 -27       trunk/src/res.c (File Modified) 
+
+
+jilles      2006/07/30 14:30:48 UTC    (20060730-1769)
+  Log:
+  Mention new default (r1767) for connect::aftype in sgml docs.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+jilles      2006/07/30 13:59:15 UTC    (20060730-1767)
+  Log:
+  Use IPv6 if connect::host looks like an IPv6 address
+  (contains a colon). No need to aftype=ipv6 anymore.
+  
+
+  Changes:     Modified:
+  +2 -0                trunk/src/newconf.c (File Modified) 
+
+
+jilles      2006/07/30 13:42:26 UTC    (20060730-1765)
+  Log:
+  More information about connect::host.
+  
+
+  Changes:     Modified:
+  +7 -2                trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+jilles      2006/07/30 12:59:39 UTC    (20060730-1763)
+  Log:
+  Remove fallback to A if AAAA cannot be found.
+  In case of a forward check of a reverse lookup, we
+  already know if it's ipv4 or ipv6, so it is not
+  useful and in case of a forward lookup of a hostname
+  in connect::host, connect::aftype already specifies
+  if it's ipv4 or ipv6.
+  
+
+  Changes:     Modified:
+  +4 -27       trunk/src/res.c (File Modified) 
+
+
+jilles      2006/07/27 19:27:49 UTC    (20060727-1761)
+  Log:
+  msg_channel():
+  - check if +c made the message text empty and refuse
+    to send it if so
+  - don't copy message text if it is not necessary
+    (channel is -c)
+  
+
+  Changes:     Modified:
+  +14 -4       trunk/modules/core/m_message.c (File Modified) 
+
+
+jilles      2006/07/25 23:46:50 UTC    (20060725-1759)
+  Log:
+  remove_conf_item(): do not free cf_name, this is generally a string constant
+  
+
+  Changes:     Modified:
+  +0 -1                trunk/src/newconf.c (File Modified) 
+
+
+jilles      2006/07/25 23:34:45 UTC    (20060725-1757)
+  Log:
+  Remove the old unused FDL_ constants.
+  
+
+  Changes:     Modified:
+  +0 -9                trunk/libcharybdis/commio.h (File Modified) 
+
+
+jilles      2006/07/25 23:17:59 UTC    (20060725-1755)
+  Log:
+  Remove an unused struct irc_sockaddr_storage from fde_t
+  (allocated for every possible file descriptor).
+  
+
+  Changes:     Modified:
+  +0 -2                trunk/libcharybdis/commio.h (File Modified) 
+
+
+jilles      2006/07/25 22:48:38 UTC    (20060725-1753)
+  Log:
+  If the DNS lookup for an outgoing connection is still
+  pending when it is closed, clean it up.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/libcharybdis/commio.c (File Modified) 
+
+
+jilles      2006/07/25 22:40:33 UTC    (20060725-1751)
+  Log:
+  If proc_answer() fails (for example if a lookup for an
+  A record returns a CNAME), fail the query immediately.
+  Previously the packet was just ignored, leaving the
+  query to time out.
+  
+
+  Changes:     Modified:
+  +4 -8                trunk/src/res.c (File Modified) 
+
+
+jilles      2006/07/25 22:16:20 UTC    (20060725-1749)
+  Log:
+  Correct sockhost field in an outgoing server connection.
+  First copy the host field from the server_conf, then
+  take the IP from to where the connection was attempted
+  when the connection callback is called.
+  (Before r1747 this used the IP from the server_conf.)
+  
+
+  Changes:     Modified:
+  +8 -2                trunk/src/s_serv.c (File Modified) 
+
+
+jilles      2006/07/25 21:22:45 UTC    (20060725-1747)
+  Log:
+  Remove ipnum (keep aftype) and dns_query from server_conf.
+  We don't keep track of binary form address in connect{}
+  blocks anymore, DNS lookups of names in host= gone.
+  As before the DNS lookup is done on connect.
+  This should unbreak hostnames in host= somewhat.
+  
+
+  Changes:     Modified:
+  +1 -2                trunk/include/s_newconf.h (File Modified) 
+  +2 -2                trunk/src/newconf.c (File Modified) 
+  +1 -42       trunk/src/s_newconf.c (File Modified) 
+  +12 -31      trunk/src/s_serv.c (File Modified) 
+
+
+jilles      2006/07/25 16:25:56 UTC    (20060725-1745)
+  Log:
+  Rerun autoconf.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/configure (File Modified) 
+
+
+jilles      2006/07/25 16:25:12 UTC    (20060725-1743)
+  Log:
+  Fix --disable-balloc help text (said --disable-small-net).
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/configure.ac (File Modified) 
+
+
+jilles      2006/07/23 18:58:52 UTC    (20060723-1741)
+  Log:
+  Add general::servicestring, shown on RPL_WHOISOPERATOR for
+  services (+S). Unlike operstring and adminstring, this
+  is not changeable with /quote set but is updated on rehash.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/doc/example.conf (File Modified) 
+  +10 -2       trunk/doc/reference.conf (File Modified) 
+  +1 -0                trunk/include/s_conf.h (File Modified) 
+  +6 -0                trunk/modules/m_info.c (File Modified) 
+  +3 -2                trunk/modules/m_whois.c (File Modified) 
+  +1 -0                trunk/src/newconf.c (File Modified) 
+  +1 -0                trunk/src/s_conf.c (File Modified) 
+
+
+jilles      2006/07/22 16:27:02 UTC    (20060722-1739)
+  Log:
+  Fix handling of comma in whois: ignore the comma and
+  everything after it but do output the entire parameter
+  in RPL_ENDOFWHOIS.
+  
+
+  Changes:     Modified:
+  +2 -2                trunk/modules/m_whois.c (File Modified) 
+
+
+beu         2006/07/21 22:36:46 UTC    (20060721-1737)
+  Log:
+  New /stats letter 's' to list HURTs:
+  - opers get the full listing.
+  - users get any HURTs that match their sockhost/orighost if
+    "stats_k_oper_only" is set to 1.
+  
+
+  Changes:     Modified:
+  +50 -0       trunk/extensions/hurt.c (File Modified) 
+
+
+nenolod     2006/07/19 02:35:40 UTC    (20060719-1735)
+  Log:
+  - make the newconf system available to modules.
+  
+
+  Changes:     Modified:
+  +4 -1                trunk/include/newconf.h (File Modified) 
+  +4 -8                trunk/src/newconf.c (File Modified) 
+
+
+beu         2006/07/18 22:39:16 UTC    (20060718-1733)
+  Log:
+  Undo silly commit (tor.dnsbl.sectoor.de requirs record checking).
+
+  Changes:     Modified:
+  +0 -3                trunk/doc/example.conf (File Modified) 
+  +0 -3                trunk/doc/reference.conf (File Modified) 
+
+
+beu         2006/07/18 22:34:36 UTC    (20060718-1731)
+  Log:
+  Add more effective Tor DNSBL (more up-to-date, more NATed nodes, etc).
+  
+
+  Changes:     Modified:
+  +3 -0                trunk/doc/example.conf (File Modified) 
+  +3 -0                trunk/doc/reference.conf (File Modified) 
+
+
+jilles      2006/07/17 16:48:13 UTC    (20060717-1729)
+  Log:
+  Fix too early truncation of JOIN channel list.
+  
+
+  Changes:     Modified:
+  +2 -3                trunk/modules/core/m_join.c (File Modified) 
+
+
+jilles      2006/07/07 21:59:52 UTC    (20060707-1727)
+  Log:
+  - From ratbox 2.2 (anfl), send server notices about read
+    errors from handshakes and servers to +s instead of +d.
+  - Send various server notices about failed server
+    connections which did not reach registered state network
+    wide if the connection was initiated by a remote oper.
+    This avoids annoying the whole net if there is a
+    broken autoconnect, but allows all opers to see why a
+    remote connect failed. Failed connections which did reach
+    server state already generate server notices everywhere.
+  
+  Note: this is an exception to our general policy to not send
+  server notices about unregistered connections remotely.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/include/client.h (File Modified) 
+  +20 -6       trunk/src/client.c (File Modified) 
+  +6 -6                trunk/src/s_serv.c (File Modified) 
+
+
+nenolod     2006/07/07 14:41:39 UTC    (20060707-1725)
+  Log:
+  - fix typoes
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/doc/example.conf (File Modified) 
+  +1 -1                trunk/doc/reference.conf (File Modified) 
+
+
+jilles      2006/07/06 15:23:58 UTC    (20060706-1723)
+  Log:
+  Don't allow #channel +b $c:&channel (inconsistent target).
+  
+
+  Changes:     Modified:
+  +3 -0                trunk/extensions/extb_channel.c (File Modified) 
+
+
+jilles      2006/07/05 14:37:18 UTC    (20060705-1721)
+  Log:
+  Remove dns_query pointer from LocalClient, we store this in AuthQuery.
+  
+
+  Changes:     Modified:
+  +0 -2                trunk/include/client.h (File Modified) 
+
+
+jilles      2006/07/05 13:28:40 UTC    (20060705-1719)
+  Log:
+  Invalidate can_send ban cache when a TS6 SJOIN clears the ban list.
+  
+
+  Changes:     Modified:
+  +2 -0                trunk/modules/core/m_sjoin.c (File Modified) 
+
+
+jilles      2006/07/04 14:41:11 UTC    (20060704-1717)
+  Log:
+  Store IP addresses in whowas. These are shown to opers.
+  Obtained from Eurus patches.
+  orighost tracking removed (not worth the memory IMHO),
+  numeric changed to RPL_WHOISACTUALLY, fixed to deal
+  with unknown IPs and to not violate auth{} spoof policy.
+  
+
+  Changes:     Modified:
+  +2 -0                trunk/doc/reference.conf (File Modified) 
+  +1 -0                trunk/include/numeric.h (File Modified) 
+  +1 -0                trunk/include/whowas.h (File Modified) 
+  +10 -1       trunk/modules/m_whowas.c (File Modified) 
+  +1 -1                trunk/src/messages.tab (File Modified) 
+  +4 -0                trunk/src/whowas.c (File Modified) 
+
+
+jilles      2006/07/03 15:18:47 UTC    (20060703-1715)
+  Log:
+  Describe hostmask parameter of masktrace better in sgml docs.
+  
+
+  Changes:     Modified:
+  +5 -0                trunk/doc/sgml/oper-guide/commands.sgml (File Modified) 
+
+
+jilles      2006/07/03 14:03:05 UTC    (20060703-1713)
+  Log:
+  masktrace help file: mention CIDR IP masks
+  From ratbox 2.2
+  
+
+  Changes:     Modified:
+  +2 -0                trunk/help/opers/masktrace (File Modified) 
+
+
+jilles      2006/07/03 13:56:38 UTC    (20060703-1711)
+  Log:
+  MASKTRACE: allow normal match() on IP address also
+  From ratbox 2.2
+  
+
+  Changes:     Modified:
+  +2 -3                trunk/modules/m_etrace.c (File Modified) 
+
+
+jilles      2006/06/29 22:36:45 UTC    (20060629-1709)
+  Log:
+  Allow +S clients (services) to send to channels and @/+ channels always.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/modules/core/m_message.c (File Modified) 
+  +1 -1                trunk/src/channel.c (File Modified) 
+
+
+jilles      2006/06/29 22:25:46 UTC    (20060629-1707)
+  Log:
+  Allow servers to send to @#chan and +#chan.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/modules/core/m_message.c (File Modified) 
+
+
+jilles      2006/06/29 21:51:59 UTC    (20060629-1705)
+  Log:
+  Don't count opers on service{} servers in /lusers.
+  
+
+  Changes:     Modified:
+  +2 -2                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/06/29 21:19:38 UTC    (20060629-1703)
+  Log:
+  Show opers the real host behind a dynamic spoof in WHOIS.
+  If the user is auth{} spoofed, this shows the auth{} spoof
+  otherwise it shows the DNS hostname and IP address.
+  The numeric used is 378 (RPL_WHOISHOST) taken from Unreal.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/include/numeric.h (File Modified) 
+  +12 -2       trunk/modules/m_whois.c (File Modified) 
+  +1 -1                trunk/src/messages.tab (File Modified) 
+
+
+jilles      2006/06/27 16:25:52 UTC    (20060627-1701)
+  Log:
+  Remove #define HIDE_SPOOF_IPS from config.h, should
+  have been done earlier.
+  
+
+  Changes:     Modified:
+  +0 -7                trunk/include/config.h (File Modified) 
+
+
+jilles      2006/06/27 15:29:10 UTC    (20060627-1699)
+  Log:
+  Bring back ERR_CANTKILLSERVER.
+  
+
+  Changes:     Modified:
+  +5 -7                trunk/modules/core/m_kill.c (File Modified) 
+
+
+jilles      2006/06/27 15:18:57 UTC    (20060627-1697)
+  Log:
+  ip_cloaking module:
+  - also send RPL_HOSTHIDDEN on -h
+  - don't allow +h for auth{} spoofed clients
+  
+
+  Changes:     Modified:
+  +8 -2                trunk/extensions/ip_cloaking.c (File Modified) 
+
+
+jilles      2006/06/27 15:11:23 UTC    (20060627-1695)
+  Log:
+  /etc/resolv.conf parsing:
+  - don't crash (sometimes) if there is a line without an argument
+    (e.g. 'search' by itself)
+  - fix handling of lines with leading whitespace
+  
+
+  Changes:     Modified:
+  +9 -8                trunk/src/reslib.c (File Modified) 
+
+
+jilles      2006/06/20 14:26:16 UTC    (20060620-1683)
+  Log:
+  Put back code that terminates DNS queries, which was
+  removed during the resolver changes.
+  
+
+  Changes:     Modified:
+  +4 -0                trunk/src/s_auth.c (File Modified) 
+
+
+nenolod     2006/06/20 09:20:58 UTC    (20060620-1681)
+  Log:
+  - oh hey, that was in the wrong place
+  
+
+  Changes:     Modified:
+  +13 -13      trunk/src/s_auth.c (File Modified) 
+
+
+nenolod     2006/06/20 08:33:20 UTC    (20060620-1679)
+  Log:
+  - handle a situation where a user can go away before DNS completes
+  
+
+  Changes:     Modified:
+  +13 -0       trunk/src/s_auth.c (File Modified) 
+
+
+jilles      2006/06/16 14:43:33 UTC    (20060616-1677)
+  Log:
+  More dnsbl stuff
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/include/blacklist.h (File Modified) 
+  +1 -0                trunk/include/res.h (File Modified) 
+  +33 -2       trunk/src/blacklist.c (File Modified) 
+  +2 -0                trunk/src/client.c (File Modified) 
+  +24 -0       trunk/src/res.c (File Modified) 
+
+
+jilles      2006/06/15 22:32:23 UTC    (20060615-1675)
+  Log:
+  Don't touch the returned sockaddr (mangle_mapped_sockaddr())
+  if comm_accept() failed.
+  
+  Found with valgrind.
+  
+
+  Changes:     Modified:
+  +4 -4                trunk/src/listener.c (File Modified) 
+
+
+nenolod     2006/06/15 18:13:04 UTC    (20060615-1673)
+  Log:
+  - handle unavailable Client/preClient structs
+  
+
+  Changes:     Modified:
+  +9 -0                trunk/src/blacklist.c (File Modified) 
+
+
+jilles      2006/06/14 17:52:20 UTC    (20060614-1671)
+  Log:
+  Add +lf to SGML docs.
+  
+
+  Changes:     Modified:
+  +3 -2                trunk/doc/sgml/oper-guide/cmodes.sgml (File Modified) 
+
+
+jilles      2006/06/14 17:48:41 UTC    (20060614-1669)
+  Log:
+  Also do forwarding if the channel limit (+l) is exceeded.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/help/opers/cmode (File Modified) 
+  +2 -2                trunk/modules/core/m_join.c (File Modified) 
+
+
+beu         2006/06/07 11:53:21 UTC    (20060607-1663)
+  Log:
+  Post-release lovin':
+  - Update version to 2.1.0.
+  - Regenerate configure.
+  
+
+  Changes:     Modified:
+  +9 -9                trunk/configure (File Modified) 
+  +1 -1                trunk/configure.ac (File Modified) 
+
+
+beu         2006/06/07 11:42:54 UTC    (20060607-1659)
+  Log:
+  Comment out example blacklist{} block.
+  
+
+  Changes:     Modified:
+  +7 -7                trunk/doc/example.conf (File Modified) 
+  +7 -7                trunk/doc/reference.conf (File Modified) 
+
+
+beu         2006/06/07 10:59:48 UTC    (20060607-1653)
+  Log:
+  Add note regarding use of AHBL BLs.
+  
+
+  Changes:     Modified:
+  +4 -0                trunk/doc/example.conf (File Modified) 
+  +4 -0                trunk/doc/reference.conf (File Modified) 
+
+
+jilles      2006/06/05 15:43:45 UTC    (20060605-1646)
+  Log:
+  Fix typos.
+  
+
+  Changes:     Modified:
+  +2 -2                trunk/CREDITS (File Modified) 
+
+
+jilles      2006/06/05 15:28:22 UTC    (20060605-1644)
+  Log:
+  Add beu to CREDITS.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/CREDITS (File Modified) 
+
+
+jilles      2006/06/05 00:02:19 UTC    (20060605-1640)
+  Log:
+  Put more recent ratbox CREDITS here.
+  
+
+  Changes:     Modified:
+  +3 -2                trunk/doc/Ratbox-team (File Modified) 
+
+
+jilles      2006/06/04 19:19:02 UTC    (20060604-1636)
+  Log:
+  Clarify a bit.
+  
+
+  Changes:     Modified:
+  +5 -4                trunk/NEWS (File Modified) 
+
+
+jilles      2006/06/04 13:26:04 UTC    (20060604-1634)
+  Log:
+  Mention that install or make install also avoids modunload crashes.
+  
+
+  Changes:     Modified:
+  +2 -1                trunk/BUGS (File Modified) 
+
+
+nenolod     2006/06/04 07:01:42 UTC    (20060604-1632)
+  Log:
+  - update NEWS a bit
+  
+
+  Changes:     Modified:
+  +3 -8                trunk/NEWS (File Modified) 
+
+
+nenolod     2006/06/04 03:06:33 UTC    (20060604-1630)
+  Log:
+  - further updates
+  
+
+  Changes:     Modified:
+  +3 -2                trunk/BUGS (File Modified) 
+
+
+nenolod     2006/06/04 03:05:20 UTC    (20060604-1628)
+  Log:
+  - add orighost check to hurt.c
+  - update BUGS info
+  
+
+  Changes:     Modified:
+  +1 -6                trunk/BUGS (File Modified) 
+  +1 -1                trunk/extensions/hurt.c (File Modified) 
+
+
+jilles      2006/06/04 03:03:46 UTC    (20060604-1626)
+  Log:
+  Make kline_exempt exempt from HURT also.
+  
+
+  Changes:     Modified:
+  +2 -1                trunk/extensions/hurt.c (File Modified) 
+
+
+jilles      2006/06/04 03:02:27 UTC    (20060604-1624)
+  Log:
+  Fix mask HEAL propagation.
+  
+
+  Changes:     Modified:
+  +6 -3                trunk/extensions/hurt.c (File Modified) 
+
+
+beu         2006/06/04 03:01:05 UTC    (20060604-1622)
+  Log:
+  - Remove old cruft.
+  - Update.
+  
+
+  Changes:     Modified:
+  +18 -31      trunk/extensions/README (File Modified) 
+
+
+jilles      2006/06/04 02:46:31 UTC    (20060604-1620)
+  Log:
+  More target change hax.
+  Ick.
+  
+
+  Changes:     Modified:
+  +5 -0                trunk/extensions/hurt.c (File Modified) 
+
+
+jilles      2006/06/04 02:44:47 UTC    (20060604-1618)
+  Log:
+  Improvements to HURT propagation.
+  
+
+  Changes:     Modified:
+  +8 -6                trunk/extensions/hurt.c (File Modified) 
+
+
+nenolod     2006/06/04 02:33:31 UTC    (20060604-1616)
+  Log:
+  - further simplification
+  
+
+  Changes:     Modified:
+  +25 -76      trunk/extensions/hurt.c (File Modified) 
+  +0 -9                trunk/extensions/hurt.h (File Modified) 
+
+
+nenolod     2006/06/04 02:22:52 UTC    (20060604-1614)
+  Log:
+  - client_exit hook
+  
+
+  Changes:     Modified:
+  +13 -0       trunk/extensions/hurt.c (File Modified) 
+
+
+nenolod     2006/06/04 02:17:01 UTC    (20060604-1612)
+  Log:
+  - cut off at 15 messages instead of 30
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/extensions/hurt.h (File Modified) 
+
+
+jilles      2006/06/04 02:16:18 UTC    (20060604-1610)
+  Log:
+  Squash a warning here.
+  
+
+  Changes:     Modified:
+  +1 -3                trunk/src/ircd.c (File Modified) 
+
+
+jilles      2006/06/04 02:11:40 UTC    (20060604-1608)
+  Log:
+  Don't show servers in /stats l to nonopers if flatten links is enabled.
+  
+
+  Changes:     Modified:
+  +3 -1                trunk/modules/m_stats.c (File Modified) 
+
+
+nenolod     2006/06/04 02:05:50 UTC    (20060604-1606)
+  Log:
+  - hurt expiry
+  
+
+  Changes:     Modified:
+  +20 -7       trunk/extensions/hurt.c (File Modified) 
+
+
+nenolod     2006/06/04 01:59:06 UTC    (20060604-1603)
+  Log:
+  - remove inline stuff (yuck)
+  - sockaddr should have been sockhost
+  
+
+  Changes:     Modified:
+  +22 -31      trunk/extensions/hurt.c (File Modified) 
+
+
+nenolod     2006/06/04 01:56:14 UTC    (20060604-1601)
+  Log:
+  - make hurt checking actually work
+  
+
+  Changes:     Modified:
+  +2 -7                trunk/extensions/hurt.c (File Modified) 
+
+
+jilles      2006/06/04 01:55:34 UTC    (20060604-1599)
+  Log:
+  Slight tweak to alias{}.
+  
+
+  Changes:     Modified:
+  +4 -0                trunk/src/parse.c (File Modified) 
+
+
+nenolod     2006/06/04 01:54:42 UTC    (20060604-1597)
+  Log:
+  - further simplification
+  
+
+  Changes:     Modified:
+  +59 -71      trunk/extensions/hurt.c (File Modified) 
+  +0 -1                trunk/extensions/hurt.h (File Modified) 
+
+
+nenolod     2006/06/04 01:40:14 UTC    (20060604-1595)
+  Log:
+  - further cleanup (but, it does not compile right now because i've removed the patricia code (well, most of it)
+  
+
+  Changes:     Modified:
+  +10 -20      trunk/extensions/hurt.c (File Modified) 
+  +0 -4                trunk/extensions/hurt.h (File Modified) 
+
+
+nenolod     2006/06/04 01:25:26 UTC    (20060604-1593)
+  Log:
+  - remove some unnecessary code here (hurt_initial_check_event()).
+  
+
+  Changes:     Modified:
+  +0 -23       trunk/extensions/hurt.c (File Modified) 
+
+
+nenolod     2006/06/04 01:21:30 UTC    (20060604-1591)
+  Log:
+  - if PRIVMSG has been crippled (localClient.target_last > CurrentTime), and the PM target is an operator, then allow it through
+  
+
+  Changes:     Modified:
+  +8 -0                trunk/modules/core/m_message.c (File Modified) 
+
+
+nenolod     2006/06/04 01:09:52 UTC    (20060604-1589)
+  Log:
+  - more sane tgchange hax
+  
+
+  Changes:     Modified:
+  +2 -1                trunk/extensions/hurt.c (File Modified) 
+
+
+jilles      2006/06/03 23:28:39 UTC    (20060603-1587)
+  Log:
+  Make HEAL <nick> work.
+  
+
+  Changes:     Modified:
+  +40 -43      trunk/extensions/hurt.c (File Modified) 
+
+
+jilles      2006/06/03 23:04:33 UTC    (20060603-1585)
+  Log:
+  Destroy hurt_clients list on unload.
+  
+
+  Changes:     Modified:
+  +7 -0                trunk/extensions/hurt.c (File Modified) 
+
+
+jilles      2006/06/03 22:55:21 UTC    (20060603-1583)
+  Log:
+  Coding style: no space between a function name and parenthesis.
+  
+
+  Changes:     Modified:
+  +43 -43      trunk/extensions/hurt.c (File Modified) 
+
+
+jilles      2006/06/03 22:48:40 UTC    (20060603-1581)
+  Log:
+  Now works and throws out hurt clients after 30 protocol messages
+  unless they identify.
+  
+
+  Changes:     Modified:
+  +28 -36      trunk/extensions/hurt.c (File Modified) 
+  +1 -7                trunk/extensions/hurt.h (File Modified) 
+
+
+jilles      2006/06/03 22:19:39 UTC    (20060603-1579)
+  Log:
+  Working addition/lookup.
+  
+
+  Changes:     Modified:
+  +8 -0                trunk/extensions/hurt.c (File Modified) 
+
+
+jilles      2006/06/03 22:00:31 UTC    (20060603-1577)
+  Log:
+  Get rid of hyb6 style propagation (:server COMMAND source).
+  
+
+  Changes:     Modified:
+  +18 -22      trunk/extensions/hurt.c (File Modified) 
+
+
+jilles      2006/06/03 21:53:47 UTC    (20060603-1575)
+  Log:
+  add not-working hurt_add and hurt_find
+  
+
+  Changes:     Modified:
+  +13 -5       trunk/extensions/hurt.c (File Modified) 
+
+
+jilles      2006/06/03 21:34:56 UTC    (20060603-1573)
+  Log:
+  Comment out a lot of stuff so I can load and unload this without crashing.
+  
+
+  Changes:     Modified:
+  +17 -6       trunk/extensions/hurt.c (File Modified) 
+
+
+jilles      2006/06/03 21:24:02 UTC    (20060603-1571)
+  Log:
+  Fix svn:keywords and add a short comment at the top.
+  
+
+  Changes:     Modified:
+  +8 -0                trunk/extensions/hurt.c (File Modified) (Property Modified)
+
+
+jilles      2006/06/03 21:21:44 UTC    (20060603-1569)
+  Log:
+  - Make hurt module compile
+  - Link it to the build
+  - Initial tweaks, use struct Message's min params, ERR_NOPRIVS shows
+    correct flag name, no CAP_TS6 use etc
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/extensions/Makefile.in (File Modified) 
+  +30 -32      trunk/extensions/hurt.c (File Modified) 
+
+
+jilles      2006/06/03 21:06:46 UTC    (20060603-1567)
+  Log:
+  Put beu's hurt module in trunk.
+  
+
+  Changes:     Modified:
+  + -          trunk/extensions/hurt.c (File Added) 
+  + -          trunk/extensions/hurt.h (File Added) 
+
+
+nenolod     2006/06/02 00:43:35 UTC    (20060602-1563)
+  Log:
+  - _iprint(): use stderr instead of stdout
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/s_log.c (File Modified) 
+
+
+jilles      2006/06/01 23:50:54 UTC    (20060601-1561)
+  Log:
+  - Open fd 0, 1, 2 to /dev/null so we don't get kqueue there
+    and subsequently destroy our kqueue when we close 0, 1, 2
+    (broke /restart).
+  - After closing fd 0, 1, 2 reopen them to /dev/null again
+    so we don't send messages from malloc etc to a random
+    user's connection.
+  - Remove an obsolete comment.
+  
+
+  Changes:     Modified:
+  +13 -2       trunk/src/ircd.c (File Modified) 
+
+
+jilles      2006/06/01 22:17:16 UTC    (20060601-1559)
+  Log:
+  Update NEWS file.
+  
+
+  Changes:     Modified:
+  +29 -1       trunk/NEWS (File Modified) 
+
+
+jilles      2006/06/01 20:18:31 UTC    (20060601-1551)
+  Log:
+  Rerun autoconf.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/configure (File Modified) 
+
+
+jilles      2006/06/01 20:17:21 UTC    (20060601-1549)
+  Log:
+  Fix openssl version check to also accept versions newer than 0.9.6.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/configure.ac (File Modified) 
+
+
+jilles      2006/06/01 18:18:28 UTC    (20060601-1543)
+  Log:
+  Oops, need packet.h here.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/modules/m_cmessage.c (File Modified) 
+
+
+jilles      2006/06/01 18:17:00 UTC    (20060601-1541)
+  Log:
+  End the flood grace period in CPRIVMSG/CNOTICE.
+  
+
+  Changes:     Modified:
+  +3 -0                trunk/modules/m_cmessage.c (File Modified) 
+
+
+nenolod     2006/06/01 17:51:07 UTC    (20060601-1539)
+  Log:
+  - update class::connectfreq documentation
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+nenolod     2006/06/01 17:41:10 UTC    (20060601-1537)
+  Log:
+  - get rid of the "minimum connection frequency delay" concept, as it is quite silly and does no good anyway
+  
+
+  Changes:     Modified:
+  +3 -6                trunk/src/s_serv.c (File Modified) 
+
+
+jilles      2006/06/01 15:27:18 UTC    (20060601-1535)
+  Log:
+  New RPL_YOUREOPER, from ircd.digi.pl3d.5.2.1.jp3 (1995-1996).
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/messages.tab (File Modified) 
+
+
+jilles      2006/06/01 13:06:23 UTC    (20060601-1533)
+  Log:
+  Don't mention that /stats p shows idle times, as it doesn't.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/help/opers/stats (File Modified) 
+  +1 -1                trunk/help/users/stats (File Modified) 
+
+
+jilles      2006/06/01 12:59:03 UTC    (20060601-1531)
+  Log:
+  /stats A shows DNS servers, it doesn't matter whether ircd
+  uses ADNS or something else.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/help/opers/stats (File Modified) 
+
+
+jilles      2006/05/30 21:34:57 UTC    (20060530-1529)
+  Log:
+  get_client_name() fix
+  
+
+  Changes:     Modified:
+  +4 -0                trunk/src/client.c (File Modified) 
+
+
+jilles      2006/05/28 13:58:14 UTC    (20060528-1527)
+  Log:
+  Add some comments.
+  
+
+  Changes:     Modified:
+  +6 -0                trunk/src/ircd.c (File Modified) 
+
+
+beu         2006/05/28 09:22:09 UTC    (20060528-1521)
+  Log:
+  Fix argument order for AC_SEARCH_LIBS (yeah, I fail...)
+
+  Changes:     Modified:
+  +16 -17      trunk/configure (File Modified) 
+  +1 -1                trunk/configure.ac (File Modified) 
+
+
+beu         2006/05/28 09:10:43 UTC    (20060528-1517)
+  Log:
+  Fix build for SunOS/Solaris [libnsl is required for inet_ntoa()].
+
+  Changes:     Modified:
+  +135 -0      trunk/configure (File Modified) 
+  +6 -0                trunk/configure.ac (File Modified) 
+
+
+jilles      2006/05/28 03:28:53 UTC    (20060528-1515)
+  Log:
+  Exit 0 on successful -conftest.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/ircd.c (File Modified) 
+
+
+jilles      2006/05/28 03:19:47 UTC    (20060528-1513)
+  Log:
+  Make the "keep the parent process around" thing work, by opening
+  a pipe to the child process. This pipe is on fd 0 in the child
+  process. After successful initialization, the child will write
+  a byte to this pipe, on fatal errors it will close it without
+  writing anything.
+  
+  Somewhat hackish still but should work.
+  
+
+  Changes:     Modified:
+  +27 -30      trunk/src/ircd.c (File Modified) 
+
+
+nenolod     2006/05/28 02:37:26 UTC    (20060528-1511)
+  Log:
+  - convert some error messages to ierror() over fprintf/ilog combination
+  
+
+  Changes:     Modified:
+  +3 -6                trunk/src/ircd.c (File Modified) 
+
+
+nenolod     2006/05/28 02:35:58 UTC    (20060528-1509)
+  Log:
+  - inotice() for loadmodule when in foreground mode
+  
+
+  Changes:     Modified:
+  +3 -0                trunk/src/modules.c (File Modified) 
+
+
+nenolod     2006/05/28 02:34:43 UTC    (20060528-1507)
+  Log:
+  - remove inotice() on loading modules from the config
+  
+
+  Changes:     Modified:
+  +0 -3                trunk/src/modules.c (File Modified) 
+
+
+nenolod     2006/05/28 00:11:14 UTC    (20060528-1505)
+  Log:
+  - usleep for 50000usec in the parent process to allow for startup messages
+    to be cleanly printed before detaching to shell, this should be more than 
+    enough time really
+  
+
+  Changes:     Modified:
+  +3 -0                trunk/src/ircd.c (File Modified) 
+
+
+nenolod     2006/05/28 00:07:11 UTC    (20060528-1503)
+  Log:
+  - display more errors during normal startup as to try to help people find common problems
+  
+
+  Changes:     Modified:
+  +27 -10      trunk/src/ircd.c (File Modified) 
+
+
+nenolod     2006/05/27 23:36:23 UTC    (20060527-1501)
+  Log:
+  - version bump in preparation of 2.0.0 release
+  
+
+  Changes:     Modified:
+  +9 -9                trunk/configure (File Modified) 
+  +1 -1                trunk/configure.ac (File Modified) 
+
+
+jilles      2006/05/27 20:39:47 UTC    (20060527-1495)
+  Log:
+  Change example.conf operator block from "admin" to "god",
+  so as to show we encourage per-person operator blocks.
+  
+
+  Changes:     Modified:
+  +4 -2                trunk/doc/example.conf (File Modified) 
+
+
+jilles      2006/05/27 20:33:58 UTC    (20060527-1493)
+  Log:
+  Document alias{} block.
+  
+
+  Changes:     Modified:
+  +28 -0       trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+jilles      2006/05/27 20:28:00 UTC    (20060527-1491)
+  Log:
+  Document DNS blacklist stuff in sgml.
+  
+
+  Changes:     Modified:
+  +6 -0                trunk/doc/sgml/oper-guide/commands.sgml (File Modified) 
+  +39 -1       trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+jilles      2006/05/27 20:13:30 UTC    (20060527-1489)
+  Log:
+  Misc /stats clarifications.
+  
+
+  Changes:     Modified:
+  +9 -4                trunk/doc/sgml/oper-guide/commands.sgml (File Modified) 
+
+
+jilles      2006/05/27 19:54:37 UTC    (20060527-1487)
+  Log:
+  Move snomasks into umodes chapter.
+  Move oprivs chapter down.
+  
+
+  Changes:     Modified:
+  +1 -160      trunk/doc/sgml/oper-guide/charybdis-oper-guide.sgml (File Modified) 
+  + -          trunk/doc/sgml/oper-guide/snomasks.sgml (File Deleted) 
+  +137 -0      trunk/doc/sgml/oper-guide/umodes.sgml (File Modified) 
+
+
+jilles      2006/05/27 19:09:19 UTC    (20060527-1485)
+  Log:
+  Mention operator{} user@host change.
+  
+
+  Changes:     Modified:
+  +9 -3                trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+jilles      2006/05/27 18:58:12 UTC    (20060527-1483)
+  Log:
+  operator{} block user@host matches against orighost now, not host.
+  This means that services/+h spoofs do not work in operator{} blocks;
+  auth{} spoofs still work.
+  
+
+  Changes:     Modified:
+  +4 -0                trunk/doc/example.conf (File Modified) 
+  +1 -1                trunk/doc/reference.conf (File Modified) 
+  +2 -2                trunk/modules/m_challenge.c (File Modified) 
+  +1 -1                trunk/modules/m_oper.c (File Modified) 
+
+
+nenolod     2006/05/27 17:24:05 UTC    (20060527-1481)
+  Log:
+  - inotice/iwarn/ierror() stuff I was working on
+  
+
+  Changes:     Modified:
+  +3 -0                trunk/include/s_log.h (File Modified) 
+  +15 -11      trunk/src/ircd.c (File Modified) 
+  +3 -1                trunk/src/modules.c (File Modified) 
+  +1 -1                trunk/src/newconf.c (File Modified) 
+  +54 -0       trunk/src/s_log.c (File Modified) 
+
+
+jilles      2006/05/26 22:54:29 UTC    (20060526-1473)
+  Log:
+  Oops, don't add blacklists to the list twice on rehash.
+  
+
+  Changes:     Modified:
+  +3 -2                trunk/src/blacklist.c (File Modified) 
+
+
+jilles      2006/05/26 22:27:21 UTC    (20060526-1471)
+  Log:
+  Remove notices to the client about progress of dnsbl lookups.
+  
+
+  Changes:     Modified:
+  +0 -4                trunk/src/blacklist.c (File Modified) 
+
+
+jilles      2006/05/26 22:18:23 UTC    (20060526-1469)
+  Log:
+  Add auth{} flag dnsbl_exempt.
+  
+
+  Changes:     Modified:
+  +2 -1                trunk/doc/example.conf (File Modified) 
+  +2 -1                trunk/doc/reference.conf (File Modified) 
+  +2 -0                trunk/include/s_conf.h (File Modified) 
+  +1 -0                trunk/src/newconf.c (File Modified) 
+  +8 -1                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/05/26 22:07:49 UTC    (20060526-1467)
+  Log:
+  Switch alias{} and blacklist{} around, for consistency with example.conf.
+  
+
+  Changes:     Modified:
+  +18 -18      trunk/doc/reference.conf (File Modified) 
+
+
+jilles      2006/05/26 21:58:29 UTC    (20060526-1465)
+  Log:
+  Send a warning to the user if they are dnsbl listed but exempted.
+  
+
+  Changes:     Modified:
+  +17 -12      trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/05/26 21:25:28 UTC    (20060526-1463)
+  Log:
+  Move throwing out dnsbl listed clients to registration,
+  and make kline_exempt exempt from it.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/include/blacklist.h (File Modified) 
+  +4 -0                trunk/include/client.h (File Modified) 
+  +15 -16      trunk/src/blacklist.c (File Modified) 
+  +6 -0                trunk/src/client.c (File Modified) 
+  +17 -0       trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/05/26 21:20:56 UTC    (20060526-1461)
+  Log:
+  Show refcount in /stats n.
+  
+
+  Changes:     Modified:
+  +3 -2                trunk/modules/m_stats.c (File Modified) 
+
+
+jilles      2006/05/26 20:50:41 UTC    (20060526-1459)
+  Log:
+  Don't look up dnsbls twice if they send USER twice.
+  
+
+  Changes:     Modified:
+  +5 -3                trunk/modules/m_user.c (File Modified) 
+
+
+jilles      2006/05/26 20:42:48 UTC    (20060526-1457)
+  Log:
+  Add /stats n to help files.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/help/opers/stats (File Modified) 
+  +1 -0                trunk/help/users/stats (File Modified) 
+
+
+jilles      2006/05/26 20:36:54 UTC    (20060526-1455)
+  Log:
+  Only check dnsbls for A records, not AAAA.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/blacklist.c (File Modified) 
+
+
+jilles      2006/05/26 20:09:55 UTC    (20060526-1453)
+  Log:
+  Don't remove non-illegal blacklists on completion of check.
+  Add debugging notices (not working).
+  
+
+  Changes:     Modified:
+  +5 -1                trunk/src/blacklist.c (File Modified) 
+
+
+jilles      2006/05/26 19:58:05 UTC    (20060526-1451)
+  Log:
+  Don't call register_local_user() if they haven't sent a nick yet.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/blacklist.c (File Modified) 
+
+
+jilles      2006/05/26 19:45:28 UTC    (20060526-1449)
+  Log:
+  Add /stats n, shows dnsbls with counts (counts reset on rehash).
+  
+
+  Changes:     Modified:
+  +21 -0       trunk/modules/m_stats.c (File Modified) 
+
+
+jilles      2006/05/26 18:57:36 UTC    (20060526-1447)
+  Log:
+  More dnsbl rehash fixes, it was adding bogus entries.
+  
+
+  Changes:     Modified:
+  +2 -7                trunk/src/newconf.c (File Modified) 
+
+
+jilles      2006/05/26 17:38:52 UTC    (20060526-1445)
+  Log:
+  Need blacklist.h here.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/src/s_conf.c (File Modified) 
+
+
+nenolod     2006/05/26 17:33:33 UTC    (20060526-1443)
+  Log:
+  - nuke iauth
+  
+
+  Changes:     Modified:
+  +1 -2                trunk/configure (File Modified) 
+  +0 -48       trunk/configure.ac (File Modified) 
+  + -          trunk/doc/example-iauth.conf (File Deleted) 
+  + -          trunk/iauth/ (File Deleted) 
+
+
+jilles      2006/05/26 17:20:01 UTC    (20060526-1441)
+  Log:
+  Improve handling of rehashing with blacklists.
+  Also some coding style tweaks.
+  
+
+  Changes:     Modified:
+  +3 -2                trunk/include/blacklist.h (File Modified) 
+  +35 -16      trunk/src/blacklist.c (File Modified) 
+  +2 -0                trunk/src/s_conf.c (File Modified) 
+
+
+jilles      2006/05/25 15:20:48 UTC    (20060525-1439)
+  Log:
+  Clear can_send cache if a user logs in or out from services.
+  
+
+  Changes:     Modified:
+  +2 -0                trunk/modules/m_services.c (File Modified) 
+
+
+jilles      2006/05/23 16:41:33 UTC    (20060523-1425)
+  Log:
+  Add unsupported/ directory and move m_force.c and m_clearchan.c into it.
+  This directory is not entered by default.
+  More stuff needs to be moved into here.
+  
+
+  Changes:     Modified:
+  +2 -1                trunk/configure (File Modified) 
+  +1 -0                trunk/configure.ac (File Modified) 
+  +69 -458     trunk/extensions/Makefile.in (File Modified) 
+  + -          trunk/extensions/m_clearchan.c (File Deleted) 
+  + -          trunk/extensions/m_force.c (File Deleted) 
+  + -          trunk/unsupported/ (File Added) 
+  + -          trunk/unsupported/Makefile.in (File Added) 
+  + -          trunk/unsupported/m_clearchan.c (File Added) 
+  + -          trunk/unsupported/m_force.c (File Added) 
+
+
+jilles      2006/05/23 16:32:11 UTC    (20060523-1423)
+  Log:
+  Logging/wallops for forcejoin/forcepart, numeric fix.
+  This needs to be moved to the toys section.
+  
+
+  Changes:     Modified:
+  +22 -2       trunk/extensions/m_force.c (File Modified) 
+
+
+jilles      2006/05/23 16:06:01 UTC    (20060523-1421)
+  Log:
+  Fix comments at the top (including copyright).
+  
+
+  Changes:     Modified:
+  +3 -2                trunk/extensions/m_omode.c (File Modified) 
+
+
+jilles      2006/05/23 16:01:22 UTC    (20060523-1419)
+  Log:
+  Add OMODE command to extensions/ for oper mode hacking:
+  - requires admin privs
+  - does not work for opped opers
+  - sends wallops
+  - sends a ServerMode for opping the oper themselves,
+    otherwise a mode coming from the oper (not only
+    does this provide full accountability, it is also
+    easiest to implement while avoiding channels
+    messed up with bogus bans etc).
+  
+
+  Changes:     Modified:
+  +171 -0      trunk/extensions/Makefile.in (File Modified) 
+  + -          trunk/extensions/m_omode.c (File Added) 
+
+
+gxti        2006/05/22 23:02:06 UTC    (20060522-1417)
+  Log:
+  Metadata fix
+  
+
+  Changes:     Modified:
+  + -          trunk/include/blacklist.h  (Property Modified)
+  + -          trunk/src/blacklist.c  (Property Modified)
+
+
+nenolod     2006/05/22 19:25:09 UTC    (20060522-1415)
+  Log:
+  - avoid loosing the username forever when calling register_local_user after the blacklist checking lock has been released
+  
+
+  Changes:     Modified:
+  +5 -1                trunk/src/blacklist.c (File Modified) 
+
+
+nenolod     2006/05/22 17:13:15 UTC    (20060522-1413)
+  Log:
+  Initial DNS blacklist support:
+  - see example.conf for how to use.
+  - because opm.blitzed.org is currently offline, we recommend ircbl.ahbl.org as a replacement
+  - tor.ahbl.org is also included because most networks will not want to allow tor
+    (and we're considering going KoS on tor users here anyway due to abuse)
+  
+
+  Changes:     Modified:
+  +18 -0       trunk/doc/example.conf (File Modified) 
+  +66 -0       trunk/doc/reference.conf (File Modified) 
+  + -          trunk/include/blacklist.h (File Added) 
+  +2 -0                trunk/include/client.h (File Modified) 
+  +3 -0                trunk/modules/m_user.c (File Modified) 
+  +152 -0      trunk/src/Makefile.in (File Modified) 
+  + -          trunk/src/blacklist.c (File Added) 
+  +34 -0       trunk/src/newconf.c (File Modified) 
+  +1 -0                trunk/src/s_auth.c (File Modified) 
+  +4 -0                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/05/21 17:38:31 UTC    (20060521-1411)
+  Log:
+  Remove last bit of lzo stuff (comment in example.conf connect{}).
+  
+
+  Changes:     Modified:
+  +0 -4                trunk/doc/example.conf (File Modified) 
+
+
+jilles      2006/05/21 14:46:17 UTC    (20060521-1409)
+  Log:
+  Show sasl successes and failures in /stats t (like other
+  things in /stats t, about local clients only).
+  
+
+  Changes:     Modified:
+  +2 -0                trunk/include/s_stats.h (File Modified) 
+  +3 -0                trunk/modules/m_sasl.c (File Modified) 
+  +3 -0                trunk/src/s_stats.c (File Modified) 
+
+
+jilles      2006/05/20 20:13:56 UTC    (20060520-1405)
+  Log:
+  Allow messaging services by nickname without using
+  target change slots (this was already possible with
+  user@server notation or services shortcuts).
+  
+
+  Changes:     Modified:
+  +2 -2                trunk/modules/core/m_message.c (File Modified) 
+
+
+jilles      2006/05/20 19:28:16 UTC    (20060520-1393)
+  Log:
+  Abort a safelist if a new /list comes in while one is already in progress.
+  
+
+  Changes:     Modified:
+  +16 -0       trunk/modules/m_list_safelist.c (File Modified) 
+
+
+jilles      2006/05/20 19:24:11 UTC    (20060520-1391)
+  Log:
+  Change $![letter]:[mask] to $~[letter]:[mask]
+  so both ! and ~ invert an extban.
+  
+
+  Changes:     Modified:
+  +2 -0                trunk/src/chmode.c (File Modified) 
+
+
+nenolod     2006/05/20 19:19:00 UTC    (20060520-1389)
+  Log:
+  - revert due to technical issues
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/extban.c (File Modified) 
+
+
+nenolod     2006/05/20 19:17:42 UTC    (20060520-1387)
+  Log:
+  - allow $![letter]:[mask] to also invert an extban, like $~[letter]:[mask], since some people will likely believe that is the correct way of doing it
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/extban.c (File Modified) 
+
+
+jilles      2006/05/20 18:32:45 UTC    (20060520-1385)
+  Log:
+  Don't pace /list on a single channel.
+  
+
+  Changes:     Modified:
+  +10 -7       trunk/modules/m_list_safelist.c (File Modified) 
+
+
+jilles      2006/05/20 18:15:46 UTC    (20060520-1383)
+  Log:
+  Add EXTBAN=$:<letters> to 005 if any extban modules are loaded.
+  
+
+  Changes:     Modified:
+  +4 -2                trunk/include/supported.h (File Modified) 
+
+
+jilles      2006/05/20 17:21:19 UTC    (20060520-1381)
+  Log:
+  Extban types are case insensitive; force them to lowercase when added.
+  
+
+  Changes:     Modified:
+  +5 -5                trunk/doc/extban.txt (File Modified) 
+  +4 -0                trunk/src/chmode.c (File Modified) 
+  +3 -3                trunk/src/extban.c (File Modified) 
+
+
+jilles      2006/05/20 14:11:07 UTC    (20060520-1379)
+  Log:
+  sendto_wallops_flags():
+  - instead of checking IsOper on each client, walk the appropriate list
+  - instead of sending non-+z wallops from persons to nonopers, send only
+    +w wallops from persons
+  
+
+  Changes:     Modified:
+  +1 -5                trunk/src/send.c (File Modified) 
+
+
+jilles      2006/05/20 13:48:37 UTC    (20060520-1377)
+  Log:
+  Prefix oper wallops with "WALLOPS - " if they would
+  otherwise look like operwalls or locops, when sending
+  them to local users.
+  
+
+  Changes:     Modified:
+  +11 -1       trunk/modules/m_wallops.c (File Modified) 
+
+
+jilles      2006/05/20 13:47:22 UTC    (20060520-1375)
+  Log:
+  Make sure destination field in some sasl numerics
+  is the user's nick, not the sasl agent or server
+  name.
+  
+
+  Changes:     Modified:
+  +2 -2                trunk/modules/m_sasl.c (File Modified) 
+
+
+beu         2006/05/19 19:24:44 UTC    (20060519-1373)
+  Log:
+  Add `-I.' to INCLUDES (hurt module has it's own header file...)
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/extensions/Makefile.in (File Modified) 
+
+
+jilles      2006/05/19 18:10:55 UTC    (20060519-1369)
+  Log:
+  Invalidate can_send cache on CHGHOST/SIGNON (change_nick_user_host()).
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/src/s_user.c (File Modified) 
+
+
+beu         2006/05/19 18:10:13 UTC    (20060519-1367)
+  Log:
+  Fix build for when IPv6 is disabled.
+  
+
+  Changes:     Modified:
+  +12 -10      trunk/src/s_auth.c (File Modified) 
+
+
+jilles      2006/05/18 18:38:04 UTC    (20060518-1365)
+  Log:
+  Add information about adding extban types.
+  
+
+  Changes:     Modified:
+  +25 -0       trunk/doc/extban.txt (File Modified) 
+
+
+jilles      2006/05/18 17:59:35 UTC    (20060518-1363)
+  Log:
+  Better extban validation: try to match a new extban from
+  a local user against its setter to see if it is valid.
+  Unknown extban types from remotes are no longer hidden.
+  
+
+  Changes:     Modified:
+  +4 -3                trunk/doc/extban.txt (File Modified) 
+  +1 -0                trunk/include/channel.h (File Modified) 
+  +2 -6                trunk/src/chmode.c (File Modified) 
+  +32 -0       trunk/src/extban.c (File Modified) 
+
+
+jilles      2006/05/17 20:55:55 UTC    (20060517-1359)
+  Log:
+  Make sure both .c.o: and .s.o: are followed by the necessary command.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/src/Makefile.in (File Modified) 
+
+
+jilles      2006/05/17 18:07:20 UTC    (20060517-1357)
+  Log:
+  Add need_sasl auth{} flag to sgml documentation.
+  
+
+  Changes:     Modified:
+  +7 -1                trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+jilles      2006/05/17 17:50:10 UTC    (20060517-1353)
+  Log:
+  Document need_sasl auth{} flag in example confs.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/doc/example.conf (File Modified) 
+  +1 -0                trunk/doc/reference.conf (File Modified) 
+
+
+jilles      2006/05/17 17:37:46 UTC    (20060517-1349)
+  Log:
+  Don't allow TB to set an empty topic.
+  This would be possible if a server sent bad protocol
+  and could cause a crash.
+  
+
+  Changes:     Modified:
+  +4 -0                trunk/modules/m_tb.c (File Modified) 
+
+
+nenolod     2006/05/17 14:49:13 UTC    (20060517-1347)
+  Log:
+  - oops
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/Makefile.in (File Modified) 
+
+
+nenolod     2006/05/17 14:46:58 UTC    (20060517-1345)
+  Log:
+  - typo fix
+  
+
+  Changes:     Modified:
+  +2 -2                trunk/configure (File Modified) 
+  +1 -1                trunk/configure.ac (File Modified) 
+
+
+nenolod     2006/05/17 14:45:52 UTC    (20060517-1343)
+  Log:
+  - rebuild configure
+  
+
+  Changes:     Modified:
+  +2 -2                trunk/configure (File Modified) 
+
+
+nenolod     2006/05/17 00:52:51 UTC    (20060517-1341)
+  Log:
+  - makefile fix
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/extensions/Makefile.in (File Modified) 
+
+
+nenolod     2006/05/17 00:45:40 UTC    (20060517-1339)
+  Log:
+  - rename contrib to extensions to bring some clarity to things
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/Makefile.in (File Modified) 
+  +1 -1                trunk/configure.ac (File Modified) 
+  +10 -10      trunk/doc/example.conf (File Modified) 
+  +10 -10      trunk/doc/reference.conf (File Modified) 
+  + -          trunk/extensions/ (File Added) 
+  + -          trunk/extras/ (File Deleted) 
+
+
+nenolod     2006/05/17 00:43:32 UTC    (20060517-1337)
+  Log:
+  - temporary rename
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/Makefile.in (File Modified) 
+  +1 -1                trunk/configure.ac (File Modified) 
+  + -          trunk/contrib/ (File Deleted) 
+  + -          trunk/extras/ (File Added) 
+
+
+jilles      2006/05/14 13:47:33 UTC    (20060514-1333)
+  Log:
+  Don't allow servers to QUIT (they should use SQUIT).
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/modules/core/m_quit.c (File Modified) 
+
+
+nenolod     2006/05/14 02:09:30 UTC    (20060514-1329)
+  Log:
+  - keywords
+  
+
+  Changes:     Modified:
+  + -          trunk/src/fnvhash.s  (Property Modified)
+
+
+nenolod     2006/05/14 01:47:33 UTC    (20060514-1327)
+  Log:
+  - reduced version of code
+  
+
+  Changes:     Modified:
+  +9 -61       trunk/src/fnvhash.s (File Modified) 
+
+
+nenolod     2006/05/14 01:20:24 UTC    (20060514-1325)
+  Log:
+  - ok, this only works on x86, because amd64 wants pushq/%rbp for stack manipulation
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/fnvhash.s (File Modified) 
+
+
+jilles      2006/05/14 01:19:25 UTC    (20060514-1323)
+  Log:
+  Fix orighost matching for klines, etc. Was hashing the visible
+  host, oops.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/hostmask.c (File Modified) 
+
+
+nenolod     2006/05/13 23:49:14 UTC    (20060513-1321)
+  Log:
+  - integrate fnvhash.s into buildsystem (--enable-ricer-hashing).
+  
+
+  Changes:     Modified:
+  +7 -1                trunk/configure (File Modified) 
+  +5 -0                trunk/configure.ac (File Modified) 
+  +5 -6                trunk/src/Makefile.in (File Modified) 
+  +0 -4                trunk/src/fnvhash.s (File Modified) 
+  +0 -2                trunk/src/hash.c (File Modified) 
+
+
+nenolod     2006/05/13 23:35:31 UTC    (20060513-1319)
+  Log:
+  - regenerate configure
+  
+
+  Changes:     Modified:
+  +18 -0       trunk/configure (File Modified) 
+
+
+nenolod     2006/05/13 23:35:15 UTC    (20060513-1317)
+  Log:
+  - --enable-ricer-hashing option.
+  
+
+  Changes:     Modified:
+  +9 -0                trunk/configure.ac (File Modified) 
+  +3 -0                trunk/include/setup.h.in (File Modified) 
+
+
+nenolod     2006/05/13 23:22:47 UTC    (20060513-1315)
+  Log:
+  - Add assembly versions of the hashing code. They live in src/fnvhash.s, and require an x86 or x64 CPU.
+  
+
+  Changes:     Modified:
+  + -          trunk/src/fnvhash.s (File Added) 
+  +3 -0                trunk/src/hash.c (File Modified) 
+
+
+jilles      2006/05/12 15:57:25 UTC    (20060512-1309)
+  Log:
+  Fix syntax error in reference.conf.
+  
+
+  Changes:     Modified:
+  +0 -1                trunk/doc/reference.conf (File Modified) 
+
+
+jilles      2006/05/11 16:28:16 UTC    (20060511-1307)
+  Log:
+  Expand blah.blah and blah:blah to *!*@... instead of ...!*@* for bans
+  (&& instead of ||...)
+  Allows stuff like /mode +b 127.0.0.1 to ban that IP.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/chmode.c (File Modified) 
+
+
+jilles      2006/05/11 16:16:36 UTC    (20060511-1303)
+  Log:
+  Documentation for extban.
+  
+
+  Changes:     Modified:
+  + -          trunk/doc/extban.txt (File Added) 
+
+
+jilles      2006/05/11 15:50:33 UTC    (20060511-1301)
+  Log:
+  Add extban modules to example confs.
+  
+
+  Changes:     Modified:
+  +5 -0                trunk/doc/example.conf (File Modified) 
+  +10 -0       trunk/doc/reference.conf (File Modified) 
+
+
+jilles      2006/05/11 15:43:03 UTC    (20060511-1299)
+  Log:
+  Initial addition of extended ban types (conditionals).
+  Allows custom +bqeI checks via modules.
+  Initial extra types are account (a[:mask]), oper (o),
+  channel (c:name), realname (r:mask), server (s:mask).
+  
+
+  Changes:     Modified:
+  +229 -0      trunk/contrib/Makefile.in (File Modified) 
+  + -          trunk/contrib/extb_account.c (File Added) 
+  + -          trunk/contrib/extb_channel.c (File Added) 
+  + -          trunk/contrib/extb_oper.c (File Added) 
+  + -          trunk/contrib/extb_realname.c (File Added) 
+  + -          trunk/contrib/extb_server.c (File Added) 
+  +13 -0       trunk/include/channel.h (File Modified) 
+  +1 -0                trunk/src/Makefile.in (File Modified) 
+  +14 -5       trunk/src/channel.c (File Modified) 
+  +91 -0       trunk/src/chmode.c (File Modified) 
+  + -          trunk/src/extban.c (File Added) 
+
+
+jilles      2006/05/09 19:28:19 UTC    (20060509-1297)
+  Log:
+  Do not force +bqeI modes starting with '$' in nick!user@host format.
+  * and ? characters in them are still assumed to be wildcards.
+  
+
+  Changes:     Modified:
+  +6 -0                trunk/src/chmode.c (File Modified) 
+
+
+nenolod     2006/05/08 13:05:25 UTC    (20060508-1295)
+  Log:
+  - memory leak fix, reported by Lee Hardy <lee@leeh.co.uk>
+  
+
+  Changes:     Modified:
+  +4 -0                trunk/modules/m_capab.c (File Modified) 
+
+
+jilles      2006/05/05 19:00:19 UTC    (20060505-1291)
+  Log:
+  Stop some mixing of client and server protocol.
+  
+
+  Changes:     Modified:
+  +6 -0                trunk/modules/core/m_nick.c (File Modified) 
+  +4 -2                trunk/modules/m_pass.c (File Modified) 
+  +6 -0                trunk/modules/m_sasl.c (File Modified) 
+  +6 -0                trunk/modules/m_user.c (File Modified) 
+
+
+nenolod     2006/05/05 15:06:00 UTC    (20060505-1287)
+  Log:
+  - additional revert
+  
+
+  Changes:     Modified:
+  +0 -2                trunk/include/s_newconf.h (File Modified) 
+  +0 -4                trunk/include/s_serv.h (File Modified) 
+  +0 -1                trunk/src/newconf.c (File Modified) 
+  +1 -13       trunk/src/s_serv.c (File Modified) 
+
+
+nenolod     2006/05/05 15:03:53 UTC    (20060505-1285)
+  Log:
+  - revert LZOLink patch for now
+  
+
+  Changes:     Modified:
+  +0 -1                trunk/servlink/Makefile.in (File Modified) 
+  +0 -16       trunk/servlink/README (File Modified) 
+  +2 -36       trunk/servlink/control.c (File Modified) 
+  +0 -3                trunk/servlink/control.h (File Modified) 
+  +7 -5955     trunk/servlink/io.c (File Modified) 
+  + -          trunk/servlink/lzoconf.h (File Deleted) 
+  + -          trunk/servlink/lzodefs.h (File Deleted) 
+  + -          trunk/servlink/minilzo.c (File Deleted) 
+  + -          trunk/servlink/minilzo.h (File Deleted) 
+  +0 -1                trunk/servlink/servlink.h (File Modified) 
+
+
+nenolod     2006/05/05 13:37:26 UTC    (20060505-1283)
+  Log:
+  - more stuff here
+  
+
+  Changes:     Modified:
+  +4 -2                trunk/servlink/control.c (File Modified) 
+  +2 -1                trunk/servlink/io.c (File Modified) 
+
+
+nenolod     2006/05/05 04:21:59 UTC    (20060505-1281)
+  Log:
+  - oops
+  
+
+  Changes:     Modified:
+  +2 -2                trunk/servlink/io.c (File Modified) 
+
+
+nenolod     2006/05/05 04:15:09 UTC    (20060505-1279)
+  Log:
+  - paranoia, prevent segfaults
+  
+
+  Changes:     Modified:
+  +2 -2                trunk/servlink/io.c (File Modified) 
+
+
+nenolod     2006/05/05 03:49:15 UTC    (20060505-1277)
+  Log:
+  - more optimal servlink code
+  
+
+  Changes:     Modified:
+  +21 -8       trunk/servlink/io.c (File Modified) 
+
+
+nenolod     2006/05/05 03:33:12 UTC    (20060505-1275)
+  Log:
+  - more efficient read strategy
+  
+
+  Changes:     Modified:
+  +15 -3       trunk/servlink/io.c (File Modified) 
+
+
+nenolod     2006/05/05 03:23:07 UTC    (20060505-1273)
+  Log:
+  - use lzo_uintp cast to make LZO happy
+  
+
+  Changes:     Modified:
+  +3 -3                trunk/servlink/io.c (File Modified) 
+
+
+nenolod     2006/05/05 03:09:46 UTC    (20060505-1271)
+  Log:
+  - lzolink patch. not highly tested yet, will need extensive testing before 2.0 release
+  
+
+  Changes:     Modified:
+  +4 -0                trunk/doc/example.conf (File Modified) 
+  +2 -1                trunk/include/s_newconf.h (File Modified) 
+  +4 -0                trunk/include/s_serv.h (File Modified) 
+  +1 -0                trunk/servlink/Makefile.in (File Modified) 
+  +16 -0       trunk/servlink/README (File Modified) 
+  +34 -2       trunk/servlink/control.c (File Modified) 
+  +3 -0                trunk/servlink/control.h (File Modified) 
+  +5929 -7     trunk/servlink/io.c (File Modified) 
+  + -          trunk/servlink/lzoconf.h (File Added) 
+  + -          trunk/servlink/lzodefs.h (File Added) 
+  + -          trunk/servlink/minilzo.c (File Added) 
+  + -          trunk/servlink/minilzo.h (File Added) 
+  +1 -0                trunk/servlink/servlink.h (File Modified) 
+  +1 -0                trunk/src/newconf.c (File Modified) 
+  +14 -2       trunk/src/s_serv.c (File Modified) 
+
+
+nenolod     2006/04/30 16:51:11 UTC    (20060430-1269)
+  Log:
+  - remove imalloc, it was a concept that probably wouldn't have worked properly
+  
+
+  Changes:     Modified:
+  +0 -977      trunk/libcharybdis/Makefile.in (File Modified) 
+  + -          trunk/libcharybdis/imalloc.c (File Deleted) 
+  + -          trunk/libcharybdis/imalloc.h (File Deleted) 
+
+
+nenolod     2006/04/29 03:04:39 UTC    (20060429-1267)
+  Log:
+  - disable imalloc for now
+  
+
+  Changes:     Modified:
+  +33 -7       trunk/libcharybdis/imalloc.c (File Modified) 
+
+
+nenolod     2006/04/29 02:47:22 UTC    (20060429-1265)
+  Log:
+  - remove unneeded debug code
+  
+
+  Changes:     Modified:
+  +0 -6                trunk/libcharybdis/imalloc.c (File Modified) 
+
+
+nenolod     2006/04/29 02:46:00 UTC    (20060429-1263)
+  Log:
+  - minimum allocation size is 32 bytes, not 16 due to dlink_list overhead
+  
+
+  Changes:     Modified:
+  +6 -4                trunk/libcharybdis/imalloc.c (File Modified) 
+
+
+nenolod     2006/04/29 02:40:23 UTC    (20060429-1261)
+  Log:
+  - more stuff here, imalloc remains disabled for now
+  
+
+  Changes:     Modified:
+  +2 -3                trunk/libcharybdis/imalloc.c (File Modified) 
+
+
+nenolod     2006/04/29 02:27:03 UTC    (20060429-1259)
+  Log:
+  - more progress
+  
+
+  Changes:     Modified:
+  +13 -4       trunk/libcharybdis/imalloc.c (File Modified) 
+
+
+nenolod     2006/04/29 02:21:48 UTC    (20060429-1257)
+  Log:
+  - more tweaks
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/libcharybdis/imalloc.c (File Modified) 
+  +2 -0                trunk/src/ircd.c (File Modified) 
+
+
+nenolod     2006/04/29 02:13:05 UTC    (20060429-1255)
+  Log:
+  - roll back libircd crap
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/libcharybdis/Makefile.in (File Modified) 
+  +4 -0                trunk/libcharybdis/imalloc.c (File Modified) 
+  +29 -0       trunk/src/.depend (File Modified) 
+  +6 -21       trunk/src/Makefile.in (File Modified) 
+  +3 -218      trunk/src/ircd.c (File Modified) 
+  + -          trunk/src/ircd_linker.c (File Deleted) 
+  + -          trunk/src/main.c (File Deleted) 
+
+
+nenolod     2006/04/29 01:57:30 UTC    (20060429-1253)
+  Log:
+  - realloc(), free() implementation
+  
+
+  Changes:     Modified:
+  +141 -0      trunk/libcharybdis/imalloc.c (File Modified) 
+
+
+nenolod     2006/04/29 01:12:55 UTC    (20060429-1251)
+  Log:
+  - malloc(), calloc() implementation
+  
+
+  Changes:     Modified:
+  +78 -3       trunk/libcharybdis/imalloc.c (File Modified) 
+
+
+nenolod     2006/04/29 00:41:14 UTC    (20060429-1249)
+  Log:
+  - block_free(), block_find(), retune_heaps() implementation
+  
+
+  Changes:     Modified:
+  +146 -1      trunk/libcharybdis/imalloc.c (File Modified) 
+
+
+nenolod     2006/04/28 21:43:10 UTC    (20060428-1246)
+  Log:
+  - block_destroy code, block_allocate code.
+  
+
+  Changes:     Modified:
+  +81 -4       trunk/libcharybdis/imalloc.c (File Modified) 
+
+
+nenolod     2006/04/28 21:04:19 UTC    (20060428-1244)
+  Log:
+  - block_new() code
+  
+
+  Changes:     Modified:
+  +57 -0       trunk/libcharybdis/imalloc.c (File Modified) 
+
+
+nenolod     2006/04/28 20:34:53 UTC    (20060428-1242)
+  Log:
+  - disable imalloc again :P
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/libcharybdis/imalloc.c (File Modified) 
+
+
+nenolod     2006/04/28 20:34:31 UTC    (20060428-1240)
+  Log:
+  - fix warning
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/libcharybdis/imalloc.c (File Modified) 
+
+
+nenolod     2006/04/28 20:34:03 UTC    (20060428-1238)
+  Log:
+  - fix typo
+  
+
+  Changes:     Modified:
+  +2 -2                trunk/libcharybdis/imalloc.c (File Modified) 
+
+
+nenolod     2006/04/28 20:32:20 UTC    (20060428-1236)
+  Log:
+  - constructor code for imalloc engine (malloc_init())
+  
+
+  Changes:     Modified:
+  +35 -2       trunk/libcharybdis/imalloc.c (File Modified) 
+
+
+nenolod     2006/04/28 20:22:37 UTC    (20060428-1234)
+  Log:
+  - imalloc engine improvements
+  
+
+  Changes:     Modified:
+  +60 -6       trunk/libcharybdis/imalloc.c (File Modified) 
+
+
+nenolod     2006/04/28 19:51:10 UTC    (20060428-1232)
+  Log:
+  - replace mmap() code with direct brk()/sbrk() calls.
+  
+
+  Changes:     Modified:
+  +32 -10      trunk/libcharybdis/imalloc.c (File Modified) 
+
+
+nenolod     2006/04/28 19:26:44 UTC    (20060428-1230)
+  Log:
+  - remove outdated i_malloc() interfaces
+  
+
+  Changes:     Modified:
+  +1 -44       trunk/libcharybdis/imalloc.c (File Modified) 
+
+
+nenolod     2006/04/28 15:04:38 UTC    (20060428-1228)
+  Log:
+  - redisable imalloc (sorry!)
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/libcharybdis/imalloc.c (File Modified) 
+
+
+nenolod     2006/04/28 15:03:12 UTC    (20060428-1226)
+  Log:
+  - correct GET_PAGE_SLOT() macro
+  
+
+  Changes:     Modified:
+  +2 -2                trunk/libcharybdis/imalloc.c (File Modified) 
+
+
+nenolod     2006/04/28 15:01:53 UTC    (20060428-1224)
+  Log:
+  - oops forgot to commit it with imalloc turned off
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/libcharybdis/imalloc.c (File Modified) 
+
+
+nenolod     2006/04/28 15:01:29 UTC    (20060428-1222)
+  Log:
+  - cleanups
+  
+
+  Changes:     Modified:
+  +11 -11      trunk/libcharybdis/imalloc.c (File Modified) 
+  +8 -2                trunk/libcharybdis/imalloc.h (File Modified) 
+
+
+nenolod     2006/04/28 14:56:20 UTC    (20060428-1220)
+  Log:
+  - lowlevel imalloc code
+  
+
+  Changes:     Modified:
+  +278 -16     trunk/libcharybdis/imalloc.c (File Modified) 
+  + -          trunk/libcharybdis/imalloc.h (File Added) 
+
+
+nenolod     2006/04/26 14:53:05 UTC    (20060426-1218)
+  Log:
+  - fix bindings
+  
+
+  Changes:     Modified:
+  +3 -3                trunk/libcharybdis/imalloc.c (File Modified) 
+
+
+nenolod     2006/04/26 14:51:53 UTC    (20060426-1216)
+  Log:
+  remove #ifndef
+  
+
+  Changes:     Modified:
+  +0 -1                trunk/libcharybdis/imalloc.c (File Modified) 
+
+
+nenolod     2006/04/26 14:50:01 UTC    (20060426-1214)
+  Log:
+  - add imalloc engine, however the actual engine itself has not been written yet (just the bindings for if the imalloc option is unavailable, which are forcefully used at present)
+  
+
+  Changes:     Modified:
+  +115 -0      trunk/libcharybdis/Makefile.in (File Modified) 
+  + -          trunk/libcharybdis/imalloc.c (File Added) 
+
+
+nenolod     2006/04/26 14:37:24 UTC    (20060426-1212)
+  Log:
+  - increment configure Id
+  
+
+  Changes:     Modified:
+  +2208 -1     trunk/configure (File Modified) 
+
+
+nenolod     2006/04/26 14:33:37 UTC    (20060426-1210)
+  Log:
+  - bootstrap for imalloc code
+  
+
+  Changes:     Modified:
+  +54 -1       trunk/configure.ac (File Modified) 
+  +27 -0       trunk/include/setup.h.in (File Modified) 
+
+
+jilles      2006/04/25 14:52:37 UTC    (20060425-1208)
+  Log:
+  Clarify interaction of spoofs and channel bans/operator{} blocks.
+  
+
+  Changes:     Modified:
+  +4 -1                trunk/doc/sgml/oper-guide/cmodes.sgml (File Modified) 
+  +6 -1                trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+nenolod     2006/04/24 13:42:18 UTC    (20060424-1206)
+  Log:
+  - move rehash checking &c into a timed event (idea stolen from ratbox3)
+  
+
+  Changes:     Modified:
+  +30 -22      trunk/src/ircd.c (File Modified) 
+
+
+jilles      2006/04/22 17:07:07 UTC    (20060422-1204)
+  Log:
+  If shared{} blocks deny something, the command
+  is silently ignored.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+jilles      2006/04/22 10:26:56 UTC    (20060422-1202)
+  Log:
+  Move up IsService check so we don't store a non-service
+  in preClient->sasl_agent.
+  
+
+  Changes:     Modified:
+  +6 -6                trunk/modules/m_sasl.c (File Modified) 
+
+
+gxti        2006/04/22 03:53:40 UTC    (20060422-1198)
+  Log:
+  SASL ENCAP messages originate from the server, not the agent. Check the correct cptr for service status.
+  Add some more sanity checks on agent strings.
+  
+
+  Changes:     Modified:
+  +13 -11      trunk/modules/m_sasl.c (File Modified) 
+
+
+jilles      2006/04/21 16:28:56 UTC    (20060421-1194)
+  Log:
+  Unknown clients can have an ID too now so make sure to remove
+  them from the hash if they exit.
+  
+
+  Changes:     Modified:
+  +3 -0                trunk/src/client.c (File Modified) 
+
+
+jilles      2006/04/21 16:21:02 UTC    (20060421-1192)
+  Log:
+  Only accept sasl from servers in a service{} block.
+  Not tested but this must go in.
+  
+
+  Changes:     Modified:
+  +6 -0                trunk/modules/m_sasl.c (File Modified) 
+  +3 -0                trunk/modules/m_signon.c (File Modified) 
+
+
+jilles      2006/04/19 15:52:08 UTC    (20060419-1190)
+  Log:
+  Only process SAVE messages targetting registered users,
+  not servers or unregistered connections. Could cause
+  a crash when bad protocol was received.
+  
+
+  Changes:     Modified:
+  +5 -1                trunk/modules/core/m_nick.c (File Modified) 
+
+
+nenolod     2006/04/19 03:44:55 UTC    (20060419-1186)
+  Log:
+  - fix QJM buffer overflow vulnerability (fucking GXTi)
+  
+
+  Changes:     Modified:
+  +3 -3                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/04/18 23:28:33 UTC    (20060418-1184)
+  Log:
+  Mention /scan umodes under oper_spy privilege.
+  
+
+  Changes:     Modified:
+  +3 -2                trunk/doc/sgml/oper-guide/oprivs.sgml (File Modified) 
+
+
+jilles      2006/04/18 23:05:05 UTC    (20060418-1182)
+  Log:
+  Mention that overlapping cluster blocks are a bad thing.
+  
+
+  Changes:     Modified:
+  +5 -0                trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+jilles      2006/04/18 22:57:47 UTC    (20060418-1180)
+  Log:
+  - Document cluster{} and shared{} blocks.
+  - Mention that service{} does not allow wildcards.
+  
+
+  Changes:     Modified:
+  +222 -1      trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+jilles      2006/04/18 22:22:36 UTC    (20060418-1178)
+  Log:
+  Document exempt{} and service{} blocks, point to reference.conf for
+  general{}, channel{} and serverhide{}.
+  
+
+  Changes:     Modified:
+  +88 -1       trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+jilles      2006/04/18 22:02:17 UTC    (20060418-1176)
+  Log:
+  Document ~ in lists of values better.
+  
+
+  Changes:     Modified:
+  +7 -0                trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+jilles      2006/04/18 21:51:18 UTC    (20060418-1174)
+  Log:
+  More detailed CNOTICE, CPRIVMSG descriptions.
+  
+
+  Changes:     Modified:
+  +9 -0                trunk/doc/sgml/oper-guide/ucommands.sgml (File Modified) 
+
+
+jilles      2006/04/18 13:49:18 UTC    (20060418-1172)
+  Log:
+  Oops, need both Revision and Id on modules.
+  
+
+  Changes:     Modified:
+  + -          trunk/modules/sno_routing.c  (Property Modified)
+
+
+jilles      2006/04/17 22:26:12 UTC    (20060417-1170)
+  Log:
+  Tweak header comment a bit (filename, Id).
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/modules/sno_routing.c (File Modified) (Property Modified)
+
+
+jilles      2006/04/17 00:13:57 UTC    (20060417-1166)
+  Log:
+  Add GLINE and UNGLINE.
+  
+
+  Changes:     Modified:
+  +40 -0       trunk/doc/sgml/oper-guide/commands.sgml (File Modified) 
+
+
+jilles      2006/04/16 13:07:49 UTC    (20060416-1156)
+  Log:
+  New configure with proper Id.
+  
+
+  Changes:     Modified:
+  +3 -1                trunk/configure (File Modified) 
+
+
+jilles      2006/04/16 13:06:04 UTC    (20060416-1154)
+  Log:
+  Change #include directives for in6addr_any, hopefully compiles better now.
+  
+
+  Changes:     Modified:
+  +3 -1                trunk/configure.ac (File Modified) 
+
+
+jilles      2006/04/09 20:20:32 UTC    (20060409-1152)
+  Log:
+  Encourage putting actual administrative information
+  in the admin{} block.
+  
+
+  Changes:     Modified:
+  +3 -3                trunk/doc/example.conf (File Modified) 
+
+
+gxti        2006/04/08 01:36:41 UTC    (20060408-1150)
+  Log:
+  New auth{} flag need_sasl to reject connecting users who have not authenticated by the time they register.
+  
+
+  Changes:     Modified:
+  +9 -7                trunk/include/s_conf.h (File Modified) 
+  +1 -0                trunk/src/newconf.c (File Modified) 
+  +10 -0       trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/04/07 22:52:35 UTC    (20060407-1146)
+  Log:
+  - Change to glines = no in example confs
+  - Point to clustered/remote KLINE/UNKLINE in notices if glines
+    are disabled.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/doc/example.conf (File Modified) 
+  +1 -1                trunk/doc/reference.conf (File Modified) 
+  +2 -2                trunk/modules/m_gline.c (File Modified) 
+
+
+nenolod     2006/04/06 13:35:20 UTC    (20060406-1144)
+  Log:
+  - forward-port QJM fix from 1.1
+  
+
+  Changes:     Modified:
+  +2 -0                trunk/src/s_user.c (File Modified) 
+
+
+nenolod     2006/04/06 13:33:39 UTC    (20060406-1142)
+  Log:
+  - add switch to configure to disable the block allocator
+  
+
+  Changes:     Modified:
+  +18 -0       trunk/configure (File Modified) 
+  +9 -0                trunk/configure.ac (File Modified) 
+  +0 -6                trunk/include/config.h (File Modified) 
+  +3 -0                trunk/include/setup.h.in (File Modified) 
+
+
+gxti        2006/04/02 08:30:17 UTC    (20060402-1118)
+  Log:
+  Fix wierd error that would exit SASL users with "Overridden"
+
+  Changes:     Modified:
+  +1 -1                trunk/modules/m_signon.c (File Modified) 
+
+
+jilles      2006/03/30 10:11:21 UTC    (20060330-1116)
+  Log:
+  Remove obsolete XXX comment about lazylinks.
+  
+
+  Changes:     Modified:
+  +0 -3                trunk/contrib/m_ojoin.c (File Modified) 
+
+
+jilles      2006/03/30 02:22:18 UTC    (20060330-1114)
+  Log:
+  OJOIN: make sure to send the wallops remotely for #channels
+  
+
+  Changes:     Modified:
+  +5 -0                trunk/contrib/m_ojoin.c (File Modified) 
+
+
+gxti        2006/03/30 02:14:42 UTC    (20060330-1112)
+  Log:
+  Accountability for OJOIN (contrib module)
+
+  Changes:     Modified:
+  +6 -0                trunk/contrib/m_ojoin.c (File Modified) 
+
+
+nenolod     2006/03/29 22:55:25 UTC    (20060329-1110)
+  Log:
+  - move more stuff over to ircd_state
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/libcharybdis/linebuf.c (File Modified) 
+  +1 -1                trunk/libcharybdis/tools.c (File Modified) 
+  +9 -0                trunk/src/ircd_state.c (File Modified) 
+  +3 -3                trunk/src/patricia.c (File Modified) 
+
+
+nenolod     2006/03/29 22:49:53 UTC    (20060329-1108)
+  Log:
+  - move more stuff out of libircd and into ircd_state.c
+  
+
+  Changes:     Modified:
+  +5 -5                trunk/src/channel.c (File Modified) 
+  +4 -4                trunk/src/client.c (File Modified) 
+  +12 -0       trunk/src/ircd_state.c (File Modified) 
+
+
+nenolod     2006/03/29 22:46:12 UTC    (20060329-1106)
+  Log:
+  - this is just barrels of fun
+  
+
+  Changes:     Modified:
+  + -          trunk/include/ircd_state.h (File Added) 
+  +1 -1                trunk/src/Makefile.in (File Modified) 
+  +2 -1                trunk/src/channel.c (File Modified) 
+  +3 -52       trunk/src/ircd.c (File Modified) 
+  +100 -3      trunk/src/ircd_state.c (File Modified) 
+
+
+jilles      2006/03/26 22:51:26 UTC    (20060326-1100)
+  Log:
+  It's .include, not #include.
+  
+
+  Changes:     Modified:
+  +3 -1                trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+jilles      2006/03/26 22:35:04 UTC    (20060326-1098)
+  Log:
+  More consistent section titles.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/doc/sgml/oper-guide/cmodes.sgml (File Modified) 
+  +8 -6                trunk/doc/sgml/oper-guide/snomasks.sgml (File Modified) 
+  +5 -5                trunk/doc/sgml/oper-guide/umodes.sgml (File Modified) 
+
+
+jilles      2006/03/23 11:15:26 UTC    (20060323-1096)
+  Log:
+  Mention possible exceeding of +j/+l due to propagation
+  delays between servers.
+  
+
+  Changes:     Modified:
+  +8 -0                trunk/doc/sgml/oper-guide/cmodes.sgml (File Modified) 
+
+
+jilles      2006/03/23 11:04:43 UTC    (20060323-1094)
+  Log:
+  Formatting nits:
+  - "text" -> <quote>text</quote>
+  - <filename>
+  - a few more
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/doc/sgml/oper-guide/cmodes.sgml (File Modified) 
+  +19 -19      trunk/doc/sgml/oper-guide/commands.sgml (File Modified) 
+  +1 -1                trunk/doc/sgml/oper-guide/snomasks.sgml (File Modified) 
+  +1 -1                trunk/doc/sgml/oper-guide/umodes.sgml (File Modified) 
+
+
+jilles      2006/03/23 01:23:57 UTC    (20060323-1092)
+  Log:
+  Remove text about deprecation of glines.
+  
+
+  Changes:     Modified:
+  +0 -4                trunk/doc/sgml/oper-guide/commands.sgml (File Modified) 
+
+
+jilles      2006/03/23 00:20:59 UTC    (20060323-1090)
+  Log:
+  - Add description of umode +D, deaf.
+  - Mention CALLERID 005 token with umode +g.
+  
+
+  Changes:     Modified:
+  +24 -0       trunk/doc/sgml/oper-guide/umodes.sgml (File Modified) 
+
+
+jilles      2006/03/19 15:57:54 UTC    (20060319-1088)
+  Log:
+  Strip off a leading colon in services shortcuts (aliases).
+  
+
+  Changes:     Modified:
+  +2 -0                trunk/src/parse.c (File Modified) 
+
+
+jilles      2006/03/17 23:20:30 UTC    (20060317-1086)
+  Log:
+  Add no_oper_invis contrib module, denies opers setting
+  themselves invisible (except hidden_oper's).
+  
+
+  Changes:     Modified:
+  +42 -0       trunk/contrib/Makefile.in (File Modified) 
+  + -          trunk/contrib/no_oper_invis.c (File Added) 
+
+
+jilles      2006/03/17 21:02:06 UTC    (20060317-1084)
+  Log:
+  Mention /stats E, make the other /stats descriptions more consistent.
+  
+
+  Changes:     Modified:
+  +13 -7       trunk/doc/sgml/oper-guide/commands.sgml (File Modified) 
+
+
+jilles      2006/03/17 18:01:32 UTC    (20060317-1082)
+  Log:
+  Mention that the KILL reason and oper will appear on channels.
+  
+
+  Changes:     Modified:
+  +3 -0                trunk/doc/sgml/oper-guide/commands.sgml (File Modified) 
+
+
+jilles      2006/03/17 15:49:35 UTC    (20060317-1080)
+  Log:
+  Mention /mode #channel f to query forward channel from outside.
+  
+
+  Changes:     Modified:
+  +4 -0                trunk/doc/sgml/oper-guide/cmodes.sgml (File Modified) 
+
+
+jilles      2006/03/17 15:13:00 UTC    (20060317-1074)
+  Log:
+  Port over RATBOX_2_1 r20960 (anfl):
+  client connect notices to +C should be hiding the extra
+  fields for spoofed users
+  
+
+  Changes:     Modified:
+  +2 -1                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/03/15 17:07:32 UTC    (20060315-1072)
+  Log:
+  Add a chapter with our extra user commands:
+  ACCEPT, CNOTICE, CPRIVMSG, HELP, KNOCK, MONITOR.
+  
+
+  Changes:     Modified:
+  +181 -0      trunk/doc/sgml/oper-guide/charybdis-oper-guide.sgml (File Modified) 
+  + -          trunk/doc/sgml/oper-guide/ucommands.sgml (File Added) 
+
+
+jilles      2006/03/15 14:31:14 UTC    (20060315-1070)
+  Log:
+  Do not put by <server>: in SQUIT reasons to servers
+  other than the one being exited.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/client.c (File Modified) 
+
+
+jilles      2006/03/14 19:16:18 UTC    (20060314-1068)
+  Log:
+  Regenerate configure.
+  
+
+  Changes:     Modified:
+  +1162 -1159  trunk/configure (File Modified) 
+
+
+jilles      2006/03/14 19:15:34 UTC    (20060314-1066)
+  Log:
+  Move the warning flags down so they do not mess up
+  checks like for -Wl,-export-dynamic.
+  
+
+  Changes:     Modified:
+  +33 -30      trunk/configure.ac (File Modified) 
+
+
+nenolod     2006/03/14 14:53:54 UTC    (20060314-1064)
+  Log:
+  - more work here
+  
+
+  Changes:     Modified:
+  +2 -1                trunk/iauth/Makefile.in (File Modified) 
+
+
+nenolod     2006/03/14 14:51:39 UTC    (20060314-1062)
+  Log:
+  - build iauth makefile
+  
+
+  Changes:     Modified:
+  +3 -2                trunk/configure (File Modified) 
+  +1 -0                trunk/configure.ac (File Modified) 
+
+
+nenolod     2006/03/14 14:50:54 UTC    (20060314-1060)
+  Log:
+  - Makefile
+  
+
+  Changes:     Modified:
+  + -          trunk/iauth/Makefile.in (File Added) 
+
+
+nenolod     2006/03/14 14:46:12 UTC    (20060314-1058)
+  Log:
+  - add iauth.conf.example from irc2.11
+  
+
+  Changes:     Modified:
+  + -          trunk/doc/example-iauth.conf (File Added) 
+
+
+nenolod     2006/03/14 14:38:33 UTC    (20060314-1056)
+  Log:
+  - wow, i found some docs on this thing
+  
+
+  Changes:     Modified:
+  + -          trunk/doc/technical/iauth-internals.txt (File Added) 
+
+
+nenolod     2006/03/14 14:36:46 UTC    (20060314-1054)
+  Log:
+  - no longer applicable
+  
+
+  Changes:     Modified:
+  + -          trunk/authdaemon/ (File Deleted) 
+
+
+nenolod     2006/03/14 14:27:52 UTC    (20060314-1052)
+  Log:
+  - remove libircd.so on make clean (oops)
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/Makefile.in (File Modified) 
+
+
+nenolod     2006/03/14 14:25:50 UTC    (20060314-1050)
+  Log:
+  - merge iauth source for experimentation
+  
+
+  Changes:     Modified:
+  + -          trunk/iauth/ (File Added) 
+  + -          trunk/iauth/a_conf.c (File Added) 
+  + -          trunk/iauth/a_conf_def.h (File Added) 
+  + -          trunk/iauth/a_conf_ext.h (File Added) 
+  + -          trunk/iauth/a_defines.h (File Added) 
+  + -          trunk/iauth/a_externs.h (File Added) 
+  + -          trunk/iauth/a_io.c (File Added) 
+  + -          trunk/iauth/a_io_ext.h (File Added) 
+  + -          trunk/iauth/a_log.c (File Added) 
+  + -          trunk/iauth/a_log_def.h (File Added) 
+  + -          trunk/iauth/a_log_ext.h (File Added) 
+  + -          trunk/iauth/a_struct_def.h (File Added) 
+  + -          trunk/iauth/iauth.c (File Added) 
+  + -          trunk/iauth/mod_lhex.c (File Added) 
+  + -          trunk/iauth/mod_lhex_ext.h (File Added) 
+  + -          trunk/iauth/mod_pipe.c (File Added) 
+  + -          trunk/iauth/mod_pipe_ext.h (File Added) 
+  + -          trunk/iauth/mod_rfc931.c (File Added) 
+  + -          trunk/iauth/mod_rfc931_ext.h (File Added) 
+  + -          trunk/iauth/mod_socks.c (File Added) 
+  + -          trunk/iauth/mod_socks_ext.h (File Added) 
+  + -          trunk/iauth/mod_webproxy.c (File Added) 
+  + -          trunk/iauth/mod_webproxy_ext.h (File Added) 
+
+
+jilles      2006/03/12 16:05:39 UTC    (20060312-1044)
+  Log:
+  User /quote help index was not sorted properly.
+  
+
+  Changes:     Modified:
+  +2 -2                trunk/help/Makefile.in (File Modified) 
+  +8 -8                trunk/help/users/index (File Modified) 
+
+
+jilles      2006/03/12 15:57:27 UTC    (20060312-1038)
+  Log:
+  Add SCAN help file.
+  
+
+  Changes:     Modified:
+  +25 -8       trunk/help/opers/index (File Modified) 
+  + -          trunk/help/opers/scan (File Added) 
+
+
+jilles      2006/03/12 15:27:06 UTC    (20060312-1032)
+  Log:
+  SGML docs:
+  - Document SCAN UMODES
+  - Add details about the IP address field in MASKTRACE/CHANTRACE/SCAN UMODES
+  
+
+  Changes:     Modified:
+  +41 -0       trunk/doc/sgml/oper-guide/commands.sgml (File Modified) 
+
+
+jilles      2006/03/10 15:28:58 UTC    (20060310-1028)
+  Log:
+  Add our copyright information to /info (part of release-1.1 r1026).
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/src/version.c.SH (File Modified) 
+
+
+jilles      2006/03/10 00:16:30 UTC    (20060310-1020)
+  Log:
+  Fix some compile warnings.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/modules/core/m_join.c (File Modified) 
+  +2 -2                trunk/modules/core/m_nick.c (File Modified) 
+  +0 -1                trunk/modules/core/m_sjoin.c (File Modified) 
+  +1 -1                trunk/modules/m_scan.c (File Modified) 
+  +4 -4                trunk/modules/m_signon.c (File Modified) 
+
+
+jilles      2006/03/09 15:54:20 UTC    (20060309-1012)
+  Log:
+  RSFNC: OK, actually consider unknowns also for detecting a collide.
+  Otherwise we can get two clients with the same nick.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/modules/m_services.c (File Modified) 
+
+
+nenolod     2006/03/09 15:32:14 UTC    (20060309-1006)
+  Log:
+  - charybdis profiling stuff
+  - move all channel mode logic into src/chmode.c from modules/core/m_mode.c
+  - update .depend
+  
+
+  Changes:     Modified:
+  +0 -8                trunk/configure (File Modified) 
+  +1 -8                trunk/configure.ac (File Modified) 
+  +18 -0       trunk/include/channel.h (File Modified) 
+  +0 -1322     trunk/modules/core/m_mode.c (File Modified) 
+  +335 -260    trunk/src/.depend (File Modified) 
+  +1569 -0     trunk/src/Makefile.in (File Modified) 
+  + -          trunk/src/chmode.c (File Added) 
+  +16 -1       trunk/src/ircd.c (File Modified) 
+  +11 -0       trunk/src/main.c (File Modified) 
+  +11 -0       trunk/src/modules.c (File Modified) 
+
+
+jilles      2006/03/09 14:33:38 UTC    (20060309-1004)
+  Log:
+  RSFNC: Do not send kills to servers for unknowns
+  
+
+  Changes:     Modified:
+  +4 -2                trunk/modules/m_services.c (File Modified) 
+
+
+jilles      2006/03/09 14:25:01 UTC    (20060309-1002)
+  Log:
+  Describe service{} blocks in reference.conf.
+  
+
+  Changes:     Modified:
+  +12 -0       trunk/doc/reference.conf (File Modified) 
+
+
+jilles      2006/03/09 01:14:34 UTC    (20060309-996)
+  Log:
+  Replace this list of modes with pointers to other documentation.
+  
+
+  Changes:     Modified:
+  +6 -50       trunk/doc/modes.txt (File Modified) 
+
+
+jilles      2006/03/08 00:10:46 UTC    (20060308-986)
+  Log:
+  Name the variable for the channel pointer 'chptr' instead of 'cptr',
+  looks too much like an old-ircd client pointer otherwise.
+  
+
+  Changes:     Modified:
+  +7 -7                trunk/contrib/m_findforwards.c (File Modified) 
+
+
+jilles      2006/03/08 00:09:27 UTC    (20060308-984)
+  Log:
+  findforwards:
+  - note truncation of the list (perhaps sending multiple
+    notices is better)
+  - clarify in a comment that /findforwards on a nonexistent
+    channel can be useful
+  - sendto_one_notice() requires that the text start with
+    a colon
+  
+
+  Changes:     Modified:
+  +9 -3                trunk/contrib/m_findforwards.c (File Modified) 
+
+
+jilles      2006/03/07 23:33:48 UTC    (20060307-982)
+  Log:
+  When we close a local server's link, always include the
+  name of the client causing the exit in the reason in the
+  SQUIT we send them (replacing them with us). This makes
+  sure server notices for stuff like "Not enough arguments
+  to server command" are different on the two sides.
+  
+
+  Changes:     Modified:
+  +7 -5                trunk/src/client.c (File Modified) 
+
+
+gxti        2006/03/07 22:58:03 UTC    (20060307-980)
+  Log:
+  New contrib module m_findforwards.c
+  
+
+  Changes:     Modified:
+  +112 -0      trunk/contrib/Makefile.in (File Modified) 
+  + -          trunk/contrib/m_findforwards.c (File Added) 
+
+
+jilles      2006/03/07 22:21:29 UTC    (20060307-968)
+  Log:
+  Whoops, don't show real host behind auth{} spoof in
+  spoof notices if hide_spoof_ips is enabled.
+  
+  From ratbox (part of initial HIDE_SPOOF_IPS to conf patch)
+  
+
+  Changes:     Modified:
+  +3 -2                trunk/src/s_conf.c (File Modified) 
+
+
+jilles      2006/03/07 12:54:53 UTC    (20060307-962)
+  Log:
+  Add dalnet-style /identify that sends to nickserv or chanserv.
+  
+
+  Changes:     Modified:
+  +102 -0      trunk/contrib/Makefile.in (File Modified) 
+  + -          trunk/contrib/m_identify.c (File Added) 
+
+
+jilles      2006/03/07 12:26:20 UTC    (20060307-958)
+  Log:
+  Document alias{} blocks a bit better.
+  
+
+  Changes:     Modified:
+  +9 -0                trunk/doc/reference.conf (File Modified) 
+
+
+nenolod     2006/03/06 04:01:20 UTC    (20060306-948)
+  Log:
+  - add aliases to /stats m (data usage is not counted though, sorry)
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/include/s_conf.h (File Modified) 
+  +3 -0                trunk/src/newconf.c (File Modified) 
+  +15 -0       trunk/src/parse.c (File Modified) 
+
+
+nenolod     2006/03/06 03:43:02 UTC    (20060306-946)
+  Log:
+  - remove m_sshortcut as it's no longer relevant
+  
+
+  Changes:     Modified:
+  +0 -145      trunk/modules/Makefile.in (File Modified) 
+  + -          trunk/modules/m_sshortcut.c (File Deleted) 
+
+
+nenolod     2006/03/06 03:41:31 UTC    (20060306-944)
+  Log:
+  - support for aliases, needs some more work before it can be backported to the 1.2 branch (jilles changed this to use 
+    targets instead of my original idea :P)
+  
+
+  Changes:     Modified:
+  +32 -0       trunk/doc/example.conf (File Modified) 
+  +35 -0       trunk/doc/reference.conf (File Modified) 
+  +4 -0                trunk/include/parse.h (File Modified) 
+  +7 -0                trunk/include/s_conf.h (File Modified) 
+  +82 -0       trunk/src/newconf.c (File Modified) 
+  +78 -0       trunk/src/parse.c (File Modified) 
+  +16 -0       trunk/src/s_conf.c (File Modified) 
+
+
+jilles      2006/03/05 23:33:56 UTC    (20060305-942)
+  Log:
+  Remove some spaces after tabs. ??
+  
+
+  Changes:     Modified:
+  +18 -18      trunk/src/newconf.c (File Modified) 
+
+
+jilles      2006/03/05 23:15:38 UTC    (20060305-940)
+  Log:
+  Global /who:
+  - make sure to clear all marks also if the who was aborted
+    because of too many matches
+  - give ERR_TOOMANYMATCHES if too many matches
+  - clarify comments
+  
+  ratbox RATBOX_2_2 r22003 (jilles)
+  
+
+  Changes:     Modified:
+  +28 -26      trunk/modules/m_who.c (File Modified) 
+
+
+nenolod     2006/03/05 09:45:50 UTC    (20060305-936)
+  Log:
+  - devel is 2.0
+  
+
+  Changes:     Modified:
+  +9 -9                trunk/configure (File Modified) 
+  +1 -1                trunk/configure.ac (File Modified) 
+
+
+nenolod     2006/03/05 03:39:14 UTC    (20060305-932)
+  Log:
+  - add /rehash nickdelay to clear out the nickdelay tables (hack hack!)
+  
+
+  Changes:     Modified:
+  +2 -1                trunk/include/s_newconf.h (File Modified) 
+  +20 -0       trunk/modules/m_rehash.c (File Modified) 
+  +1 -1                trunk/src/s_newconf.c (File Modified) 
+
+
+gxti        2006/03/05 03:38:33 UTC    (20060305-930)
+  Log:
+  Pull quiet_on_ban from the config as only people who can't configure their ircd properly turn this off.
+  
+
+  Changes:     Modified:
+  +0 -1                trunk/doc/example.conf (File Modified) 
+  +0 -3                trunk/doc/reference.conf (File Modified) 
+  +0 -1                trunk/include/s_conf.h (File Modified) 
+  +0 -6                trunk/modules/m_info.c (File Modified) 
+  +1 -1                trunk/src/channel.c (File Modified) 
+  +0 -1                trunk/src/newconf.c (File Modified) 
+
+
+gxti        2006/03/05 00:48:56 UTC    (20060305-928)
+  Log:
+  Missing header in m_chghost.c
+
+  Changes:     Modified:
+  +1 -0                trunk/modules/m_chghost.c (File Modified) 
+
+
+gxti        2006/02/28 19:53:33 UTC    (20060228-926)
+  Log:
+  Relocate QJM code to a seperate function(change_nick_user_host)
+  Change CHGHOST to use change_nick_user_host instead of just setting it
+  
+
+  Changes:     Modified:
+  +3 -0                trunk/include/s_user.h (File Modified) 
+  +1 -1                trunk/modules/m_chghost.c (File Modified) 
+  +3 -78       trunk/modules/m_signon.c (File Modified) 
+  +89 -0       trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/02/28 13:24:51 UTC    (20060228-924)
+  Log:
+  Restore /stats a (dns servers, admin-only).
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/include/res.h (File Modified) 
+  +5 -8                trunk/modules/m_stats.c (File Modified) 
+  +16 -0       trunk/src/res.c (File Modified) 
+
+
+nenolod     2006/02/23 18:29:24 UTC    (20060223-920)
+  Log:
+  - Add CHARYBDIS_PROFILE if we are profiling.
+  - Remove -static from CFLAGS when profiling because this is really unnecessary.
+  - Remove duplicate --enable-epoll entry.
+  
+
+  Changes:     Modified:
+  +1595 -15    trunk/configure (File Modified) 
+  +30 -11      trunk/configure.ac (File Modified) 
+  +3 -0                trunk/include/setup.h.in (File Modified) 
+
+
+nenolod     2006/02/23 18:17:21 UTC    (20060223-918)
+  Log:
+  - Add CHARYBDIS_C_GCC_TRY_FLAGS. Guess where this is from. Just guess.
+  
+
+  Changes:     Modified:
+  +28 -0       trunk/aclocal.m4 (File Modified) 
+
+
+jilles      2006/02/23 13:25:48 UTC    (20060223-916)
+  Log:
+  Allow requesting forward channel and quiet list in same mode command.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/modules/core/m_mode.c (File Modified) 
+
+
+jilles      2006/02/22 00:06:41 UTC    (20060222-912)
+  Log:
+  Add description of xline wildcards.
+  
+
+  Changes:     Modified:
+  +14 -3       trunk/doc/sgml/oper-guide/commands.sgml (File Modified) 
+
+
+gxti        2006/02/21 23:54:57 UTC    (20060221-908)
+  Log:
+  Stop throwing out LOGIN from non-bursting servers as this interferes with SASL.
+  
+
+  Changes:     Modified:
+  +0 -4                trunk/modules/m_services.c (File Modified) 
+
+
+nenolod     2006/02/21 02:25:43 UTC    (20060221-906)
+  Log:
+  typo
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/include/hook.h (File Modified) 
+
+
+nenolod     2006/02/20 22:34:50 UTC    (20060220-904)
+  Log:
+  call_hook, not hook_call
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/modules/core/m_join.c (File Modified) 
+
+
+nenolod     2006/02/20 22:05:41 UTC    (20060220-902)
+  Log:
+  Add h_channel_join, a hook that's fired (for modules) when a channel is joined.
+  Could be useful for a number of things.
+  
+
+  Changes:     Modified:
+  +9 -0                trunk/modules/core/m_join.c (File Modified) 
+
+
+nenolod     2006/02/20 21:35:40 UTC    (20060220-900)
+  Log:
+  New type: hook_data_channel_activity, used primarily for joins and parts from a channel.
+  
+
+  Changes:     Modified:
+  +7 -0                trunk/include/hook.h (File Modified) 
+
+
+gxti        2006/02/20 21:27:46 UTC    (20060220-896)
+  Log:
+  Burst LOGIN on registration if the user was already identified (i.e. from SIGNON)
+  
+
+  Changes:     Modified:
+  +15 -0       trunk/modules/m_services.c (File Modified) 
+
+
+jilles      2006/02/20 11:26:45 UTC    (20060220-894)
+  Log:
+  Clarify snomask +f, +k, +u.
+  
+
+  Changes:     Modified:
+  +8 -4                trunk/doc/sgml/oper-guide/snomasks.sgml (File Modified) 
+
+
+jilles      2006/02/20 11:26:22 UTC    (20060220-892)
+  Log:
+  Cmode +p and +s may be set simultaneously.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/doc/sgml/oper-guide/cmodes.sgml (File Modified) 
+
+
+nenolod     2006/02/20 05:20:38 UTC    (20060220-890)
+  Log:
+  actually, we should check the data version on each reload (oops)
+  
+
+  Changes:     Modified:
+  +6 -6                trunk/src/main.c (File Modified) 
+
+
+nenolod     2006/02/20 05:17:22 UTC    (20060220-888)
+  Log:
+  more work on the loader
+  
+
+  Changes:     Modified:
+  +45 -21      trunk/src/main.c (File Modified) 
+
+
+nenolod     2006/02/20 04:04:42 UTC    (20060220-886)
+  Log:
+  Add prototype ircd_state.c
+  
+
+  Changes:     Modified:
+  + -          trunk/src/ircd_state.c (File Added) 
+
+
+jilles      2006/02/19 00:41:15 UTC    (20060219-882)
+  Log:
+  Smaller improvements.
+  
+
+  Changes:     Modified:
+  +18 -8       trunk/doc/sgml/oper-guide/commands.sgml (File Modified) 
+
+
+jilles      2006/02/19 00:15:39 UTC    (20060219-880)
+  Log:
+  Add a lot of stuff here.
+  
+
+  Changes:     Modified:
+  +210 -16     trunk/doc/sgml/oper-guide/commands.sgml (File Modified) 
+
+
+jilles      2006/02/18 22:55:32 UTC    (20060218-878)
+  Log:
+  Add +o, +t and +v cmodes and add a lot of information to other cmodes.
+  
+
+  Changes:     Modified:
+  +81 -10      trunk/doc/sgml/oper-guide/cmodes.sgml (File Modified) 
+
+
+jilles      2006/02/18 21:57:54 UTC    (20060218-873)
+  Log:
+  Invex doesn't trump +r or (sic) +J.
+  
+
+  Changes:     Modified:
+  +0 -2                trunk/doc/sgml/oper-guide/cmodes.sgml (File Modified) 
+
+
+nenolod     2006/02/18 21:56:00 UTC    (20060218-871)
+  Log:
+  Check to make sure a module is not loaded before loading it.
+  
+
+  Changes:     Modified:
+  +6 -1                trunk/src/ircd_parser.y (File Modified) 
+
+
+nenolod     2006/02/16 18:54:16 UTC    (20060216-869)
+  Log:
+  - Add a missing comma in the HeaderMessages array
+  - Only send "Your hostname is too long ..." if that really is the case
+  
+
+  Changes:     Modified:
+  +2 -2                trunk/src/s_auth.c (File Modified) 
+
+
+nenolod     2006/02/16 14:25:09 UTC    (20060216-867)
+  Log:
+  build_symtable() will have already bailed here, so no need to check
+  explicitly whether or not charybdis_main is NULL.
+  
+
+  Changes:     Modified:
+  +7 -16       trunk/src/main.c (File Modified) 
+
+
+nenolod     2006/02/16 14:05:37 UTC    (20060216-865)
+  Log:
+  Data structure versioning, part 1.
+  
+
+  Changes:     Modified:
+  +10 -1       trunk/include/ircd_defs.h (File Modified) 
+  +2 -0                trunk/src/ircd.c (File Modified) 
+  +15 -3       trunk/src/main.c (File Modified) 
+
+
+nenolod     2006/02/16 06:51:59 UTC    (20060216-863)
+  Log:
+  build a symbol table and use that instead of doing a raw dlsym on everything
+  
+
+  Changes:     Modified:
+  + -          trunk/include/ircd_linker.h (File Added) 
+  +71 -1       trunk/src/Makefile.in (File Modified) 
+  + -          trunk/src/ircd_linker.c (File Added) 
+  +16 -4       trunk/src/main.c (File Modified) 
+
+
+nenolod     2006/02/15 23:15:08 UTC    (20060215-861)
+  Log:
+  The launcher now calls io_loop() instead of charybdis_main().
+  This is so that we do not have to reinitialize *everything* later.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/include/ircd.h (File Modified) 
+  +6 -7                trunk/src/ircd.c (File Modified) 
+  +13 -1       trunk/src/main.c (File Modified) 
+
+
+nenolod     2006/02/15 23:05:22 UTC    (20060215-859)
+  Log:
+  Use global binding on libircd.so.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/main.c (File Modified) 
+
+
+nenolod     2006/02/15 22:49:16 UTC    (20060215-857)
+  Log:
+  - most of the IRCd is now a shared library, ircd is just a launcher that opens libircd.so and runs it now.
+    (it will do more later)
+  
+
+  Changes:     Modified:
+  +14 -12      trunk/include/config.h (File Modified) 
+  +1 -1                trunk/libcharybdis/Makefile.in (File Modified) 
+  +31 -5       trunk/src/Makefile.in (File Modified) 
+  +78 -1       trunk/src/ircd.c (File Modified) 
+  + -          trunk/src/main.c (File Added) 
+
+
+nenolod     2006/02/15 03:27:43 UTC    (20060215-855)
+  Log:
+  Add whitespace here, oops.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/CREDITS (File Modified) 
+
+
+nenolod     2006/02/15 01:34:19 UTC    (20060215-851)
+  Log:
+  Properly copy over the IP address here instead of using a cheap hack.
+  Because the hack didn't work right except on IPv6. :|
+  
+
+  Changes:     Modified:
+  +12 -2       trunk/src/s_newconf.c (File Modified) 
+
+
+jilles      2006/02/15 01:33:43 UTC    (20060215-849)
+  Log:
+  Revert reject cache notice to ratbox's, which more
+  clearly suggests what's happening.
+  
+
+  Changes:     Modified:
+  +4 -1                trunk/src/reject.c (File Modified) 
+
+
+nenolod     2006/02/15 01:30:41 UTC    (20060215-847)
+  Log:
+  Fix the openssl status in the overview information.
+  
+
+  Changes:     Modified:
+  +1 -3                trunk/configure (File Modified) 
+  +1 -3                trunk/configure.ac (File Modified) 
+
+
+jilles      2006/02/15 00:53:32 UTC    (20060215-843)
+  Log:
+  - Add simple exempt{} block (127.0.0.1) to example.conf.
+  - Remove mention of deny{}.
+  
+
+  Changes:     Modified:
+  +5 -0                trunk/doc/example.conf (File Modified) 
+  +1 -1                trunk/doc/reference.conf (File Modified) 
+
+
+jilles      2006/02/15 00:37:34 UTC    (20060215-839)
+  Log:
+  example.conf: add some comments at the start
+  reference.conf: some ircd-ratbox -> charybdis
+  
+
+  Changes:     Modified:
+  +11 -0       trunk/doc/example.conf (File Modified) 
+  +6 -5                trunk/doc/reference.conf (File Modified) 
+
+
+jilles      2006/02/15 00:27:59 UTC    (20060215-833)
+  Log:
+  Rename m_createauthonly module to createauthonly
+  as this is not a module providing an m_function
+  (command).
+  
+
+  Changes:     Modified:
+  +1 -38       trunk/contrib/Makefile.in (File Modified) 
+  + -          trunk/contrib/createauthonly.c (File Added) 
+  + -          trunk/contrib/m_createauthonly.c (File Deleted) 
+
+
+jilles      2006/02/15 00:22:08 UTC    (20060215-831)
+  Log:
+  Add to example confs commented lines for:
+  createauthonly.so, ip_cloaking.so, sno_farconnect.so,
+  sno_globalkline.so, sno_globaloper.so.
+  
+
+  Changes:     Modified:
+  +5 -1                trunk/doc/example.conf (File Modified) 
+  +9 -1                trunk/doc/reference.conf (File Modified) 
+
+
+jilles      2006/02/15 00:12:24 UTC    (20060215-829)
+  Log:
+  - Unbreak connecting to connect{}s with hostnames
+    instead of IP addresses (broken with new resolver).
+  - Try to do A/AAAA query based on aftype in
+    connect{} (doesn't seem to work fully).
+  
+
+  Changes:     Modified:
+  +19 -2       trunk/libcharybdis/commio.c (File Modified) 
+
+
+jilles      2006/02/14 22:54:37 UTC    (20060214-827)
+  Log:
+  Unbreak /rehash dns.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/src/res.c (File Modified) 
+
+
+jilles      2006/02/14 22:40:55 UTC    (20060214-825)
+  Log:
+  Preserve Hybrid Id and add one of our own.
+  
+
+  Changes:     Modified:
+  +2 -1                trunk/src/res.c (File Modified) (Property Modified)
+  +2 -1                trunk/src/reslib.c (File Modified) (Property Modified)
+
+
+jilles      2006/02/14 22:17:17 UTC    (20060214-821)
+  Log:
+  Add anfl and Androsyn to CREDITS.
+  They wrote a lot of ratbox code we use, both before and after the fork.
+  
+
+  Changes:     Modified:
+  +2 -0                trunk/CREDITS (File Modified) 
+
+
+nenolod     2006/02/14 21:39:42 UTC    (20060214-819)
+  Log:
+  Hostname validity check.
+  
+
+  Changes:     Modified:
+  +42 -3       trunk/src/s_auth.c (File Modified) 
+
+
+nenolod     2006/02/14 21:02:12 UTC    (20060214-817)
+  Log:
+  Version bump to 1.2.0.
+  
+
+  Changes:     Modified:
+  +9 -9                trunk/configure (File Modified) 
+  +1 -1                trunk/configure.ac (File Modified) 
+
+
+nenolod     2006/02/14 20:55:24 UTC    (20060214-815)
+  Log:
+  - Missed a spot in the IPv6 code here. Should be usable now.
+  
+
+  Changes:     Modified:
+  +2 -2                trunk/src/res.c (File Modified) 
+
+
+nenolod     2006/02/14 20:52:15 UTC    (20060214-813)
+  Log:
+  Alright, so, this massive commit does the following:
+  - Removes adns
+  - Adds a resolver based on the undernet and hybrid one.
+  - Tries to clean up a giant mess in the header dependencies (encountered during the above)
+  - Makes a check in ./configure be posixly correct
+  - Simplifies the auth code and DNS callbacks
+  
+  Needs testing. Especially under IPv6. I probably fucked something up there. I will test it later.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/Makefile.in (File Modified) 
+  + -          trunk/adns/ (File Deleted) 
+  +148 -80     trunk/configure (File Modified) 
+  +1 -2                trunk/configure.ac (File Modified) 
+  +6 -0                trunk/include/client.h (File Modified) 
+  +1 -0                trunk/include/packet.h (File Modified) 
+  +153 -41     trunk/include/res.h (File Modified) 
+  + -          trunk/include/reslib.h (File Added) 
+  +4 -33       trunk/libcharybdis/commio.c (File Modified) 
+  +930 -1449   trunk/modules/.depend (File Modified) 
+  +3 -0                trunk/modules/m_stats.c (File Modified) 
+  +417 -621    trunk/src/.depend (File Modified) 
+  +1 -1                trunk/src/.indent.pro (File Modified) 
+  +2069 -289   trunk/src/Makefile.in (File Modified) 
+  + -          trunk/src/adns.c (File Deleted) 
+  + -          trunk/src/res.c (File Added) 
+  + -          trunk/src/reslib.c (File Added) 
+  +11 -50      trunk/src/s_auth.c (File Modified) 
+  +4 -26       trunk/src/s_newconf.c (File Modified) 
+
+
+nenolod     2006/02/13 20:14:51 UTC    (20060213-811)
+  Log:
+  Document the NOBALLOC feature.
+  
+
+  Changes:     Modified:
+  +7 -1                trunk/include/config.h (File Modified) 
+
+
+jilles      2006/02/12 20:50:51 UTC    (20060212-806)
+  Log:
+  commands.sgml changes
+  
+
+  Changes:     Modified:
+  +126 -51     trunk/doc/sgml/oper-guide/commands.sgml (File Modified) 
+
+
+jilles      2006/02/12 19:58:28 UTC    (20060212-804)
+  Log:
+  connect{} changes.
+  
+
+  Changes:     Modified:
+  +11 -4       trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+jilles      2006/02/12 19:47:43 UTC    (20060212-802)
+  Log:
+  Improve description of class{} block (in particular,
+  mention server classes as well as client classes).
+  
+
+  Changes:     Modified:
+  +41 -3       trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+jilles      2006/02/12 19:37:35 UTC    (20060212-800)
+  Log:
+  In comment:
+  -/* sendq: servers need a higher sendq as they send more data */
+  +/* sendq: servers need a higher sendq as they are sent more data */
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/doc/reference.conf (File Modified) 
+
+
+jilles      2006/02/12 19:33:35 UTC    (20060212-798)
+  Log:
+  Add modules{} block.
+  
+
+  Changes:     Modified:
+  +28 -0       trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+jilles      2006/02/12 17:31:44 UTC    (20060212-796)
+  Log:
+  Add general::oper_snomask, snomask on oper up for opers
+  that have umode +s set on oper up, but do not have
+  a specific snomask setting in their operator block.
+  If this is empty or not specified, +s is used as before.
+  
+
+  Changes:     Modified:
+  +4 -1                trunk/doc/example.conf (File Modified) 
+  +7 -1                trunk/doc/reference.conf (File Modified) 
+  +1 -0                trunk/include/client.h (File Modified) 
+  +1 -0                trunk/include/s_conf.h (File Modified) 
+  +32 -0       trunk/src/newconf.c (File Modified) 
+  +1 -0                trunk/src/s_conf.c (File Modified) 
+  +13 -3       trunk/src/s_user.c (File Modified) 
+
+
+nenolod     2006/02/12 07:27:54 UTC    (20060212-794)
+  Log:
+  fix error
+
+  Changes:     Modified:
+  +1 -1                trunk/doc/sgml/oper-guide/commands.sgml (File Modified) 
+
+
+nenolod     2006/02/12 07:13:38 UTC    (20060212-792)
+  Log:
+  Add MASKTRACE and CHANTRACE commands.
+  
+
+  Changes:     Modified:
+  +23 -5       trunk/doc/sgml/oper-guide/commands.sgml (File Modified) 
+
+
+nenolod     2006/02/12 06:39:51 UTC    (20060212-790)
+  Log:
+  document loadmodule directive
+  
+
+  Changes:     Modified:
+  +12 -3       trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+nenolod     2006/02/12 06:36:19 UTC    (20060212-788)
+  Log:
+  finish this up
+  
+
+  Changes:     Modified:
+  +29 -3       trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+nenolod     2006/02/12 06:29:55 UTC    (20060212-786)
+  Log:
+  q:lines are no longer living in the ircd.conf either
+  
+
+  Changes:     Modified:
+  +0 -8                trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+nenolod     2006/02/12 04:28:54 UTC    (20060212-784)
+  Log:
+  remove k:line, d:line, x:line as they are their own files now
+  
+
+  Changes:     Modified:
+  +0 -29       trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+jilles      2006/02/12 03:55:38 UTC    (20060212-782)
+  Log:
+  New place for operator::snomask.
+  
+
+  Changes:     Modified:
+  +9 -9                trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+nenolod     2006/02/12 03:46:29 UTC    (20060212-780)
+  Log:
+  Document connect {}.
+  
+
+  Changes:     Modified:
+  +101 -20     trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+jilles      2006/02/12 03:42:26 UTC    (20060212-778)
+  Log:
+  example.conf: move operator::snomask to a more logical place,
+  more sensible default
+  reference.conf: add operator::snomask
+  
+
+  Changes:     Modified:
+  +3 -3                trunk/doc/example.conf (File Modified) 
+  +3 -0                trunk/doc/reference.conf (File Modified) 
+
+
+jilles      2006/02/12 03:34:24 UTC    (20060212-776)
+  Log:
+  Allow specifying +D (deaf), +Q (noforward) and +R (regonlymsg)
+  in those conf entries that take umodes like <name1>, <name2>, ...
+  
+
+  Changes:     Modified:
+  +3 -0                trunk/doc/reference.conf (File Modified) 
+  +3 -0                trunk/src/newconf.c (File Modified) 
+
+
+nenolod     2006/02/12 03:33:02 UTC    (20060212-774)
+  Log:
+  Remove H:line
+  
+
+  Changes:     Modified:
+  +0 -7                trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+nenolod     2006/02/12 03:30:32 UTC    (20060212-772)
+  Log:
+  Aesthetic changes.
+  
+
+  Changes:     Modified:
+  +2 -0                trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+nenolod     2006/02/12 03:28:34 UTC    (20060212-770)
+  Log:
+  s/allow/auth
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+nenolod     2006/02/12 03:26:36 UTC    (20060212-768)
+  Log:
+  fix
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+nenolod     2006/02/12 03:25:40 UTC    (20060212-766)
+  Log:
+  Document operator {} blocks.
+  
+
+  Changes:     Modified:
+  +65 -17      trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+jilles      2006/02/12 03:18:31 UTC    (20060212-764)
+  Log:
+  auth{}: clarify/add some details
+  
+
+  Changes:     Modified:
+  +14 -7       trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+nenolod     2006/02/12 03:11:11 UTC    (20060212-762)
+  Log:
+  auth{}: Move a paragraph.
+  
+
+  Changes:     Modified:
+  +3 -3                trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+nenolod     2006/02/12 03:02:10 UTC    (20060212-760)
+  Log:
+  Document auth{} blocks.
+  
+
+  Changes:     Modified:
+  +107 -43     trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+jilles      2006/02/12 02:23:21 UTC    (20060212-758)
+  Log:
+  Add umode +R.
+  
+
+  Changes:     Modified:
+  +2 -1                trunk/doc/sgml/oper-guide/umodes.sgml (File Modified) 
+
+
+jilles      2006/02/12 02:19:41 UTC    (20060212-756)
+  Log:
+  Add umode +R, prevents unidentified clients from
+  sending private messages or notices. /accept'ed
+  clients and opers are exempt.
+  Due to the /accept part, this is only checked
+  at the target's server, may want to change
+  this?
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/help/opers/umode (File Modified) 
+  +1 -0                trunk/help/users/umode (File Modified) 
+  +2 -0                trunk/include/client.h (File Modified) 
+  +1 -0                trunk/include/numeric.h (File Modified) 
+  +11 -1       trunk/modules/core/m_message.c (File Modified) 
+  +9 -1                trunk/modules/m_cmessage.c (File Modified) 
+  +1 -1                trunk/src/messages.tab (File Modified) 
+  +1 -1                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/02/12 01:26:44 UTC    (20060212-754)
+  Log:
+  Don't allow a nick change if banned or quieted (and not
+  voiced or opped) on a channel. This uses numeric 435
+  (bahamut's "cannot change to a banned nick") because
+  bahamut/ircu's 437 and hyperion's 438 already have
+  another meaning for us.
+  
+
+  Changes:     Modified:
+  +2 -0                trunk/include/channel.h (File Modified) 
+  +1 -0                trunk/include/numeric.h (File Modified) 
+  +9 -0                trunk/modules/core/m_nick.c (File Modified) 
+  +38 -0       trunk/src/channel.c (File Modified) 
+  +1 -1                trunk/src/messages.tab (File Modified) 
+
+
+jilles      2006/02/11 20:55:03 UTC    (20060211-752)
+  Log:
+  KNOCK:
+  - respect ban exceptions
+  - also deny a knock if quieted
+  
+
+  Changes:     Modified:
+  +2 -1                trunk/modules/m_knock.c (File Modified) 
+
+
+jilles      2006/02/11 19:42:32 UTC    (20060211-750)
+  Log:
+  Reverse bad substitution in comment.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/channel.c (File Modified) 
+
+
+jilles      2006/02/11 19:04:47 UTC    (20060211-748)
+  Log:
+  - set DynSpoof flag for clients spoofed at registration
+  - add orighost instead of host to the hostname hash
+  
+
+  Changes:     Modified:
+  +5 -1                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/02/11 16:59:13 UTC    (20060211-746)
+  Log:
+  sendto_common_channels_local_butone(): nicer way to skip the user themselves.
+  
+
+  Changes:     Modified:
+  +2 -3                trunk/src/send.c (File Modified) 
+
+
+gxti        2006/02/10 02:44:34 UTC    (20060210-744)
+  Log:
+  Change login field semantics in SVSLOGIN/SIGNON to allow both no-change and logout.
+  
+
+  Changes:     Modified:
+  +17 -7       trunk/modules/m_signon.c (File Modified) 
+
+
+gxti        2006/02/09 02:44:48 UTC    (20060209-742)
+  Log:
+  Correct minimum args on ENCAP SASL to avoid nasty core.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/modules/m_sasl.c (File Modified) 
+
+
+jilles      2006/02/09 01:14:21 UTC    (20060209-740)
+  Log:
+  Style nits: sptr can't ever be NULL, don't compare truth
+  values with YES.
+  
+
+  Changes:     Modified:
+  +2 -3                trunk/modules/m_scan.c (File Modified) 
+
+
+jilles      2006/02/09 01:04:56 UTC    (20060209-738)
+  Log:
+  - Comment out scan_cmodes() prototype to suppress warning
+  - Correct minimum parameter count for mo_scan()
+  
+
+  Changes:     Modified:
+  +2 -2                trunk/modules/m_scan.c (File Modified) 
+
+
+jilles      2006/02/09 00:56:16 UTC    (20060209-736)
+  Log:
+  SCAN UMODES:
+  - Include full command in operspy notice
+  - Allow global scans (no-list used, mask not used) without operspy
+  - Use ERR_NOPRIVS numeric
+  
+
+  Changes:     Modified:
+  +21 -9       trunk/modules/m_scan.c (File Modified) 
+
+
+jilles      2006/02/08 23:45:23 UTC    (20060208-734)
+  Log:
+  Cancel out the >3 default if < is given; this way
+  any </> specification fully overrides the default.
+  
+
+  Changes:     Modified:
+  +3 -0                trunk/modules/m_list_safelist.c (File Modified) 
+
+
+jilles      2006/02/08 23:13:44 UTC    (20060208-732)
+  Log:
+  - Call mo_list() from m_list() to reduce code duplication
+  - Default to >3, rather arbitrarily (conf option?)
+  - Make < and > mean less than and greater than again
+  
+
+  Changes:     Modified:
+  +16 -47      trunk/modules/m_list_safelist.c (File Modified) 
+
+
+jilles      2006/02/08 22:20:43 UTC    (20060208-730)
+  Log:
+  When processing topic burst, hide connecting server
+  on netburst if flatten links is enabled.
+  
+
+  Changes:     Modified:
+  +9 -2                trunk/modules/m_tb.c (File Modified) 
+
+
+nenolod     2006/02/08 22:03:57 UTC    (20060208-728)
+  Log:
+  - remove PENALTY token
+  
+
+  Changes:     Modified:
+  +0 -1                trunk/include/supported.h (File Modified) 
+
+
+nenolod     2006/02/08 22:00:03 UTC    (20060208-726)
+  Log:
+  005 fixups:
+  - Add PENALTY because we have a pace-wait system.
+  - Add FNC due to SAVE and RSFNC
+  - Add q to MAXLIST.
+  
+
+  Changes:     Modified:
+  +4 -2                trunk/include/supported.h (File Modified) 
+
+
+nenolod     2006/02/08 21:55:57 UTC    (20060208-724)
+  Log:
+  mkay, indent went nuts here
+  
+
+  Changes:     Modified:
+  +4 -6                trunk/modules/m_list_safelist.c (File Modified) 
+
+
+nenolod     2006/02/08 21:51:28 UTC    (20060208-722)
+  Log:
+  Implement SAFELIST. The old ratbox method is now called m_list_ratbox.c,
+  and can be used instead. The SAFELIST implementation is the one used by
+  default, as most users/networks will be used to it.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/NEWS (File Modified) 
+  +14 -0       trunk/include/client.h (File Modified) 
+  +5 -0                trunk/include/hash.h (File Modified) 
+  +404 -272    trunk/modules/Makefile.in (File Modified) 
+  + -          trunk/modules/m_list.c (File Deleted) 
+  + -          trunk/modules/m_list_ratbox.c (File Added) 
+  + -          trunk/modules/m_list_safelist.c (File Added) 
+  +5 -5                trunk/src/hash.c (File Modified) 
+
+
+jilles      2006/02/08 21:02:52 UTC    (20060208-720)
+  Log:
+  Clear invites on a lowerTS JOIN or SJOIN.
+  This should complete kick_on_split_riding protection.
+  
+
+  Changes:     Modified:
+  +5 -0                trunk/modules/core/m_join.c (File Modified) 
+  +5 -1                trunk/modules/core/m_sjoin.c (File Modified) 
+
+
+jilles      2006/02/08 20:26:58 UTC    (20060208-718)
+  Log:
+  Like in ratbox, send and interpret timestamps on invites.
+  
+
+  Changes:     Modified:
+  +9 -2                trunk/modules/m_invite.c (File Modified) 
+
+
+jilles      2006/02/07 12:48:28 UTC    (20060207-716)
+  Log:
+  Add +S (network service) umode. Just for completeness, users or opers
+  cannot set this.
+  
+
+  Changes:     Modified:
+  +19 -0       trunk/doc/sgml/oper-guide/umodes.sgml (File Modified) 
+
+
+nenolod     2006/02/06 20:04:23 UTC    (20060206-714)
+  Log:
+  update NEWS a bit
+  
+
+  Changes:     Modified:
+  +35 -2       trunk/NEWS (File Modified) 
+
+
+gxti        2006/02/06 04:42:14 UTC    (20060206-712)
+  Log:
+  Split off a PreClient structure for data to be freed on registation (i.e. password).
+  New hook introduce_client for post-registration messages.
+  Fix b0rked SASL numerics.
+  Burst REALHOST post-introduction for spoofed-on-registration clients.
+  Rearrange SVSLOGIN arguments so that allowednicks is at the end; optional.
+  Pre-registration signon support.
+  
+
+  Changes:     Modified:
+  +10 -0       trunk/configure (File Modified) 
+  +2 -0                trunk/configure.ac (File Modified) 
+  +14 -4       trunk/include/client.h (File Modified) 
+  +1 -0                trunk/include/hook.h (File Modified) 
+  +1 -0                trunk/include/numeric.h (File Modified) 
+  +3 -0                trunk/include/setup.h.in (File Modified) 
+  +16 -0       trunk/modules/m_chghost.c (File Modified) 
+  +25 -21      trunk/modules/m_sasl.c (File Modified) 
+  +63 -30      trunk/modules/m_signon.c (File Modified) 
+  +18 -0       trunk/src/client.c (File Modified) 
+  +2 -0                trunk/src/hook.c (File Modified) 
+  +5 -5                trunk/src/messages.tab (File Modified) 
+  +2 -0                trunk/src/s_serv.c (File Modified) 
+  +28 -2       trunk/src/s_user.c (File Modified) 
+
+
+gxti        2006/02/06 03:10:01 UTC    (20060206-710)
+  Log:
+  Update hook documentation.
+  
+
+  Changes:     Modified:
+  +30 -0       trunk/doc/hooks.txt (File Modified) 
+
+
+jilles      2006/02/05 22:44:03 UTC    (20060205-708)
+  Log:
+  Improve @/# handling in match_esc().
+  
+
+  Changes:     Modified:
+  +21 -13      trunk/src/match.c (File Modified) 
+
+
+nenolod     2006/02/05 21:09:04 UTC    (20060205-706)
+  Log:
+  backtrack instead of bailing out when handling a mismatched escape
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/match.c (File Modified) 
+
+
+nenolod     2006/02/05 20:33:39 UTC    (20060205-704)
+  Log:
+  Denote Entrope as being a contributor, since we used his match() routines from ircu/srvx.
+
+  Changes:     Modified:
+  +2 -1                trunk/CREDITS (File Modified) 
+
+
+nenolod     2006/02/05 20:24:55 UTC    (20060205-702)
+  Log:
+  Fix the escape brokenness and pick up a more efficient matching algorithm,
+  via ircu (Entrope, Runaway et al.). Where do we lose? Nowhere.
+  Patch sent upstream. They can do whatever they want with it, *shrug*.
+  
+
+  Changes:     Modified:
+  +147 -161    trunk/src/match.c (File Modified) 
+
+
+jilles      2006/02/04 20:13:39 UTC    (20060204-700)
+  Log:
+  If flatten links is enabled, fake the origins of some ServerModes
+  sent to clients so that the server sending the netburst is hidden.
+  Most mode hacks still show the true source.
+  
+
+  Changes:     Modified:
+  +17 -4       trunk/modules/core/m_mode.c (File Modified) 
+  +20 -10      trunk/modules/core/m_sjoin.c (File Modified) 
+
+
+jilles      2006/02/04 18:26:55 UTC    (20060204-698)
+  Log:
+  - When exiting a local server, send SQUIT <them> :<reason> (no matter
+    where the exit originated).
+  - When receiving an SQUIT for a server themselves
+    (IsMe(target_p) || target_p == client_p)
+    close their link and send a local server notice.
+  
+
+  Changes:     Modified:
+  +16 -9       trunk/modules/core/m_squit.c (File Modified) 
+  +6 -3                trunk/src/client.c (File Modified) 
+
+
+nenolod     2006/02/04 04:37:10 UTC    (20060204-696)
+  Log:
+  Hooking into the wrong hook, whoops. :P
+  
+
+  Changes:     Modified:
+  +3 -5                trunk/contrib/m_createauthonly.c (File Modified) 
+  +6 -10       trunk/modules/core/m_join.c (File Modified) 
+
+
+nenolod     2006/02/04 04:11:17 UTC    (20060204-694)
+  Log:
+  this doesn't work right, right now :P
+  
+
+  Changes:     Modified:
+  +40 -0       trunk/contrib/Makefile.in (File Modified) 
+  + -          trunk/contrib/m_createauthonly.c (File Added) 
+  +6 -0                trunk/include/hook.h (File Modified) 
+  +26 -1       trunk/modules/core/m_join.c (File Modified) 
+  +1 -1                trunk/src/ircd.c (File Modified) 
+
+
+nenolod     2006/02/04 03:11:05 UTC    (20060204-692)
+  Log:
+  Make can_join() hookable.
+  
+
+  Changes:     Modified:
+  +12 -1       trunk/src/channel.c (File Modified) 
+
+
+nenolod     2006/02/04 03:04:20 UTC    (20060204-690)
+  Log:
+  add 'int approved;' to the channel event hook
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/include/hook.h (File Modified) 
+
+
+gxti        2006/02/04 02:50:03 UTC    (20060204-688)
+  Log:
+  Use SIDs in SASL ENCAP origin.
+  Ignore responses from other agents once the first SASL response has been received for a client.
+  
+
+  Changes:     Modified:
+  +9 -5                trunk/modules/m_sasl.c (File Modified) 
+
+
+gxti        2006/02/04 01:44:17 UTC    (20060204-686)
+  Log:
+  Removed stray debug code.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/modules/m_sasl.c (File Modified) 
+
+
+jilles      2006/02/03 22:39:24 UTC    (20060203-684)
+  Log:
+  Don't complain "unknown MODE flag" if a non-oper attempts
+  to unset an oper only umode they do not have.
+  This is to prevent unwanted error messages when users/bots
+  do things like MODE <nick> +i-sw.
+  
+
+  Changes:     Modified:
+  +4 -2                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/02/03 22:32:03 UTC    (20060203-682)
+  Log:
+  Fix client_exit hook name and only call it for local exits that are not
+  IsAnyServer.
+  
+
+  Changes:     Modified:
+  +3 -2                trunk/modules/m_sasl.c (File Modified) 
+
+
+gxti        2006/02/03 21:41:48 UTC    (20060203-680)
+  Log:
+  Fix SASL logic to actually use stored agent UID.
+  Change instances of SASL code that use sendto_one_prefix for ENCAP.
+  Add abort code for exiting clients.
+  
+
+  Changes:     Modified:
+  +18 -9       trunk/modules/m_sasl.c (File Modified) 
+
+
+jilles      2006/02/03 20:25:01 UTC    (20060203-678)
+  Log:
+  Port over ratbox 2.2 /challenge. This is slightly more secure
+  (better crypto, longer keys, challenge timeout) and has better
+  client scripts.
+  
+  The respond tool is no longer part of the ircd tree but a
+  separate package, currently available from
+  http://respond.ircd-ratbox.org (we should mirror/... this).
+  
+
+  Changes:     Modified:
+  +65 -310     trunk/doc/challenge.txt (File Modified) 
+  +5 -5                trunk/include/client.h (File Modified) 
+  +3 -0                trunk/include/irc_string.h (File Modified) 
+  +3 -0                trunk/include/numeric.h (File Modified) 
+  +94 -50      trunk/modules/m_challenge.c (File Modified) 
+  +1 -2                trunk/src/client.c (File Modified) 
+  +125 -0      trunk/src/irc_string.c (File Modified) 
+  +2 -2                trunk/src/messages.tab (File Modified) 
+  + -          trunk/tools/rsa_respond/ (File Deleted) 
+
+
+gxti        2006/02/03 20:05:09 UTC    (20060203-676)
+  Log:
+  Preliminary SASL support.
+  
+
+  Changes:     Modified:
+  +7 -0                trunk/include/client.h (File Modified) 
+  +6 -0                trunk/include/numeric.h (File Modified) 
+  +1 -0                trunk/modules/Makefile.in (File Modified) 
+  +1 -1                trunk/modules/core/m_nick.c (File Modified) 
+  +175 -1      trunk/modules/m_cap.c (File Modified) 
+  + -          trunk/modules/m_sasl.c (File Added) 
+  +2 -0                trunk/modules/m_user.c (File Modified) 
+  +5 -5                trunk/src/messages.tab (File Modified) 
+  +8 -2                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/02/03 18:13:03 UTC    (20060203-674)
+  Log:
+  SIGNON: make logout also apply remotely.
+  
+
+  Changes:     Modified:
+  +7 -2                trunk/modules/m_signon.c (File Modified) 
+
+
+gxti        2006/02/03 17:45:04 UTC    (20060203-672)
+  Log:
+  Use an asterisk when sending empty logins in SIGNON.
+  
+
+  Changes:     Modified:
+  +5 -5                trunk/modules/m_signon.c (File Modified) 
+
+
+jilles      2006/02/03 17:38:31 UTC    (20060203-670)
+  Log:
+  SIGNON: Only add whowas entry (add_history()) and wipe
+  accepts (del_all_accepts()) if nick changed.
+  
+
+  Changes:     Modified:
+  +5 -3                trunk/modules/m_signon.c (File Modified) 
+
+
+jilles      2006/02/03 17:26:52 UTC    (20060203-668)
+  Log:
+  SIGNON: slight fixes to collision code:
+  - don't kill if target_p == source_p (nick unchanged or only changed case)
+  - add comment that SAVE support is missing
+  - use sendto_realops_snomask() instead of sendto_realops_flags()
+  
+
+  Changes:     Modified:
+  +9 -6                trunk/modules/m_signon.c (File Modified) 
+
+
+jilles      2006/02/03 17:19:26 UTC    (20060203-666)
+  Log:
+  Fix up kills for bad nick/user/host on SIGNON.
+  
+
+  Changes:     Modified:
+  +16 -6       trunk/modules/m_signon.c (File Modified) 
+
+
+jilles      2006/02/03 16:50:56 UTC    (20060203-664)
+  Log:
+  If changing to a nick with a digit, only allow the UID.
+  
+
+  Changes:     Modified:
+  +4 -0                trunk/modules/m_signon.c (File Modified) 
+
+
+gxti        2006/02/03 04:20:31 UTC    (20060203-661)
+  Log:
+  Cleaned up SIGNON patch for mainline with quit-join-mode support.
+  Strip leading digits from logins that are not purely numeric.
+  
+
+  Changes:     Modified:
+  +3 -0                trunk/include/numeric.h (File Modified) 
+  +2 -0                trunk/include/send.h (File Modified) 
+  +1 -0                trunk/modules/Makefile.in (File Modified) 
+  +456 -3      trunk/modules/m_services.c (File Modified) 
+  + -          trunk/modules/m_signon.c (File Added) 
+  +2 -2                trunk/src/messages.tab (File Modified) 
+  +98 -0       trunk/src/send.c (File Modified) 
+
+
+jilles      2006/02/02 14:10:16 UTC    (20060202-659)
+  Log:
+  Remove old server notice umodes from example confs.
+  
+
+  Changes:     Modified:
+  +1 -2                trunk/doc/example.conf (File Modified) 
+  +4 -17       trunk/doc/reference.conf (File Modified) 
+
+
+jilles      2006/02/01 15:11:42 UTC    (20060201-657)
+  Log:
+  Add snomask help file (forgot this earlier).
+  
+
+  Changes:     Modified:
+  + -          trunk/help/opers/snomask (File Added) 
+
+
+jilles      2006/01/31 12:50:36 UTC    (20060131-655)
+  Log:
+  Add umode +l (receive locops).
+  
+
+  Changes:     Modified:
+  +11 -0       trunk/doc/sgml/oper-guide/umodes.sgml (File Modified) 
+
+
+jilles      2006/01/31 12:44:21 UTC    (20060131-653)
+  Log:
+  We don't plan to implement cmode +R (quiet unidentified) and
+  umode +I (deny invite) for 1.1, so comment them out from the
+  docs.
+  
+
+  Changes:     Modified:
+  +2 -0                trunk/doc/sgml/oper-guide/cmodes.sgml (File Modified) 
+  +2 -0                trunk/doc/sgml/oper-guide/umodes.sgml (File Modified) 
+
+
+jilles      2006/01/31 12:40:38 UTC    (20060131-651)
+  Log:
+  Improve snomask usage description.
+  
+
+  Changes:     Modified:
+  +9 -5                trunk/doc/sgml/oper-guide/snomasks.sgml (File Modified) 
+
+
+jilles      2006/01/31 12:33:01 UTC    (20060131-649)
+  Log:
+  Mention the word snomask with umode +s (needs to be a link really).
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/doc/sgml/oper-guide/umodes.sgml (File Modified) 
+
+
+jilles      2006/01/31 12:28:58 UTC    (20060131-647)
+  Log:
+  Add snomask +Z (operspy notices).
+  
+
+  Changes:     Modified:
+  +10 -0       trunk/doc/sgml/oper-guide/snomasks.sgml (File Modified) 
+
+
+jilles      2006/01/31 12:23:29 UTC    (20060131-645)
+  Log:
+  Misc updates/clarifications.
+  
+
+  Changes:     Modified:
+  +8 -6                trunk/doc/sgml/oper-guide/oprivs.sgml (File Modified) 
+
+
+jilles      2006/01/31 12:15:29 UTC    (20060131-643)
+  Log:
+  Document snomasks.
+  
+
+  Changes:     Modified:
+  +139 -0      trunk/doc/sgml/oper-guide/charybdis-oper-guide.sgml (File Modified) 
+  + -          trunk/doc/sgml/oper-guide/snomasks.sgml (File Added) 
+  +3 -85       trunk/doc/sgml/oper-guide/umodes.sgml (File Modified) 
+
+
+jilles      2006/01/30 01:07:43 UTC    (20060130-641)
+  Log:
+  - Allow ENCAP REALHOST outside burst
+  - Fix comment describing race condition: this can only happen
+    on a local whois with use_whois_actually enabled
+  
+
+  Changes:     Modified:
+  +4 -6                trunk/modules/m_chghost.c (File Modified) 
+
+
+jilles      2006/01/29 21:42:06 UTC    (20060129-639)
+  Log:
+  Add sno_globaloper.c, remote oper up notices generated from user mode changes.
+  
+
+  Changes:     Modified:
+  +39 -0       trunk/contrib/Makefile.in (File Modified) 
+  + -          trunk/contrib/sno_globaloper.c (File Added) 
+
+
+jilles      2006/01/29 21:26:53 UTC    (20060129-637)
+  Log:
+  Pass along old umodes and snomask in umode_changed hook,
+  changing its parameter type from struct Client *
+  to hook_data_umode_changed *. (For a new client, both
+  are zero.)
+  
+  The IP cloaking module now fully ignores umode changes
+  where +h didn't change.
+  
+
+  Changes:     Modified:
+  +7 -2                trunk/contrib/ip_cloaking.c (File Modified) 
+  +7 -0                trunk/include/hook.h (File Modified) 
+  +18 -4       trunk/src/s_user.c (File Modified) 
+
+
+nenolod     2006/01/29 20:41:26 UTC    (20060129-635)
+  Log:
+  move libcharybdis-provided function initialisation into libcharybdis_init().
+  
+
+  Changes:     Modified:
+  +32 -11      trunk/src/ircd.c (File Modified) 
+
+
+jilles      2006/01/29 20:40:55 UTC    (20060129-633)
+  Log:
+  Make +f notices (local host, global host, global user@host, local class)
+  netwide. Exceeding /quote set max remains local.
+  
+
+  Changes:     Modified:
+  +4 -4                trunk/src/s_conf.c (File Modified) 
+
+
+jilles      2006/01/29 20:32:44 UTC    (20060129-631)
+  Log:
+  Netwide notices about attempts to join juped channels.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/modules/core/m_join.c (File Modified) 
+
+
+jilles      2006/01/29 19:57:17 UTC    (20060129-629)
+  Log:
+  Send server notices about failed oper attempts globally.
+  Successful remote oper attempt notices will be generated
+  from the mode changes.
+  
+
+  Changes:     Modified:
+  +3 -3                trunk/modules/m_challenge.c (File Modified) 
+  +2 -2                trunk/modules/m_oper.c (File Modified) 
+
+
+jilles      2006/01/29 19:56:11 UTC    (20060129-627)
+  Log:
+  Rest of infrastructure for sending server notices globally.
+  Uses a new L_NETWIDE level on sendto_realops_snomask().
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/include/send.h (File Modified) 
+  +31 -4       trunk/src/send.c (File Modified) 
+
+
+jilles      2006/01/29 18:55:28 UTC    (20060129-625)
+  Log:
+  Add general::global_snotices conf option to control
+  whether we send out SNOTEs. Does not do anything yet.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/doc/example.conf (File Modified) 
+  +6 -0                trunk/doc/reference.conf (File Modified) 
+  +1 -0                trunk/include/s_conf.h (File Modified) 
+  +6 -0                trunk/modules/m_info.c (File Modified) 
+  +1 -0                trunk/src/newconf.c (File Modified) 
+  +1 -0                trunk/src/s_conf.c (File Modified) 
+
+
+jilles      2006/01/29 13:47:35 UTC    (20060129-623)
+  Log:
+  Only accept SNOTE from servers.
+  
+
+  Changes:     Modified:
+  +2 -0                trunk/modules/m_snote.c (File Modified) 
+
+
+jilles      2006/01/29 13:25:06 UTC    (20060129-621)
+  Log:
+  Correct parv indices so this actually works.
+  
+
+  Changes:     Modified:
+  +2 -2                trunk/modules/m_snote.c (File Modified) 
+
+
+jilles      2006/01/29 13:16:10 UTC    (20060129-619)
+  Log:
+  s/scan/snote/g
+  
+
+  Changes:     Modified:
+  +3 -3                trunk/modules/m_snote.c (File Modified) 
+
+
+nenolod     2006/01/29 04:51:26 UTC    (20060129-617)
+  Log:
+  Add m_snote.c, SNOTE propagator.
+  
+
+  Changes:     Modified:
+  +86 -0       trunk/modules/Makefile.in (File Modified) 
+  + -          trunk/modules/m_snote.c (File Added) 
+
+
+nenolod     2006/01/29 03:25:01 UTC    (20060129-615)
+  Log:
+  start seeding the 1.1 NEWS file
+  
+
+  Changes:     Modified:
+  +4 -0                trunk/NEWS (File Modified) 
+
+
+nenolod     2006/01/29 03:03:02 UTC    (20060129-613)
+  Log:
+  rename some modules to more descriptive names...
+  
+
+  Changes:     Modified:
+  +2 -131      trunk/contrib/Makefile.in (File Modified) 
+  + -          trunk/contrib/globalconnexit.c (File Deleted) 
+  + -          trunk/contrib/globallineactive.c (File Deleted) 
+  + -          trunk/contrib/sno_farconnect.c (File Added) 
+  + -          trunk/contrib/sno_globalkline.c (File Added) 
+  +1 -120      trunk/modules/Makefile.in (File Modified) 
+  + -          trunk/modules/networknotice.c (File Deleted) 
+  + -          trunk/modules/sno_routing.c (File Added) 
+
+
+jilles      2006/01/28 22:02:18 UTC    (20060128-611)
+  Log:
+  Add networknotice (global netjoin/netsplit notices with counts/reasons).
+  Uses FLAGS2_FLOODDONE bit on servers.
+  
+
+  Changes:     Modified:
+  +3 -0                trunk/include/client.h (File Modified) 
+  +121 -1      trunk/modules/Makefile.in (File Modified) 
+  + -          trunk/modules/networknotice.c (File Added) 
+
+
+jilles      2006/01/28 21:44:33 UTC    (20060128-609)
+  Log:
+  Don't show servers in /trace to nonopers if flatten links is enabled.
+  
+
+  Changes:     Modified:
+  +8 -5                trunk/modules/m_trace.c (File Modified) 
+
+
+jilles      2006/01/28 16:45:46 UTC    (20060128-607)
+  Log:
+  CHGHOST:
+  - use RPL_HOSTHIDDEN numeric also when resetting hostname to original
+  - send back confirmation to source, if local client
+  - send a +s server notice if the source is neither a server nor a service (+S)
+  
+
+  Changes:     Modified:
+  +5 -1                trunk/modules/m_chghost.c (File Modified) 
+
+
+jilles      2006/01/28 16:01:05 UTC    (20060128-605)
+  Log:
+  Use sendto_realops_snomask_from() to make the
+  server notices appear to come from the affected
+  user's server.
+  
+
+  Changes:     Modified:
+  +5 -6                trunk/contrib/globalconnexit.c (File Modified) 
+  +6 -6                trunk/contrib/globallineactive.c (File Modified) 
+
+
+jilles      2006/01/28 16:00:14 UTC    (20060128-603)
+  Log:
+  Add sendto_realops_snomask_from(), allows
+  specification of apparent source server.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/include/send.h (File Modified) 
+  +41 -1       trunk/src/send.c (File Modified) 
+
+
+jilles      2006/01/28 15:30:20 UTC    (20060128-601)
+  Log:
+  Revert r579. Keep host, not orighost in oper up notice.
+  It would be inconsistent to have orighost there, and we
+  don't want to mess up all server notices by putting both
+  host and orighost.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/01/28 15:27:10 UTC    (20060128-599)
+  Log:
+  Include the IP address in operlog/foperlog.
+  
+
+  Changes:     Modified:
+  +10 -8       trunk/modules/m_challenge.c (File Modified) 
+  +8 -6                trunk/modules/m_oper.c (File Modified) 
+
+
+jilles      2006/01/28 15:17:01 UTC    (20060128-597)
+  Log:
+  Call umode_changed hook on oper up.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/01/28 15:13:27 UTC    (20060128-595)
+  Log:
+  Add globalconnexit contrib module, shows remote client connects/exits
+  except netsplits/netjoin on snomask +F.
+  Notice formatting will probably change somewhat still.
+  
+
+  Changes:     Modified:
+  +80 -0       trunk/contrib/Makefile.in (File Modified) 
+  + -          trunk/contrib/globalconnexit.c (File Added) 
+
+
+jilles      2006/01/28 14:54:44 UTC    (20060128-593)
+  Log:
+  Declare snomask_modes[] so modules can provide snomasks.
+  
+
+  Changes:     Modified:
+  +2 -0                trunk/include/snomask.h (File Modified) 
+
+
+jilles      2006/01/28 14:40:10 UTC    (20060128-591)
+  Log:
+  Replace user_signon hook with two new hooks: new_local_user
+  and new_remote_user.
+  These are called right before the user is introduced to the
+  rest of the network.
+  
+
+  Changes:     Modified:
+  +2 -1                trunk/include/hook.h (File Modified) 
+  +2 -0                trunk/modules/core/m_nick.c (File Modified) 
+  +4 -2                trunk/src/hook.c (File Modified) 
+  +2 -3                trunk/src/s_user.c (File Modified) 
+
+
+nenolod     2006/01/28 01:51:45 UTC    (20060128-589)
+  Log:
+  Change requirements from L_ADMIN to L_OPER for SCAN UMODES.
+  
+
+  Changes:     Modified:
+  +2 -2                trunk/modules/m_scan.c (File Modified) 
+
+
+jilles      2006/01/27 19:45:11 UTC    (20060127-587)
+  Log:
+  Update doc/technical/send.txt.
+  
+
+  Changes:     Modified:
+  +91 -131     trunk/doc/technical/send.txt (File Modified) 
+
+
+jilles      2006/01/27 14:44:19 UTC    (20060127-585)
+  Log:
+  Add chantrace and masktrace to help files.
+  
+
+  Changes:     Modified:
+  + -          trunk/help/opers/chantrace (File Added) 
+  +27 -20      trunk/help/opers/index (File Modified) 
+  + -          trunk/help/opers/masktrace (File Added) 
+  +2 -0                trunk/help/opers/operspy (File Modified) 
+
+
+jilles      2006/01/27 14:41:47 UTC    (20060127-583)
+  Log:
+  Port over chantrace from ratbox 2.2 (anfl/androsyn)
+  Shows etrace-like output for all users in a channel,
+  in particular IP addresses.
+  
+
+  Changes:     Modified:
+  +75 -2       trunk/modules/m_etrace.c (File Modified) 
+
+
+jilles      2006/01/27 13:49:21 UTC    (20060127-581)
+  Log:
+  Port over ratbox 2.2 r21727 (anfl):
+  add some logging when we drop servers in places where we only notify opers
+  
+
+  Changes:     Modified:
+  +31 -0       trunk/modules/core/m_server.c (File Modified) 
+
+
+nenolod     2006/01/27 01:00:48 UTC    (20060127-579)
+  Log:
+  display orighost in operup message
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/01/26 17:13:21 UTC    (20060126-577)
+  Log:
+  Add globallineactive contrib module, a hack which can often
+  show k/d/g/x line active for remote clients.
+  
+
+  Changes:     Modified:
+  +52 -0       trunk/contrib/Makefile.in (File Modified) 
+  + -          trunk/contrib/globallineactive.c (File Added) 
+
+
+jilles      2006/01/26 16:34:00 UTC    (20060126-575)
+  Log:
+  Show IP field in the same way as MASKTRACE:
+  "255.255.255.255" if it's unknown (remote TS5 client)
+  and "0" if we or the remote server are purposely
+  hiding it.
+  
+
+  Changes:     Modified:
+  +12 -1       trunk/modules/m_scan.c (File Modified) 
+
+
+jilles      2006/01/26 16:25:22 UTC    (20060126-573)
+  Log:
+  scan umodes:
+  - don't show servers in a global scan
+  - don't show ip if it's spoofed and hide_spoof_ips is enabled
+  
+
+  Changes:     Modified:
+  +4 -1                trunk/modules/m_scan.c (File Modified) 
+
+
+nenolod     2006/01/26 16:06:57 UTC    (20060126-571)
+  Log:
+  Implement SCAN UMODES.
+  
+
+  Changes:     Modified:
+  +3 -0                trunk/include/numeric.h (File Modified) 
+  +128 -2      trunk/modules/m_scan.c (File Modified) 
+  +2 -2                trunk/src/messages.tab (File Modified) 
+
+
+nenolod     2006/01/26 15:06:43 UTC    (20060126-569)
+  Log:
+  more oops
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/modules/m_scan.c (File Modified) 
+
+
+nenolod     2006/01/26 15:06:03 UTC    (20060126-567)
+  Log:
+  parv[0] should be parv[1].
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/modules/m_scan.c (File Modified) 
+
+
+nenolod     2006/01/26 15:05:04 UTC    (20060126-565)
+  Log:
+  another oops
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/modules/m_scan.c (File Modified) 
+
+
+nenolod     2006/01/26 15:00:41 UTC    (20060126-563)
+  Log:
+  fix mistake here
+  
+
+  Changes:     Modified:
+  +2 -2                trunk/modules/m_scan.c (File Modified) 
+
+
+nenolod     2006/01/26 14:58:36 UTC    (20060126-561)
+  Log:
+  framework for scan command
+  
+
+  Changes:     Modified:
+  +113 -0      trunk/modules/Makefile.in (File Modified) 
+  + -          trunk/modules/m_scan.c (File Added) 
+
+
+nenolod     2006/01/26 14:12:14 UTC    (20060126-559)
+  Log:
+  Add TRACEMASK from ratbox 3.0 (r21780 -- androsyn).
+  
+
+  Changes:     Modified:
+  +2 -0                trunk/include/irc_string.h (File Modified) 
+  +157 -1      trunk/modules/m_etrace.c (File Modified) 
+  +129 -90     trunk/src/match.c (File Modified) 
+
+
+nenolod     2006/01/23 15:57:12 UTC    (20060123-557)
+  Log:
+  orighost may live in a different hash bucket (likely the case), lets check it standalone
+  
+
+  Changes:     Modified:
+  +39 -3       trunk/src/hostmask.c (File Modified) 
+
+
+nenolod     2006/01/23 15:11:11 UTC    (20060123-555)
+  Log:
+  SVN didn't check modules/ somehow, hrmm.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/modules/m_kline.c (File Modified) 
+  +6 -6                trunk/modules/m_stats.c (File Modified) 
+
+
+nenolod     2006/01/23 15:01:41 UTC    (20060123-553)
+  Log:
+  Track hostmask entries for client_p->orighost, if available.
+  Not throughly tested, but seems to work fine.
+  
+
+  Changes:     Modified:
+  +8 -4                trunk/include/hostmask.h (File Modified) 
+  +14 -10      trunk/src/hostmask.c (File Modified) 
+
+
+jilles      2006/01/22 19:14:11 UTC    (20060122-549)
+  Log:
+  Pass on SQUIT reasons more.
+  
+
+  Changes:     Modified:
+  +17 -19      trunk/src/client.c (File Modified) 
+
+
+jilles      2006/01/21 17:25:27 UTC    (20060121-543)
+  Log:
+  Use IsOperAdmin() instead of IsAdmin() for admin-only server notices.
+  This way, hidden admins also get them.
+  
+
+  Changes:     Modified:
+  +4 -4                trunk/src/send.c (File Modified) 
+
+
+jilles      2006/01/20 22:26:17 UTC    (20060120-541)
+  Log:
+  From ircd-ratbox 2.2 (r21339 anfl):
+  ms_kill() should be using find_person(), not find_client()
+  otherwise it can generate a core.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/modules/core/m_kill.c (File Modified) 
+
+
+jilles      2006/01/18 22:56:51 UTC    (20060118-539)
+  Log:
+  Add m_error to core_module_table, so it is loaded by default.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/src/modules.c (File Modified) 
+
+
+jilles      2006/01/18 00:28:30 UTC    (20060118-536)
+  Log:
+  comment is a const char *, not char *.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/include/hook.h (File Modified) 
+
+
+jilles      2006/01/18 00:10:02 UTC    (20060118-534)
+  Log:
+  Fix a long standing hybrid 7 bug: when getting a read error
+  on a server, report_error() is called with a %d instead of
+  a %s in the format string ("Lost connection" in +d).
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/client.c (File Modified) 
+
+
+jilles      2006/01/16 17:21:11 UTC    (20060116-532)
+  Log:
+  Clarifications.
+  
+
+  Changes:     Modified:
+  +12 -7       trunk/doc/technical/capab.txt (File Modified) 
+
+
+nenolod     2006/01/16 04:46:11 UTC    (20060116-530)
+  Log:
+  Add document describing capabilities and what they mean.
+  
+
+  Changes:     Modified:
+  + -          trunk/doc/technical/capab.txt (File Added) 
+
+
+jilles      2006/01/16 01:19:24 UTC    (20060116-528)
+  Log:
+  Change client_exit hook to pass all exit_client() parameters.
+  
+
+  Changes:     Modified:
+  +8 -0                trunk/include/hook.h (File Modified) 
+  +6 -1                trunk/src/client.c (File Modified) 
+
+
+jilles      2006/01/15 21:51:42 UTC    (20060115-526)
+  Log:
+  Add client_exit hook, called in exit_client() for all
+  clients of all types, except clients exiting because
+  of netsplits (QS). The only thing done before it is
+  marking the client as "closing" (to prevent
+  recursion).
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/include/hook.h (File Modified) 
+  +2 -0                trunk/src/client.c (File Modified) 
+  +2 -0                trunk/src/hook.c (File Modified) 
+
+
+jilles      2006/01/15 21:06:36 UTC    (20060115-524)
+  Log:
+  Improve the code that calculates the nnnS nnnC counts
+  in RPL_TRACESERVER.
+  
+  From ircd-ratbox RATBOX_2_2 r21650 and r21678 (anfl/jilles).
+  
+
+  Changes:     Modified:
+  +43 -36      trunk/modules/m_trace.c (File Modified) 
+
+
+jilles      2006/01/15 20:55:27 UTC    (20060115-522)
+  Log:
+  Add server_eob hook.
+  Planning to use this for netsplit/join notices.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/include/hook.h (File Modified) 
+  +2 -0                trunk/modules/m_pong.c (File Modified) 
+  +2 -0                trunk/src/hook.c (File Modified) 
+
+
+jilles      2006/01/15 20:01:51 UTC    (20060115-520)
+  Log:
+  Default motd: ircd-ratbox -> charybdis
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/doc/ircd.motd (File Modified) 
+
+
+jilles      2006/01/15 19:35:03 UTC    (20060115-518)
+  Log:
+  Shouldn't use the UMODE_ALL alias here; instead UMODE_SERVNOTICE.
+  
+
+  Changes:     Modified:
+  +4 -4                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/01/15 19:12:28 UTC    (20060115-516)
+  Log:
+  - Remove obsolete EOB help file
+  - Document snomask in the help files
+  - Update indexes
+  
+
+  Changes:     Modified:
+  + -          trunk/help/opers/eob (File Deleted) 
+  +13 -12      trunk/help/opers/index (File Modified) 
+  +1 -13       trunk/help/opers/umode (File Modified) 
+  +7 -7                trunk/help/users/index (File Modified) 
+
+
+nenolod     2006/01/15 17:50:43 UTC    (20060115-514)
+  Log:
+  Bail if snomask to parse is not given. Pointy hat to myself.
+  
+
+  Changes:     Modified:
+  +3 -0                trunk/src/snomask.c (File Modified) 
+
+
+gxti        2006/01/15 17:48:44 UTC    (20060115-512)
+  Log:
+  Remove m_flags from autoconf
+  
+
+  Changes:     Modified:
+  +0 -1                trunk/contrib/Makefile.in (File Modified) 
+
+
+nenolod     2006/01/15 17:44:55 UTC    (20060115-510)
+  Log:
+  remove m_flags
+  
+
+  Changes:     Modified:
+  + -          trunk/contrib/m_flags.c (File Deleted) 
+
+
+jilles      2006/01/15 17:22:19 UTC    (20060115-508)
+  Log:
+  If +s is in oper_only_umodes, clear snomask on deoper.
+  
+
+  Changes:     Modified:
+  +5 -0                trunk/src/s_user.c (File Modified) 
+
+
+gxti        2006/01/15 17:16:50 UTC    (20060115-506)
+  Log:
+  Fix incorrect default settings for nicklen and topiclen in ./configure help entries.
+  
+
+  Changes:     Modified:
+  +2 -2                trunk/configure (File Modified) 
+  +2 -2                trunk/configure.ac (File Modified) 
+
+
+jilles      2006/01/15 17:15:56 UTC    (20060115-504)
+  Log:
+  Remove the old server notice umodes.
+  Default oper only umodes is now +s.
+  Please make sure all remaining umodes still work.
+  
+
+  Changes:     Modified:
+  +3 -21       trunk/include/client.h (File Modified) 
+  +0 -12       trunk/src/newconf.c (File Modified) 
+  +1 -1                trunk/src/s_conf.c (File Modified) 
+  +12 -12      trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/01/15 17:00:27 UTC    (20060115-502)
+  Log:
+  operator::flags nick_changes now controls +n snomask instead of +n umode.
+  
+
+  Changes:     Modified:
+  +8 -8                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/01/15 16:53:16 UTC    (20060115-500)
+  Log:
+  Move down h_umode_changed hook call after umode allowed checks
+  (so it will not see +a if someone tries to set it but is not
+  allowed to).
+  
+
+  Changes:     Modified:
+  +2 -3                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/01/15 16:40:33 UTC    (20060115-498)
+  Log:
+  Move over non-+s server notices (hopefully, all of them).
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/contrib/spy_admin_notice.c (File Modified) 
+  +1 -1                trunk/contrib/spy_info_notice.c (File Modified) 
+  +1 -1                trunk/contrib/spy_links_notice.c (File Modified) 
+  +1 -1                trunk/contrib/spy_motd_notice.c (File Modified) 
+  +3 -3                trunk/contrib/spy_stats_notice.c (File Modified) 
+  +1 -1                trunk/contrib/spy_stats_p_notice.c (File Modified) 
+  +2 -2                trunk/contrib/spy_trace_notice.c (File Modified) 
+  +1 -1                trunk/contrib/spy_whois_notice.c (File Modified) 
+  +1 -1                trunk/contrib/spy_whois_notice_global.c (File Modified) 
+  +2 -2                trunk/libcharybdis/event.c (File Modified) 
+  +2 -2                trunk/modules/core/m_join.c (File Modified) 
+  +1 -1                trunk/modules/core/m_kill.c (File Modified) 
+  +3 -3                trunk/modules/core/m_message.c (File Modified) 
+  +11 -11      trunk/modules/core/m_nick.c (File Modified) 
+  +2 -2                trunk/modules/core/m_server.c (File Modified) 
+  +1 -1                trunk/modules/core/m_sjoin.c (File Modified) 
+  +1 -1                trunk/modules/m_post.c (File Modified) 
+  +1 -1                trunk/modules/m_services.c (File Modified) 
+  +2 -2                trunk/src/channel.c (File Modified) 
+  +3 -3                trunk/src/client.c (File Modified) 
+  +1 -1                trunk/src/hash.c (File Modified) 
+  +5 -5                trunk/src/s_conf.c (File Modified) 
+  +2 -2                trunk/src/s_log.c (File Modified) 
+  +4 -4                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/01/15 16:18:59 UTC    (20060115-496)
+  Log:
+  Rename SNO_SPAMBOT to SNO_BOTS and add SNO_OPERSPY.
+  
+
+  Changes:     Modified:
+  +2 -1                trunk/include/snomask.h (File Modified) 
+  +2 -2                trunk/src/snomask.c (File Modified) 
+
+
+jilles      2006/01/15 16:08:28 UTC    (20060115-494)
+  Log:
+  s/sendto_realops_flags(UMODE_ALL,/sendto_realops_snomask(SNO_GENERAL,/
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/contrib/example_module.c (File Modified) 
+  +2 -2                trunk/include/ircd_defs.h (File Modified) 
+  +6 -6                trunk/modules/core/m_error.c (File Modified) 
+  +1 -1                trunk/modules/core/m_join.c (File Modified) 
+  +2 -2                trunk/modules/core/m_kill.c (File Modified) 
+  +1 -1                trunk/modules/core/m_message.c (File Modified) 
+  +1 -1                trunk/modules/core/m_mode.c (File Modified) 
+  +14 -14      trunk/modules/core/m_nick.c (File Modified) 
+  +18 -18      trunk/modules/core/m_server.c (File Modified) 
+  +1 -1                trunk/modules/core/m_sjoin.c (File Modified) 
+  +1 -1                trunk/modules/core/m_squit.c (File Modified) 
+  +4 -4                trunk/modules/m_challenge.c (File Modified) 
+  +4 -4                trunk/modules/m_dline.c (File Modified) 
+  +13 -13      trunk/modules/m_gline.c (File Modified) 
+  +5 -5                trunk/modules/m_kline.c (File Modified) 
+  +2 -2                trunk/modules/m_oper.c (File Modified) 
+  +1 -1                trunk/modules/m_pong.c (File Modified) 
+  +13 -13      trunk/modules/m_rehash.c (File Modified) 
+  +4 -4                trunk/modules/m_resv.c (File Modified) 
+  +16 -16      trunk/modules/m_set.c (File Modified) 
+  +3 -3                trunk/modules/m_svinfo.c (File Modified) 
+  +6 -6                trunk/modules/m_xline.c (File Modified) 
+  +1 -1                trunk/src/adns.c (File Modified) 
+  +2 -2                trunk/src/channel.c (File Modified) 
+  +1 -1                trunk/src/listener.c (File Modified) 
+  +1 -1                trunk/src/s_auth.c (File Modified) 
+  +15 -15      trunk/src/s_conf.c (File Modified) 
+  +3 -3                trunk/src/s_user.c (File Modified) 
+  +7 -7                trunk/src/send.c (File Modified) 
+
+
+jilles      2006/01/15 15:34:12 UTC    (20060115-492)
+  Log:
+  On oper up:
+  - set +s snomask if +s umode set but no snomasks
+  - put numerics in more logical order
+  
+
+  Changes:     Modified:
+  +3 -1                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/01/15 15:12:39 UTC    (20060115-490)
+  Log:
+  parse_snobuf_to_mask(): default to + at start
+  allows stuff like /mode jilles +s C
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/snomask.c (File Modified) 
+
+
+jilles      2006/01/15 15:04:34 UTC    (20060115-488)
+  Log:
+  Changes to user_mode() snomask handling.
+  - show snomask (if not 0) on /mode <nick>
+  - show snomask once at the end if +s/-s used
+  - only parse 1 parameter for umode changes
+  - don't crash on /mode <nick> +s
+  - /mode <nick> -s clears snomask, doesn't use parameter
+  - set umode +s iff snomask is not 0
+  - snomask is not propagated, but umode +s is
+  
+
+  Changes:     Modified:
+  +97 -72      trunk/src/s_user.c (File Modified) 
+
+
+nenolod     2006/01/15 10:36:32 UTC    (20060115-486)
+  Log:
+  Convert some messages over to snomask.
+  
+
+  Changes:     Modified:
+  +29 -29      trunk/src/client.c (File Modified) 
+  +2 -2                trunk/src/ircd.c (File Modified) 
+  +13 -13      trunk/src/modules.c (File Modified) 
+  +1 -1                trunk/src/newconf.c (File Modified) 
+  +5 -5                trunk/src/parse.c (File Modified) 
+  +1 -1                trunk/src/restart.c (File Modified) 
+  +4 -4                trunk/src/s_newconf.c (File Modified) 
+  +11 -11      trunk/src/s_serv.c (File Modified) 
+
+
+nenolod     2006/01/15 10:28:42 UTC    (20060115-484)
+  Log:
+  include snomask.h from client.h
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/include/client.h (File Modified) 
+
+
+nenolod     2006/01/15 10:28:18 UTC    (20060115-482)
+  Log:
+  make the snomask parser display snomasks properly, and make sure snomasks are applied to o:lines properly
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/src/newconf.c (File Modified) 
+  +2 -1                trunk/src/snomask.c (File Modified) 
+
+
+nenolod     2006/01/15 10:17:52 UTC    (20060115-480)
+  Log:
+  should start with +, not \0. Whoops. :)
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/snomask.c (File Modified) 
+
+
+nenolod     2006/01/15 10:14:17 UTC    (20060115-478)
+  Log:
+  core snomask support.
+  
+
+  Changes:     Modified:
+  +3 -0                trunk/doc/example.conf (File Modified) 
+  +2 -0                trunk/include/client.h (File Modified) 
+  +2 -0                trunk/include/numeric.h (File Modified) 
+  +2 -0                trunk/include/s_newconf.h (File Modified) 
+  +63 -0       trunk/include/send.h (File Modified) 
+  + -          trunk/include/snomask.h (File Added) 
+  +1 -0                trunk/src/Makefile.in (File Modified) 
+  +1 -1                trunk/src/messages.tab (File Modified) 
+  +8 -0                trunk/src/newconf.c (File Modified) 
+  +12 -0       trunk/src/s_user.c (File Modified) 
+  +235 -0      trunk/src/send.c (File Modified) 
+  + -          trunk/src/snomask.c (File Added) 
+
+
+nenolod     2006/01/15 05:32:44 UTC    (20060115-474)
+  Log:
+  add a blank line after the license info.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/CREDITS (File Modified) 
+
+
+jilles      2006/01/14 19:59:18 UTC    (20060114-472)
+  Log:
+  Extend copyright to 2006.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/doc/sgml/oper-guide/charybdis-oper-guide.sgml (File Modified) 
+
+
+jilles      2006/01/14 19:56:24 UTC    (20060114-470)
+  Log:
+  - Fix up book id.
+  - Give some credit to dancer-ircd/hyperion, Andrew Suffield.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/doc/sgml/oper-guide/charybdis-oper-guide.sgml (File Modified) 
+  +5 -0                trunk/doc/sgml/oper-guide/intro.sgml (File Modified) 
+
+
+jilles      2006/01/14 19:52:16 UTC    (20060114-468)
+  Log:
+  Add oper privileges document.
+  
+
+  Changes:     Modified:
+  +162 -0      trunk/doc/sgml/oper-guide/charybdis-oper-guide.sgml (File Modified) 
+  + -          trunk/doc/sgml/oper-guide/oprivs.sgml (File Added) 
+
+
+jilles      2006/01/14 18:45:57 UTC    (20060114-466)
+  Log:
+  Capitalize message names in services shortcuts (for consistency).
+  
+
+  Changes:     Modified:
+  +6 -6                trunk/modules/m_sshortcut.c (File Modified) 
+
+
+jilles      2006/01/13 16:53:35 UTC    (20060113-464)
+  Log:
+  Remove C++ comment.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/patricia.c (File Modified) 
+
+
+jilles      2006/01/13 13:45:56 UTC    (20060113-462)
+  Log:
+  Remove obsolete 'nextconnect' variable.
+  
+
+  Changes:     Modified:
+  +0 -1                trunk/include/ircd.h (File Modified) 
+  +0 -2                trunk/src/client.c (File Modified) 
+  +0 -1                trunk/src/ircd.c (File Modified) 
+
+
+jilles      2006/01/13 13:02:54 UTC    (20060113-460)
+  Log:
+  Remove this remnant of the hybrid 6 ziplinks implementation.
+  
+
+  Changes:     Modified:
+  + -          trunk/include/s_zip.h (File Deleted) 
+
+
+jilles      2006/01/09 16:05:47 UTC    (20060109-458)
+  Log:
+  Make clone limiting work on orighost, not host (so it
+  looks through services cloaks). Lightly tested, please
+  test/review.
+  
+
+  Changes:     Modified:
+  +2 -0                trunk/modules/m_chghost.c (File Modified) 
+  +1 -1                trunk/src/client.c (File Modified) 
+  +1 -1                trunk/src/s_conf.c (File Modified) 
+
+
+jilles      2006/01/09 15:51:02 UTC    (20060109-456)
+  Log:
+  Don't forget to link me_realhost() into the command hash.
+  
+  Pointy hat to: myself
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/modules/m_chghost.c (File Modified) 
+
+
+jilles      2006/01/09 14:46:59 UTC    (20060109-454)
+  Log:
+  It's call_hook, not hook_call.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/01/09 14:45:36 UTC    (20060109-452)
+  Log:
+  Add unreject help file.
+  
+
+  Changes:     Modified:
+  + -          trunk/help/opers/unreject (File Added) 
+
+
+jilles      2006/01/09 14:41:41 UTC    (20060109-450)
+  Log:
+  Link the all-important 42 module to the build :P
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/contrib/Makefile.in (File Modified) 
+
+
+jilles      2006/01/08 19:12:10 UTC    (20060108-448)
+  Log:
+  Mention /rehash help.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/help/opers/rehash (File Modified) 
+
+
+nenolod     2006/01/06 14:56:49 UTC    (20060106-446)
+  Log:
+  Add h_user_signon hook.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/include/hook.h (File Modified) 
+  +2 -0                trunk/src/hook.c (File Modified) 
+  +4 -0                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/01/06 02:30:23 UTC    (20060106-444)
+  Log:
+  Oops, forgot to set orighost for remote client introductions.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/modules/core/m_nick.c (File Modified) 
+
+
+jilles      2006/01/06 01:40:44 UTC    (20060106-442)
+  Log:
+  Use TS6 forms in services shortcuts, if possible.
+  
+
+  Changes:     Modified:
+  +3 -3                trunk/modules/m_sshortcut.c (File Modified) 
+
+
+jilles      2006/01/06 01:31:19 UTC    (20060106-440)
+  Log:
+  - Start out default_umodes conf entry from the empty set instead of +i.
+  - Move oper_only_umodes check to where default_umodes is used, as
+    oper_only_umodes may not be set yet while we're reading the conf.
+  
+
+  Changes:     Modified:
+  +6 -7                trunk/src/newconf.c (File Modified) 
+  +1 -1                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/01/06 01:00:44 UTC    (20060106-438)
+  Log:
+  Move #define HIDE_SPOOF_IPS to general::hide_spoof_ips conf option.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/doc/example.conf (File Modified) 
+  +7 -0                trunk/doc/reference.conf (File Modified) 
+  +0 -7                trunk/include/config.h.dist (File Modified) 
+  +1 -0                trunk/include/s_conf.h (File Modified) 
+  +6 -0                trunk/modules/m_info.c (File Modified) 
+  +9 -18       trunk/src/client.c (File Modified) 
+  +1 -0                trunk/src/newconf.c (File Modified) 
+  +1 -0                trunk/src/s_conf.c (File Modified) 
+
+
+jilles      2006/01/06 00:14:18 UTC    (20060106-436)
+  Log:
+  - Allow NULL target_ip in show_ip() (indicates message is being
+    sent to local opers)
+  - Add show_ip_conf(), like show_ip() but for a CONF_CLIENT
+    confitem
+  - Using these, remove all uses of #define HIDE_SPOOF_IPS except
+    those in src/client.c
+  
+  From ratbox 2.2 svn (anfl)
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/include/client.h (File Modified) 
+  +21 -2       trunk/src/client.c (File Modified) 
+  +2 -4                trunk/src/hostmask.c (File Modified) 
+  +1 -5                trunk/src/s_conf.c (File Modified) 
+  +4 -8                trunk/src/s_user.c (File Modified) 
+
+
+nenolod     2006/01/06 00:01:30 UTC    (20060106-434)
+  Log:
+  Fire off events properly.
+  
+
+  Changes:     Modified:
+  +7 -3                trunk/src/s_user.c (File Modified) 
+
+
+nenolod     2006/01/05 23:42:13 UTC    (20060105-432)
+  Log:
+  make sure modules which depend on umode information get the message upon connection (oops)
+  
+
+  Changes:     Modified:
+  +3 -0                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/01/05 23:33:33 UTC    (20060105-430)
+  Log:
+  Replace usage of HIDE_SPOOF_IPS with show_ip() in etrace.
+  From ratbox 2.2 svn.
+  
+
+  Changes:     Modified:
+  +3 -7                trunk/modules/m_etrace.c (File Modified) 
+
+
+nenolod     2006/01/05 23:27:27 UTC    (20060105-428)
+  Log:
+  Replace silly `default_invisible' option with more versatile default_umodes.
+  
+
+  Changes:     Modified:
+  +2 -2                trunk/Makefile.in (File Modified) 
+  +12 -1       trunk/doc/example.conf (File Modified) 
+  +14 -7       trunk/doc/reference.conf (File Modified) 
+  +2 -4                trunk/include/s_conf.h (File Modified) 
+  +0 -6                trunk/modules/m_info.c (File Modified) 
+  +4 -0                trunk/src/modules.c (File Modified) 
+  +41 -1       trunk/src/newconf.c (File Modified) 
+  +2 -2                trunk/src/s_conf.c (File Modified) 
+  +3 -4                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2006/01/02 14:30:45 UTC    (20060102-426)
+  Log:
+  Add temporary nick resvs with the proper duration,
+  not 60 times too long.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/modules/m_resv.c (File Modified) 
+
+
+jilles      2006/01/02 14:21:31 UTC    (20060102-424)
+  Log:
+  Add kick on split riding. See reference.conf for more details.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/doc/example.conf (File Modified) 
+  +16 -0       trunk/doc/reference.conf (File Modified) 
+  +1 -0                trunk/include/s_conf.h (File Modified) 
+  +56 -0       trunk/modules/core/m_sjoin.c (File Modified) 
+  +6 -0                trunk/modules/m_info.c (File Modified) 
+  +1 -0                trunk/src/newconf.c (File Modified) 
+  +1 -0                trunk/src/s_conf.c (File Modified) 
+
+
+nenolod     2005/12/27 06:07:24 UTC    (20051227-422)
+  Log:
+  New credits, denoting GXTi as being on the core team.
+  
+
+  Changes:     Modified:
+  +16 -5       trunk/CREDITS (File Modified) 
+
+
+nenolod     2005/12/24 05:50:12 UTC    (20051224-420)
+  Log:
+  better cloaking algorithm
+  
+
+  Changes:     Modified:
+  +14 -7       trunk/contrib/ip_cloaking.c (File Modified) 
+
+
+nenolod     2005/12/23 21:43:09 UTC    (20051223-418)
+  Log:
+  don't do redundant bitshifting.
+  
+
+  Changes:     Modified:
+  +2 -2                trunk/contrib/ip_cloaking.c (File Modified) 
+
+
+jilles      2005/12/23 21:15:41 UTC    (20051223-416)
+  Log:
+  Add ip_cloaking.so.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/contrib/Makefile.in (File Modified) 
+
+
+jilles      2005/12/23 21:15:25 UTC    (20051223-414)
+  Log:
+  Set the DynSpoof flag properly.
+  
+
+  Changes:     Modified:
+  +4 -0                trunk/contrib/ip_cloaking.c (File Modified) 
+
+
+nenolod     2005/12/23 08:11:04 UTC    (20051223-412)
+  Log:
+  first go at an ip_cloaking implementation for charybdis.
+  
+
+  Changes:     Modified:
+  + -          trunk/contrib/ip_cloaking.c (File Added) 
+
+
+nenolod     2005/12/23 07:25:47 UTC    (20051223-410)
+  Log:
+  Add libcharybdis to contrib/ includes.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/contrib/Makefile.in (File Modified) 
+
+
+nenolod     2005/12/23 02:40:07 UTC    (20051223-408)
+  Log:
+  add h_umode_changed hook for modules that provide usermodes.
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/include/hook.h (File Modified) 
+  +2 -1                trunk/src/hook.c (File Modified) 
+  +3 -0                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2005/12/19 16:52:45 UTC    (20051219-406)
+  Log:
+  Show quiets in /stats z.
+  
+
+  Changes:     Modified:
+  +15 -10      trunk/src/s_stats.c (File Modified) 
+
+
+nenolod     2005/12/19 15:33:16 UTC    (20051219-404)
+  Log:
+  remove old ratbox-services stuff from configure. pointed out with a pointy stick via 
+  
+
+  Changes:     Modified:
+  +0 -12       trunk/configure (File Modified) 
+  +0 -9                trunk/configure.ac (File Modified) 
+  +0 -3                trunk/include/setup.h.in (File Modified) 
+
+
+nenolod     2005/12/19 15:30:32 UTC    (20051219-402)
+  Log:
+  change various buffer sizes to = topiclen.
+  
+
+  Changes:     Modified:
+  +3 -4                trunk/include/ircd_defs.h (File Modified) 
+
+
+jon         2005/12/12 19:32:18 UTC    (20051212-400)
+  Log:
+  - Partial commit test, partial ego strokage ;)
+  
+
+  Changes:     Modified:
+  +2 -1                trunk/CREDITS (File Modified) 
+
+
+nenolod     2005/12/12 18:12:46 UTC    (20051212-398)
+  Log:
+  More kqueue corrections.
+
+  Changes:     Modified:
+  +8 -2                trunk/libcharybdis/kqueue.c (File Modified) 
+
+
+nenolod     2005/12/12 06:27:59 UTC    (20051212-396)
+  Log:
+  We want to use EV_ENABLE to enable tracking, as per the kqueue manpage.
+  Not sure why this wasn't this way to begin with.
+  
+
+  Changes:     Modified:
+  +3 -3                trunk/libcharybdis/kqueue.c (File Modified) 
+
+
+jilles      2005/12/11 16:39:52 UTC    (20051211-394)
+  Log:
+  example.conf tweaks:
+  Comment out serverinfo::vhost, serverinfo::vhost6 and listen::host,
+  most people do not need this.
+  Enable serverinfo::hub.
+  
+
+  Changes:     Modified:
+  +14 -11      trunk/doc/example.conf (File Modified) 
+
+
+nenolod     2005/12/10 04:37:54 UTC    (20051210-392)
+  Log:
+  Match properly, was backwards before, making connect "*.mask" { } blocks not work properly.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/s_serv.c (File Modified) 
+
+
+nenolod     2005/12/07 18:46:56 UTC    (20051207-390)
+  Log:
+  header include changes
+  
+
+  Changes:     Modified:
+  +1 -20       trunk/libcharybdis/devpoll.c (File Modified) 
+  +1 -21       trunk/libcharybdis/epoll.c (File Modified) 
+  +1 -19       trunk/libcharybdis/kqueue.c (File Modified) 
+  +1 -18       trunk/libcharybdis/poll.c (File Modified) 
+  +2 -3                trunk/libcharybdis/ports.c (File Modified) 
+  +1 -21       trunk/libcharybdis/select.c (File Modified) 
+
+
+nenolod     2005/12/07 16:34:40 UTC    (20051207-388)
+  Log:
+  s/ilog/libcharybdis_{die,log,restart}/g
+  
+
+  Changes:     Modified:
+  +7 -9                trunk/libcharybdis/balloc.c (File Modified) 
+  +4 -29       trunk/libcharybdis/commio.c (File Modified) 
+  +5 -8                trunk/libcharybdis/devpoll.c (File Modified) 
+  +4 -4                trunk/libcharybdis/epoll.c (File Modified) 
+  +2 -2                trunk/libcharybdis/kqueue.c (File Modified) 
+  +3 -0                trunk/libcharybdis/libcharybdis.h (File Modified) 
+  +3 -14       trunk/libcharybdis/memory.c (File Modified) 
+  +3 -3                trunk/libcharybdis/ports.c (File Modified) 
+
+
+nenolod     2005/12/07 16:21:24 UTC    (20051207-386)
+  Log:
+  Use the right callbacks in the function code.
+
+  Changes:     Modified:
+  +2 -2                trunk/libcharybdis/libcharybdis.c (File Modified) 
+
+
+nenolod     2005/12/07 16:18:43 UTC    (20051207-384)
+  Log:
+  More work, it builds again!
+  
+
+  Changes:     Modified:
+  +1 -0                trunk/libcharybdis/Makefile.in (File Modified) 
+  +138 -4      trunk/libcharybdis/commio.c (File Modified) 
+  + -          trunk/libcharybdis/libcharybdis.c (File Added) 
+  + -          trunk/libcharybdis/libcharybdis.h (File Added) 
+
+
+nenolod     2005/12/07 15:15:59 UTC    (20051207-382)
+  Log:
+  Move some stuff around.
+  
+
+  Changes:     Modified:
+  + -          trunk/include/memory.h (File Deleted) 
+  + -          trunk/include/tools.h (File Deleted) 
+  +8 -1                trunk/libcharybdis/Makefile.in (File Modified) 
+  + -          trunk/libcharybdis/memory.c (File Added) 
+  + -          trunk/libcharybdis/memory.h (File Added) 
+  + -          trunk/libcharybdis/snprintf.c (File Added) 
+  + -          trunk/libcharybdis/tools.c (File Added) 
+  + -          trunk/libcharybdis/tools.h (File Added) 
+  +1000 -1062  trunk/modules/.depend (File Modified) 
+  +421 -455    trunk/src/.depend (File Modified) 
+  +0 -1191     trunk/src/Makefile.in (File Modified) 
+  + -          trunk/src/memory.c (File Deleted) 
+  + -          trunk/src/snprintf.c (File Deleted) 
+  + -          trunk/src/tools.c (File Deleted) 
+
+
+nenolod     2005/12/07 15:08:37 UTC    (20051207-380)
+  Log:
+  move more headers into libcharybdis
+
+  Changes:     Modified:
+  + -          trunk/include/balloc.h (File Deleted) 
+  + -          trunk/include/event.h (File Deleted) 
+  + -          trunk/libcharybdis/balloc.h (File Added) 
+  + -          trunk/libcharybdis/event.h (File Added) 
+  +924 -1020   trunk/modules/.depend (File Modified) 
+  +327 -406    trunk/src/.depend (File Modified) 
+
+
+nenolod     2005/12/07 15:06:15 UTC    (20051207-378)
+  Log:
+  balloc, events -> libcharybdis
+
+  Changes:     Modified:
+  +1 -1                trunk/libcharybdis/Makefile.in (File Modified) 
+  + -          trunk/libcharybdis/balloc.c (File Added) 
+  + -          trunk/libcharybdis/event.c (File Added) 
+  +0 -1008     trunk/src/Makefile.in (File Modified) 
+  + -          trunk/src/balloc.c (File Deleted) 
+  + -          trunk/src/event.c (File Deleted) 
+
+
+nenolod     2005/12/07 15:00:41 UTC    (20051207-376)
+  Log:
+  More fun
+
+  Changes:     Modified:
+  + -          trunk/include/commio.h (File Deleted) 
+  + -          trunk/include/linebuf.h (File Deleted) 
+  + -          trunk/libcharybdis/commio.h (File Added) 
+  + -          trunk/libcharybdis/linebuf.h (File Added) 
+  +1644 -530   trunk/modules/.depend (File Modified) 
+  +1 -1                trunk/modules/Makefile.in (File Modified) 
+  +720 -284    trunk/src/.depend (File Modified) 
+
+
+nenolod     2005/12/07 14:54:12 UTC    (20051207-374)
+  Log:
+  Makefile reworking -- moving libcharybdis headers into proper location.
+
+  Changes:     Modified:
+  +1 -1                trunk/adns/Makefile.in (File Modified) 
+  +1 -1                trunk/src/Makefile.in (File Modified) 
+
+
+nenolod     2005/12/07 14:47:30 UTC    (20051207-372)
+  Log:
+  Document proposed authdaemon protocol.
+
+  Changes:     Modified:
+  + -          trunk/authdaemon/protocol.txt (File Added) 
+
+
+nenolod     2005/12/07 14:42:23 UTC    (20051207-370)
+  Log:
+  Makefile oops
+
+  Changes:     Modified:
+  +2 -2                trunk/libcharybdis/Makefile.in (File Modified) 
+
+
+nenolod     2005/12/07 14:38:33 UTC    (20051207-368)
+  Log:
+  Remove dead makefile from generation
+
+  Changes:     Modified:
+  +1 -2                trunk/configure (File Modified) 
+  +0 -1                trunk/configure.ac (File Modified) 
+
+
+nenolod     2005/12/07 14:36:56 UTC    (20051207-366)
+  Log:
+  libcharybdisIO -> libcharybdis
+
+  Changes:     Modified:
+  +1 -1                trunk/src/Makefile.in (File Modified) 
+
+
+nenolod     2005/12/07 14:35:50 UTC    (20051207-364)
+  Log:
+  More restructuring.
+
+  Changes:     Modified:
+  + -          trunk/libcharybdis/Makefile.in (File Added) 
+  + -          trunk/libcharybdis/commio.c (File Added) 
+  + -          trunk/libcharybdis/devpoll.c (File Added) 
+  + -          trunk/libcharybdis/epoll.c (File Added) 
+  + -          trunk/libcharybdis/io/ (File Deleted) 
+  + -          trunk/libcharybdis/kqueue.c (File Added) 
+  + -          trunk/libcharybdis/linebuf.c (File Added) 
+  + -          trunk/libcharybdis/log/ (File Deleted) 
+  + -          trunk/libcharybdis/poll.c (File Added) 
+  + -          trunk/libcharybdis/ports.c (File Added) 
+  + -          trunk/libcharybdis/select.c (File Added) 
+
+
+nenolod     2005/12/07 14:33:31 UTC    (20051207-362)
+  Log:
+  Blah kill makefile
+
+  Changes:     Modified:
+  + -          trunk/libcharybdis/Makefile.in (File Deleted) 
+
+
+nenolod     2005/12/07 14:33:10 UTC    (20051207-360)
+  Log:
+  Blah kill makefile
+
+  Changes:     Modified:
+  +2 -4                trunk/libcharybdis/io/Makefile.in (File Modified) 
+
+
+nenolod     2005/12/06 19:52:25 UTC    (20051206-358)
+  Log:
+  add authdaemon dir for later hacking
+  
+
+  Changes:     Modified:
+  + -          trunk/authdaemon/ (File Added) 
+
+
+nenolod     2005/12/06 19:49:25 UTC    (20051206-356)
+  Log:
+  linebuf -> libcharybdisIO
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/libcharybdis/io/Makefile.in (File Modified) 
+  + -          trunk/libcharybdis/io/linebuf.c (File Added) 
+  + -          trunk/libcharybdis/log/ (File Added) 
+  + -          trunk/libcharybdis/log/Makefile.in (File Added) 
+  +0 -687      trunk/src/Makefile.in (File Modified) 
+  + -          trunk/src/linebuf.c (File Deleted) 
+
+
+nenolod     2005/12/06 19:47:43 UTC    (20051206-354)
+  Log:
+  Solaris 10 I/O ports support
+
+  Changes:     Modified:
+  + -          trunk/libcharybdis/io/ports.c (File Added) 
+
+
+nenolod     2005/12/06 19:15:13 UTC    (20051206-352)
+  Log:
+  libcharybdis stuff
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/Makefile.in (File Modified) 
+  +3 -1                trunk/configure (File Modified) 
+  +133 -10     trunk/configure.ac (File Modified) 
+  + -          trunk/libcharybdis/ (File Added) 
+  + -          trunk/libcharybdis/Makefile.in (File Added) 
+  + -          trunk/libcharybdis/io/ (File Added) 
+  +4 -2                trunk/libcharybdis/io/Makefile.in (File Modified) 
+  +2 -3                trunk/src/Makefile.in (File Modified) 
+  + -          trunk/src/io/ (File Deleted) 
+
+
+nenolod     2005/12/06 18:57:28 UTC    (20051206-350)
+  Log:
+  split IO stuff into libcharybdisIO.
+  
+
+  Changes:     Modified:
+  + -          trunk/src/commio.c (File Deleted) 
+  + -          trunk/src/devpoll.c (File Deleted) 
+  + -          trunk/src/epoll.c (File Deleted) 
+  + -          trunk/src/io/ (File Added) 
+  + -          trunk/src/io/Makefile.in (File Added) 
+  + -          trunk/src/io/commio.c (File Added) 
+  + -          trunk/src/io/devpoll.c (File Added) 
+  + -          trunk/src/io/epoll.c (File Added) 
+  + -          trunk/src/io/kqueue.c (File Added) 
+  + -          trunk/src/io/poll.c (File Added) 
+  + -          trunk/src/io/select.c (File Added) 
+  + -          trunk/src/kqueue.c (File Deleted) 
+  + -          trunk/src/poll.c (File Deleted) 
+  + -          trunk/src/select.c (File Deleted) 
+
+
+nenolod     2005/12/06 18:51:20 UTC    (20051206-348)
+  Log:
+  Version bump: 1.1.0
+  
+
+  Changes:     Modified:
+  +86 -155     trunk/configure (File Modified) 
+  +1 -1                trunk/configure.ac (File Modified) 
+
+
+jilles      2005/12/04 01:56:31 UTC    (20051204-346)
+  Log:
+  Remove mentions of mkkeypair/cryptlinks.
+  
+
+  Changes:     Modified:
+  +1 -3                trunk/doc/challenge.txt (File Modified) 
+
+
+jilles      2005/12/02 17:57:29 UTC    (20051202-344)
+  Log:
+  Clarify serverinfo{} description.
+  
+
+  Changes:     Modified:
+  +13 -5       trunk/doc/sgml/oper-guide/config.sgml (File Modified) 
+
+
+jilles      2005/12/02 17:41:44 UTC    (20051202-342)
+  Log:
+  Some hyperion1->charybdis changes, and fixes in charybdis descriptions.
+  
+
+  Changes:     Modified:
+  +14 -41      trunk/doc/sgml/oper-guide/commands.sgml (File Modified) 
+
+
+jilles      2005/12/02 17:38:53 UTC    (20051202-340)
+  Log:
+  Improvements also applicable to hyperion 1.x.
+  
+
+  Changes:     Modified:
+  +4 -5                trunk/doc/sgml/oper-guide/commands.sgml (File Modified) 
+
+
+jilles      2005/12/02 17:08:45 UTC    (20051202-338)
+  Log:
+  - Add +F description
+  - General improvements and changes to charybdis
+  
+
+  Changes:     Modified:
+  +27 -14      trunk/doc/sgml/oper-guide/cmodes.sgml (File Modified) 
+
+
+jilles      2005/12/02 16:43:45 UTC    (20051202-336)
+  Log:
+  The server notice umodes only have an effect
+  for opers. ("sendto_realops_flags", so having
+  the umode is not enough, they must also be
+  opered)
+  
+
+  Changes:     Modified:
+  +13 -14      trunk/doc/sgml/oper-guide/umodes.sgml (File Modified) 
+
+
+jilles      2005/12/02 16:39:40 UTC    (20051202-334)
+  Log:
+  Updates to umodes docs.
+  
+
+  Changes:     Modified:
+  +25 -27      trunk/doc/sgml/oper-guide/umodes.sgml (File Modified) 
+
+
+nenolod     2005/11/25 19:37:36 UTC    (20051125-332)
+  Log:
+  Add SGML documentation.
+
+  Changes:     Modified:
+  + -          trunk/doc/sgml/ (File Added) 
+  + -          trunk/doc/sgml/oper-guide/ (File Added) 
+  + -          trunk/doc/sgml/oper-guide/charybdis-oper-guide.sgml (File Added) 
+  + -          trunk/doc/sgml/oper-guide/cmodes.sgml (File Added) 
+  + -          trunk/doc/sgml/oper-guide/commands.sgml (File Added) 
+  + -          trunk/doc/sgml/oper-guide/config.sgml (File Added) 
+  + -          trunk/doc/sgml/oper-guide/intro.sgml (File Added) 
+  + -          trunk/doc/sgml/oper-guide/stylesheet.dsl (File Added) 
+  + -          trunk/doc/sgml/oper-guide/umodes.sgml (File Added) 
+
+
+jilles      2005/11/21 11:04:33 UTC    (20051121-330)
+  Log:
+  Make operwall flag restrict setting umode +z.
+  This repairs this flag broken in charybdis-1.0.
+  
+
+  Changes:     Modified:
+  +41 -0       trunk/contrib/m_flags.c (File Modified) 
+  +9 -0                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2005/11/21 10:29:37 UTC    (20051121-328)
+  Log:
+  Don't complain/reset remote clients +n. I'm still not
+  convinced propagating all umodes is the way to go, oh
+  well.
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/src/s_user.c (File Modified) 
+
+
+jilles      2005/11/21 10:21:42 UTC    (20051121-326)
+  Log:
+  - Require admin flag for oper /chghost (if it's enabled
+    which is not default)
+  - Give error message on nonexistant nick
+  
+
+  Changes:     Modified:
+  +12 -0       trunk/modules/m_chghost.c (File Modified) 
+
+
+nenolod     2005/11/20 21:10:14 UTC    (20051120-324)
+  Log:
+  Incorporated jilles' dynspoof patch with a few minor changes.
+
+  Changes:     Modified:
+  +5 -2                trunk/include/client.h (File Modified) 
+  +1 -0                trunk/include/numeric.h (File Modified) 
+  +75 -4       trunk/modules/m_chghost.c (File Modified) 
+  +2 -21       trunk/modules/m_stats.c (File Modified) 
+  +2 -8                trunk/modules/m_trace.c (File Modified) 
+  +2 -0                trunk/src/client.c (File Modified) 
+  +3 -0                trunk/src/s_user.c (File Modified) 
+
+
+nenolod     2005/11/20 21:02:01 UTC    (20051120-322)
+  Log:
+  Update NEWS.
+
+  Changes:     Modified:
+  +5 -0                trunk/NEWS (File Modified) 
+
+
+jilles      2005/11/17 22:38:52 UTC    (20051117-320)
+  Log:
+  Make show_ip() far less braindead.
+  
+  Obtained from: ratbox 2.2 SVN
+  
+
+  Changes:     Modified:
+  +14 -85      trunk/src/client.c (File Modified) 
+
+
+jilles      2005/11/15 16:33:26 UTC    (20051115-318)
+  Log:
+  Instead of not showing channels at all for whoising services,
+  only show channels the requester is also on. If operspying
+  services, show all the channels.
+  
+
+  Changes:     Modified:
+  +37 -40      trunk/modules/m_whois.c (File Modified) 
+
+
+jilles      2005/11/15 15:59:00 UTC    (20051115-316)
+  Log:
+  - Show real errno if we fail to connect to a server
+  - Don't show server IPs on IRC if a server goes dead
+    during handshake
+  
+
+  Changes:     Modified:
+  +2 -5                trunk/src/s_serv.c (File Modified) 
+
+
+jilles      2005/11/15 15:28:18 UTC    (20051115-314)
+  Log:
+  Revert hybrid 7.2 aline code. It causes too many problems.
+  
+
+  Changes:     Modified:
+  +1 -47       trunk/NEWS (File Modified) 
+  + -          trunk/include/aline.h (File Deleted) 
+  +53 -6       trunk/modules/m_dline.c (File Modified) 
+  +212 -16     trunk/modules/m_kline.c (File Modified) 
+  +37 -8       trunk/modules/m_resv.c (File Modified) 
+  +45 -24      trunk/modules/m_xline.c (File Modified) 
+  +0 -485      trunk/src/Makefile.in (File Modified) 
+  + -          trunk/src/aline.c (File Deleted) 
+
+
+jilles      2005/11/07 10:47:33 UTC    (20051107-312)
+  Log:
+  Incorporate recent ratbox monitor bugfixes (could crash).
+  
+
+  Changes:     Modified:
+  +16 -0       trunk/modules/m_monitor.c (File Modified) 
+  +4 -3                trunk/src/monitor.c (File Modified) 
+
+
+jilles      2005/10/24 23:10:06 UTC    (20051024-310)
+  Log:
+  Fix /invite UID leak.
+  
+  Found by logiclrd@EFnet.
+  
+
+  Changes:     Modified:
+  +3 -2                trunk/modules/m_invite.c (File Modified) 
+
+
+nenolod     2005/10/23 05:28:02 UTC    (20051023-308)
+  Log:
+  Don't show what channels a service is in.
+
+  Changes:     Modified:
+  +1 -0                trunk/NEWS (File Modified) 
+  +40 -35      trunk/modules/m_whois.c (File Modified) 
+
+
+nenolod     2005/10/23 05:21:13 UTC    (20051023-306)
+  Log:
+  Update version to 1.0.3.
+  
+
+  Changes:     Modified:
+  +9 -9                trunk/configure (File Modified) 
+  +1 -1                trunk/configure.ac (File Modified) 
+
+
+jilles      2005/10/22 17:12:51 UTC    (20051022-304)
+  Log:
+  Update NEWS.
+  
+
+  Changes:     Modified:
+  +7 -1                trunk/NEWS (File Modified) 
+
+
+jilles      2005/10/22 17:11:32 UTC    (20051022-302)
+  Log:
+  Make sure we don't return alloca() (LOCAL_COPY) ed space.
+  More static buffers :(
+  
+
+  Changes:     Modified:
+  +12 -4       trunk/src/aline.c (File Modified) 
+
+
+jilles      2005/10/18 21:52:35 UTC    (20051018-300)
+  Log:
+  Make operspy mode (/mode !#channel showing parameters
+  even if not on channel) work again.
+  
+
+  Changes:     Modified:
+  +4 -4                trunk/src/channel.c (File Modified) 
+
+
+jilles      2005/10/16 22:04:15 UTC    (20051016-298)
+  Log:
+  Call server_introduced hook on TS6 remote server
+  introduction (ms_sid()).
+  
+
+  Changes:     Modified:
+  +6 -0                trunk/modules/core/m_server.c (File Modified) 
+
+
+nenolod     2005/10/16 08:29:57 UTC    (20051016-296)
+  Log:
+  Cyrix boxes are wierd.
+
+  Changes:     Modified:
+  +2 -1                trunk/modules/m_services.c (File Modified) 
+
+
+nenolod     2005/10/16 08:23:39 UTC    (20051016-294)
+  Log:
+  More paranoia.
+
+  Changes:     Modified:
+  +1 -1                trunk/include/client.h (File Modified) 
+  +3 -1                trunk/modules/m_services.c (File Modified) 
+
+
+nenolod     2005/10/16 08:07:40 UTC    (20051016-292)
+  Log:
+  heh
+
+  Changes:     Modified:
+  +1 -6                trunk/modules/m_services.c (File Modified) 
+
+
+nenolod     2005/10/16 08:00:24 UTC    (20051016-290)
+  Log:
+  Disable a check that doesn't always seem to work right for some reason.
+
+  Changes:     Modified:
+  +2 -0                trunk/modules/m_services.c (File Modified) 
+
+
+nenolod     2005/10/15 04:58:18 UTC    (20051015-288)
+  Log:
+  Update NEWS.
+  
+
+  Changes:     Modified:
+  +4 -1                trunk/NEWS (File Modified) 
+
+
+nenolod     2005/10/15 04:53:12 UTC    (20051015-286)
+  Log:
+  1.0.2
+  
+
+  Changes:     Modified:
+  +9 -9                trunk/configure (File Modified) 
+  +1 -1                trunk/configure.ac (File Modified) 
+
+
+jilles      2005/10/08 22:30:18 UTC    (20051008-284)
+  Log:
+  Apply http://www.ircd-ratbox.org/download/ratbox-trace.diff.
+  
+
+  Changes:     Modified:
+  +3 -13       trunk/modules/m_trace.c (File Modified) 
+
+
+jilles      2005/10/06 11:00:22 UTC    (20051006-282)
+  Log:
+  Don't send empty RPL_WHOISCHANNELS on remote whois.
+  
+  Pointy hat to: jilles
+  
+
+  Changes:     Modified:
+  +1 -1                trunk/modules/m_whois.c (File Modified) 
+
+
+nenolod     2005/10/02 21:30:55 UTC    (20051002-280)
+  Log:
+  Update NEWS.
+  
+
+  Changes:     Modified:
+  +3 -0                trunk/NEWS (File Modified) 
+
+
+nenolod     2005/10/02 21:28:23 UTC    (20051002-278)
+  Log:
+  Modular umode support.
+  
+
+  Changes:     Modified:
+  +0 -9                trunk/include/client.h (File Modified) 
+  +2 -1                trunk/include/s_user.h (File Modified) 
+  +1 -1                trunk/include/tools.h (File Modified) 
+  +2 -2                trunk/modules/core/m_nick.c (File Modified) 
+  +3 -0                trunk/src/ircd.c (File Modified) 
+  +1 -1                trunk/src/messages.tab (File Modified) 
+  +2 -2                trunk/src/s_serv.c (File Modified) 
+  +37 -59      trunk/src/s_user.c (File Modified) 
+  +21 -0       trunk/src/tools.c (File Modified) 
+
+
+jilles      2005/10/02 20:23:15 UTC    (20051002-276)
+  Log:
+  Optionally do forced nick change to the UID instead of kill
+  on nick collisions, see doc/collision_fnc.txt for more
+  details.
+  
+
+  Changes:     Modified:
+  + -          trunk/doc/collision_fnc.txt (File Added) 
+  +1 -0                trunk/doc/example.conf (File Modified) 
+  +8 -0                trunk/doc/reference.conf (File Modified) 
+  +1 -0                trunk/include/numeric.h (File Modified) 
+  +1 -0                trunk/include/s_conf.h (File Modified) 
+  +2 -1                trunk/include/s_serv.h (File Modified) 
+  +1 -0                trunk/include/s_stats.h (File Modified) 
+  +275 -95     trunk/modules/core/m_nick.c (File Modified) 
+  +1 -1                trunk/src/messages.tab (File Modified) 
+  +1 -0                trunk/src/newconf.c (File Modified) 
+  +1 -0                trunk/src/s_conf.c (File Modified) 
+  +1 -0                trunk/src/s_serv.c (File Modified) 
+  +2 -2                trunk/src/s_stats.c (File Modified) 
+
+
+nenolod     2005/10/02 19:50:18 UTC    (20051002-274)
+  Log:
+  Update NEWS.
+  
+
+  Modified:
+       trunk/NEWS (File Modified) 
+
+
+jilles      2005/09/28 15:45:31 UTC    (20050928-272)
+  Log:
+  Don't allow lookups by uid in /monitor + and /monitor s.
+  
+
+  Modified:
+       trunk/modules/m_monitor.c (File Modified) 
+
+
+jilles      2005/09/28 13:05:01 UTC    (20050928-270)
+  Log:
+  Stop garbage +j being set in cases like +j aaa:bbb by
+  initializing the variables properly.
+  
+  Reported by kyle.
+  
+
+  Modified:
+       trunk/modules/core/m_mode.c (File Modified) 
+       trunk/modules/core/m_sjoin.c (File Modified) 
+
+
+jilles      2005/09/25 15:51:54 UTC    (20050925-268)
+  Log:
+  Apply flags to the proper server in me_gcap().
+  
+
+  Modified:
+       trunk/modules/m_capab.c (File Modified) 
+
+
+jilles      2005/09/22 23:13:46 UTC    (20050922-266)
+  Log:
+  Use find_named_client() instead of find_client() to check
+  for nick collisions.
+  
+
+  Modified:
+       trunk/modules/core/m_nick.c (File Modified) 
+
+
+nenolod     2005/09/22 05:55:25 UTC    (20050922-264)
+  Log:
+  - Replace old 381 numeric with a new, more positive one!
+  
+
+  Modified:
+       trunk/src/messages.tab (File Modified) 
+
+
+jilles      2005/09/22 00:38:45 UTC    (20050922-262)
+  Log:
+  Make it compile again.
+  
+
+  Modified:
+       trunk/src/channel.c (File Modified) 
+       trunk/src/client.c (File Modified) 
+       trunk/src/ircd.c (File Modified) 
+       trunk/src/packet.c (File Modified) 
+
+
+nenolod     2005/09/22 00:02:59 UTC    (20050922-260)
+  Log:
+  - Prevent UID disclosure in cmode setting.
+  
+
+  Modified:
+       trunk/NEWS (File Modified) 
+       trunk/modules/core/m_mode.c (File Modified) 
+
+
+nenolod     2005/09/21 23:57:17 UTC    (20050921-258)
+  Log:
+  A different check which prevents UID disclosure.
+  
+
+  Modified:
+       trunk/modules/core/m_kick.c (File Modified) 
+
+
+nenolod     2005/09/21 23:46:04 UTC    (20050921-256)
+  Log:
+  - Eliminate a potential UID leak in m_kick. (As seen on EFnet.)
+  
+
+  Modified:
+       trunk/modules/core/m_kick.c (File Modified) 
+
+
+nenolod     2005/09/21 23:35:12 UTC    (20050921-254)
+  Log:
+  - Revert atheme coding style changes. We don't really need berkeley prototypes, that's overkill.
+  
+
+  Modified:
+       trunk/NEWS (File Modified) 
+       trunk/modules/m_accept.c (File Modified) 
+       trunk/modules/m_admin.c (File Modified) 
+       trunk/modules/m_away.c (File Modified) 
+       trunk/modules/m_cap.c (File Modified) 
+       trunk/modules/m_capab.c (File Modified) 
+       trunk/modules/m_challenge.c (File Modified) 
+       trunk/modules/m_chghost.c (File Modified) 
+       trunk/modules/m_close.c (File Modified) 
+       trunk/modules/m_cmessage.c (File Modified) 
+       trunk/modules/m_connect.c (File Modified) 
+       trunk/modules/m_dline.c (File Modified) 
+       trunk/modules/m_encap.c (File Modified) 
+       trunk/modules/m_etrace.c (File Modified) 
+       trunk/modules/m_gline.c (File Modified) 
+       trunk/modules/m_help.c (File Modified) 
+       trunk/modules/m_info.c (File Modified) 
+       trunk/modules/m_invite.c (File Modified) 
+       trunk/modules/m_ison.c (File Modified) 
+       trunk/modules/m_kline.c (File Modified) 
+       trunk/modules/m_knock.c (File Modified) 
+       trunk/modules/m_links.c (File Modified) 
+       trunk/modules/m_list.c (File Modified) 
+       trunk/modules/m_locops.c (File Modified) 
+       trunk/modules/m_lusers.c (File Modified) 
+       trunk/modules/m_map.c (File Modified) 
+       trunk/modules/m_monitor.c (File Modified) 
+       trunk/modules/m_motd.c (File Modified) 
+       trunk/modules/m_names.c (File Modified) 
+       trunk/modules/m_oper.c (File Modified) 
+       trunk/modules/m_operspy.c (File Modified) 
+       trunk/modules/m_pass.c (File Modified) 
+       trunk/modules/m_ping.c (File Modified) 
+       trunk/modules/m_pong.c (File Modified) 
+       trunk/modules/m_post.c (File Modified) 
+       trunk/modules/m_rehash.c (File Modified) 
+       trunk/modules/m_restart.c (File Modified) 
+       trunk/modules/m_resv.c (File Modified) 
+       trunk/modules/m_services.c (File Modified) 
+       trunk/modules/m_set.c (File Modified) 
+       trunk/modules/m_sshortcut.c (File Modified) 
+       trunk/modules/m_stats.c (File Modified) 
+       trunk/modules/m_svinfo.c (File Modified) 
+       trunk/modules/m_tb.c (File Modified) 
+       trunk/modules/m_testline.c (File Modified) 
+       trunk/modules/m_testmask.c (File Modified) 
+       trunk/modules/m_time.c (File Modified) 
+       trunk/modules/m_topic.c (File Modified) 
+       trunk/modules/m_trace.c (File Modified) 
+       trunk/modules/m_unreject.c (File Modified) 
+       trunk/modules/m_user.c (File Modified) 
+       trunk/modules/m_userhost.c (File Modified) 
+       trunk/modules/m_users.c (File Modified) 
+       trunk/modules/m_version.c (File Modified) 
+       trunk/modules/m_wallops.c (File Modified) 
+       trunk/modules/m_who.c (File Modified) 
+       trunk/modules/m_whois.c (File Modified) 
+       trunk/modules/m_whowas.c (File Modified) 
+       trunk/modules/m_xline.c (File Modified) 
+       trunk/src/adns.c (File Modified) 
+       trunk/src/aline.c (File Modified) 
+       trunk/src/cache.c (File Modified) 
+       trunk/src/channel.c (File Modified) 
+       trunk/src/class.c (File Modified) 
+       trunk/src/client.c (File Modified) 
+       trunk/src/commio.c (File Modified) 
+       trunk/src/event.c (File Modified) 
+       trunk/src/hash.c (File Modified) 
+       trunk/src/hostmask.c (File Modified) 
+       trunk/src/ircd.c (File Modified) 
+       trunk/src/kdparse.c (File Modified) 
+       trunk/src/linebuf.c (File Modified) 
+       trunk/src/listener.c (File Modified) 
+       trunk/src/modules.c (File Modified) 
+       trunk/src/monitor.c (File Modified) 
+       trunk/src/newconf.c (File Modified) 
+       trunk/src/packet.c (File Modified) 
+       trunk/src/parse.c (File Modified) 
+       trunk/src/reject.c (File Modified) 
+       trunk/src/s_auth.c (File Modified) 
+       trunk/src/s_conf.c (File Modified) 
+       trunk/src/s_gline.c (File Modified) 
+       trunk/src/s_log.c (File Modified) 
+       trunk/src/s_newconf.c (File Modified) 
+       trunk/src/s_serv.c (File Modified) 
+       trunk/src/s_stats.c (File Modified) 
+       trunk/src/s_user.c (File Modified) 
+       trunk/src/send.c (File Modified) 
+       trunk/src/whowas.c (File Modified) 
+
+
+nenolod     2005/09/21 23:24:34 UTC    (20050921-252)
+  Log:
+  - More coding style niceities. Pretty much got client.h squared away.
+  
+
+  Modified:
+       trunk/modules/m_dline.c (File Modified) 
+       trunk/modules/m_gline.c (File Modified) 
+       trunk/modules/m_kline.c (File Modified) 
+       trunk/modules/m_rehash.c (File Modified) 
+       trunk/modules/m_resv.c (File Modified) 
+       trunk/modules/m_stats.c (File Modified) 
+       trunk/modules/m_testline.c (File Modified) 
+       trunk/modules/m_user.c (File Modified) 
+       trunk/modules/m_xline.c (File Modified) 
+
+
+jilles      2005/09/21 22:37:13 UTC    (20050921-250)
+  Log:
+  - Propagate quiets (+q) on netjoins
+  - Clear +q list too on lowerTS sjoin from TS6 source
+  
+
+  Modified:
+       trunk/modules/core/m_sjoin.c (File Modified) 
+       trunk/src/s_serv.c (File Modified) 
+
+
+jilles      2005/09/21 15:49:43 UTC    (20050921-248)
+  Log:
+  Second argument to whois is always a nick, never a uid.
+  This prevents /whois other.server uid to get information
+  about that uid.
+  
+
+  Modified:
+       trunk/modules/m_whois.c (File Modified) 
+
+
+jilles      2005/09/21 15:43:45 UTC    (20050921-246)
+  Log:
+  Don't allow local users to use uids in user mode.
+  
+
+  Modified:
+       trunk/src/s_user.c (File Modified) 
+
+
+jilles      2005/09/21 15:42:56 UTC    (20050921-244)
+  Log:
+  Make it compile again.
+  
+
+  Modified:
+       trunk/src/s_stats.c (File Modified) 
+
+
+jilles      2005/09/21 15:09:11 UTC    (20050921-242)
+  Log:
+  Fix propagation of empty SJOIN.
+  
+
+  Modified:
+       trunk/modules/core/m_sjoin.c (File Modified) 
+
+
+nenolod     2005/09/21 06:13:45 UTC    (20050921-240)
+  Log:
+  Some atheme-style niceties here.
+  
+
+  Modified:
+       trunk/modules/m_accept.c (File Modified) 
+       trunk/modules/m_admin.c (File Modified) 
+       trunk/modules/m_away.c (File Modified) 
+       trunk/modules/m_cap.c (File Modified) 
+       trunk/modules/m_capab.c (File Modified) 
+       trunk/modules/m_challenge.c (File Modified) 
+       trunk/modules/m_chghost.c (File Modified) 
+       trunk/modules/m_close.c (File Modified) 
+       trunk/modules/m_cmessage.c (File Modified) 
+       trunk/modules/m_connect.c (File Modified) 
+       trunk/modules/m_dline.c (File Modified) 
+       trunk/modules/m_encap.c (File Modified) 
+       trunk/modules/m_etrace.c (File Modified) 
+       trunk/modules/m_gline.c (File Modified) 
+       trunk/modules/m_help.c (File Modified) 
+       trunk/modules/m_info.c (File Modified) 
+       trunk/modules/m_invite.c (File Modified) 
+       trunk/modules/m_ison.c (File Modified) 
+       trunk/modules/m_kline.c (File Modified) 
+       trunk/modules/m_knock.c (File Modified) 
+       trunk/modules/m_links.c (File Modified) 
+       trunk/modules/m_list.c (File Modified) 
+       trunk/modules/m_locops.c (File Modified) 
+       trunk/modules/m_lusers.c (File Modified) 
+       trunk/modules/m_map.c (File Modified) 
+       trunk/modules/m_monitor.c (File Modified) 
+       trunk/modules/m_motd.c (File Modified) 
+       trunk/modules/m_names.c (File Modified) 
+       trunk/modules/m_oper.c (File Modified) 
+       trunk/modules/m_operspy.c (File Modified) 
+       trunk/modules/m_pass.c (File Modified) 
+       trunk/modules/m_ping.c (File Modified) 
+       trunk/modules/m_pong.c (File Modified) 
+       trunk/modules/m_post.c (File Modified) 
+       trunk/modules/m_rehash.c (File Modified) 
+       trunk/modules/m_restart.c (File Modified) 
+       trunk/modules/m_resv.c (File Modified) 
+       trunk/modules/m_services.c (File Modified) 
+       trunk/modules/m_set.c (File Modified) 
+       trunk/modules/m_sshortcut.c (File Modified) 
+       trunk/modules/m_stats.c (File Modified) 
+       trunk/modules/m_svinfo.c (File Modified) 
+       trunk/modules/m_tb.c (File Modified) 
+       trunk/modules/m_testline.c (File Modified) 
+       trunk/modules/m_testmask.c (File Modified) 
+       trunk/modules/m_time.c (File Modified) 
+       trunk/modules/m_topic.c (File Modified) 
+       trunk/modules/m_trace.c (File Modified) 
+       trunk/modules/m_unreject.c (File Modified) 
+       trunk/modules/m_user.c (File Modified) 
+       trunk/modules/m_userhost.c (File Modified) 
+       trunk/modules/m_users.c (File Modified) 
+       trunk/modules/m_version.c (File Modified) 
+       trunk/modules/m_wallops.c (File Modified) 
+       trunk/modules/m_who.c (File Modified) 
+       trunk/modules/m_whois.c (File Modified) 
+       trunk/modules/m_whowas.c (File Modified) 
+       trunk/modules/m_xline.c (File Modified) 
+
+
+nenolod     2005/09/21 05:26:03 UTC    (20050921-238)
+  Log:
+  Some initial tweaks to make it somewhat meet our coding standards, nowhere near done yet.
+  
+
+  Modified:
+       trunk/.indent.pro (File Modified) 
+       trunk/include/charybdis.h (File Added) 
+       trunk/include/client.h (File Modified) 
+       trunk/modules/.indent.pro (File Modified) 
+       trunk/src/.indent.pro (File Modified) 
+       trunk/src/adns.c (File Modified) 
+       trunk/src/aline.c (File Modified) 
+       trunk/src/cache.c (File Modified) 
+       trunk/src/channel.c (File Modified) 
+       trunk/src/class.c (File Modified) 
+       trunk/src/client.c (File Modified) 
+       trunk/src/commio.c (File Modified) 
+       trunk/src/event.c (File Modified) 
+       trunk/src/hash.c (File Modified) 
+       trunk/src/hostmask.c (File Modified) 
+       trunk/src/ircd.c (File Modified) 
+       trunk/src/kdparse.c (File Modified) 
+       trunk/src/linebuf.c (File Modified) 
+       trunk/src/listener.c (File Modified) 
+       trunk/src/modules.c (File Modified) 
+       trunk/src/monitor.c (File Modified) 
+       trunk/src/newconf.c (File Modified) 
+       trunk/src/packet.c (File Modified) 
+       trunk/src/parse.c (File Modified) 
+       trunk/src/reject.c (File Modified) 
+       trunk/src/s_auth.c (File Modified) 
+       trunk/src/s_conf.c (File Modified) 
+       trunk/src/s_gline.c (File Modified) 
+       trunk/src/s_log.c (File Modified) 
+       trunk/src/s_newconf.c (File Modified) 
+       trunk/src/s_serv.c (File Modified) 
+       trunk/src/s_stats.c (File Modified) 
+       trunk/src/s_user.c (File Modified) 
+       trunk/src/send.c (File Modified) 
+       trunk/src/whowas.c (File Modified) 
+
+
+nenolod     2005/09/21 04:31:10 UTC    (20050921-236)
+  Log:
+  - Add parse_aline() via ircd-hybrid-7.2. This stuff lives in src/aline.c.
+  - Convert a few modules towards using this code.
+  - Make a note about this change in NEWS.
+  
+
+  Modified:
+       trunk/NEWS (File Modified) 
+       trunk/include/aline.h (File Added) 
+       trunk/modules/m_dline.c (File Modified) 
+       trunk/modules/m_kline.c (File Modified) 
+       trunk/modules/m_resv.c (File Modified) 
+       trunk/modules/m_xline.c (File Modified) 
+       trunk/src/Makefile.in (File Modified) 
+       trunk/src/aline.c (File Added) 
+
+
+nenolod     2005/09/21 00:20:28 UTC    (20050921-234)
+  Log:
+  - Update NEWS document.
+  
+
+  Modified:
+       trunk/NEWS (File Modified) 
+
+
+jilles      2005/09/20 18:27:19 UTC    (20050920-232)
+  Log:
+  Use find_named_person() instead of find_person() in services shortcuts.
+  
+
+  Modified:
+       trunk/modules/m_sshortcut.c (File Modified) 
+
+
+jilles      2005/09/18 22:18:59 UTC    (20050918-230)
+  Log:
+  Fix propagation of empty channels (+P).
+  
+
+  Modified:
+       trunk/modules/core/m_sjoin.c (File Modified) 
+       trunk/src/s_serv.c (File Modified) 
+
+
+jilles      2005/09/18 22:18:04 UTC    (20050918-228)
+  Log:
+  Use same comparison for +f.
+  
+
+  Modified:
+       trunk/modules/core/m_join.c (File Modified) 
+
+
+jilles      2005/09/18 18:48:13 UTC    (20050918-226)
+  Log:
+  Retire server-server non-encap CHGHOST, and clean it up a bit.
+  
+
+  Modified:
+       trunk/modules/m_chghost.c (File Modified) 
+
+
+jilles      2005/09/18 14:26:20 UTC    (20050918-224)
+  Log:
+  Use TS6 form for SQUIT wallops.
+  
+
+  Modified:
+       trunk/modules/core/m_squit.c (File Modified) 
+
+
+jilles      2005/09/18 14:25:54 UTC    (20050918-222)
+  Log:
+  Propagate nick changes for remote clients in TS6 form if possible;
+  simplify the code a bit.
+  
+
+  Modified:
+       trunk/modules/core/m_nick.c (File Modified) 
+
+
+jilles      2005/09/18 14:16:43 UTC    (20050918-220)
+  Log:
+  Only clear oper_only_umodes on deoper for local clients.
+  
+
+  Modified:
+       trunk/src/s_user.c (File Modified) 
+
+
+nenolod     2005/09/18 06:14:39 UTC    (20050918-218)
+  Log:
+  - Don't enable use_whois_actually in the default config, makes cloaking 
+    only useful for vanity.
+  
+
+  Modified:
+       trunk/doc/example.conf (File Modified) 
+
+
+jilles      2005/09/18 00:00:12 UTC    (20050918-216)
+  Log:
+  Fix linebuf raw code to not truncate lines longer than
+  510 characters. This stops ziplinks corruption at
+  the initial burst if the other side sends a lot.
+  
+
+  Modified:
+       trunk/src/linebuf.c (File Modified) 
+
+
+nenolod     2005/09/13 03:26:36 UTC    (20050913-214)
+  Log:
+  - Add +r to channel_modes().
+  
+
+  Modified:
+       trunk/src/channel.c (File Modified) 
+
+
+nenolod     2005/09/13 00:11:52 UTC    (20050913-212)
+  Log:
+  Update NEWS.
+  
+
+  Modified:
+       trunk/NEWS (File Modified) 
+
+
+nenolod     2005/09/12 23:49:25 UTC    (20050912-210)
+  Log:
+  err, nvm. wrong project :-P
+  
+
+  Modified:
+       trunk/src/match.c (File Modified) 
+
+
+nenolod     2005/09/12 23:49:00 UTC    (20050912-208)
+  Log:
+  make sure we don't crash on match(NULL, test)
+  
+
+  Modified:
+       trunk/src/match.c (File Modified) 
+
+
+jilles      2005/09/12 23:40:03 UTC    (20050912-206)
+  Log:
+  Add remote rehash, /rehash <server> and /rehash <option> <server>,
+  flags = rehash in shared{}.
+  Uses :<source> ENCAP <target> REHASH [option].
+  
+
+  Modified:
+       trunk/doc/example.conf (File Modified) 
+       trunk/doc/reference.conf (File Modified) 
+       trunk/help/opers/rehash (File Modified) 
+       trunk/include/s_newconf.h (File Modified) 
+       trunk/modules/m_rehash.c (File Modified) 
+       trunk/modules/m_stats.c (File Modified) 
+       trunk/src/newconf.c (File Modified) 
+
+
+jilles      2005/09/12 22:48:44 UTC    (20050912-204)
+  Log:
+  Initialize flags to 0 in conf_set_shared_flags() and
+  conf_set_cluster_flags().
+  
+
+  Modified:
+       trunk/src/newconf.c (File Modified) 
+
+
+jilles      2005/09/12 22:14:16 UTC    (20050912-202)
+  Log:
+  Don't allow a forward from a #channel to an &channel.
+  Error message is Illegal channel name.
+  
+
+  Modified:
+       trunk/modules/core/m_mode.c (File Modified) 
+
+
+nenolod     2005/09/12 21:56:51 UTC    (20050912-200)
+  Log:
+  - change version to 1.0.1
+  
+
+  Modified:
+       trunk/configure (File Modified) 
+       trunk/configure.ac (File Modified) 
+
+
+nenolod     2005/09/12 21:56:28 UTC    (20050912-198)
+  Log:
+  Update NEWS.
+  
+
+  Modified:
+       trunk/NEWS (File Modified) 
+
+
+jilles      2005/09/12 21:55:58 UTC    (20050912-196)
+  Log:
+  Services shortcuts changes:
+  - Require umode +S on target
+  - Use ERR_SERVICESDOWN (440) for error message
+  - Fix check for empty string
+  
+
+  Modified:
+       trunk/include/numeric.h (File Modified) 
+       trunk/modules/m_sshortcut.c (File Modified) 
+       trunk/src/messages.tab (File Modified) 
+
+
+nenolod     2005/09/12 21:24:30 UTC    (20050912-194)
+  Log:
+  s/IsChanService/IsService/g;
+  
+
+  Modified:
+       trunk/modules/m_sshortcut.c (File Modified) 
+
+
+nenolod     2005/09/12 21:23:42 UTC    (20050912-192)
+  Log:
+  Add check for service validity in shortcut routines.
+  
+
+  Modified:
+       trunk/modules/m_sshortcut.c (File Modified) 
+
+
+jilles      2005/09/12 15:30:26 UTC    (20050912-190)
+  Log:
+  Don't allow forwarding to a -F channel the setter is not on.
+  
+
+  Modified:
+       trunk/modules/core/m_mode.c (File Modified) 
+
+
+jilles      2005/09/12 13:55:56 UTC    (20050912-188)
+  Log:
+  Describe identify_service and identify_command in
+  reference.conf.
+  
+
+  Modified:
+       trunk/doc/reference.conf (File Modified) 
+
+
+jilles      2005/09/12 13:37:11 UTC    (20050912-186)
+  Log:
+  More helpfile updates.
+  
+
+  Modified:
+       trunk/help/Makefile.in (File Modified) 
+       trunk/help/opers/die (File Modified) 
+       trunk/help/opers/join (File Modified) 
+       trunk/help/opers/links (File Modified) 
+       trunk/help/opers/lusers (File Modified) 
+       trunk/help/opers/map (File Added) 
+       trunk/help/opers/motd (File Modified) 
+       trunk/help/opers/names (File Modified) 
+       trunk/help/opers/notice (File Modified) 
+       trunk/help/opers/operspy (File Modified) 
+       trunk/help/opers/part (File Modified) 
+       trunk/help/opers/privmsg (File Modified) 
+       trunk/help/opers/restart (File Modified) 
+       trunk/help/opers/set (File Modified) 
+       trunk/help/opers/stats (File Modified) 
+       trunk/help/opers/trace (File Modified) 
+       trunk/help/opers/version (File Modified) 
+       trunk/help/users/notice (File Modified) 
+       trunk/help/users/privmsg (File Modified) 
+       trunk/help/users/stats (File Modified) 
+
+
+jilles      2005/09/12 11:18:40 UTC    (20050912-184)
+  Log:
+  Update help files.
+  
+
+  Modified:
+       trunk/help/opers/cmode (File Modified) 
+       trunk/help/opers/umode (File Modified) 
+       trunk/help/opers/wallops (File Modified) 
+       trunk/help/opers/who (File Modified) 
+       trunk/help/users/umode (File Modified) 
+
+
+jilles      2005/09/12 11:11:18 UTC    (20050912-182)
+  Log:
+  Include cmode +r in 004 and 005.
+  
+
+  Modified:
+       trunk/include/supported.h (File Modified) 
+       trunk/src/messages.tab (File Modified) 
+
+
+jilles      2005/09/12 10:53:35 UTC    (20050912-180)
+  Log:
+  No need to clear all 3 buffers in channel_modes().
+  
+
+  Modified:
+       trunk/src/channel.c (File Modified) 
+
+
+jilles      2005/09/12 10:31:54 UTC    (20050912-178)
+  Log:
+  - Fix multiple +f modes per line
+  - -f shouldn't take a parameter
+  
+
+  Modified:
+       trunk/modules/core/m_mode.c (File Modified) 
+
+
+jilles      2005/09/12 10:04:27 UTC    (20050912-176)
+  Log:
+  Channel mode +Q now prevents forwarding to or through
+  a channel, just like in hyperion, not from a channel.
+  
+
+  Modified:
+       trunk/modules/core/m_join.c (File Modified) 
+
+
+jilles      2005/09/12 09:36:21 UTC    (20050912-174)
+  Log:
+  Complete +F/+Q propagation.
+  
+
+  Modified:
+       trunk/modules/core/m_join.c (File Modified) 
+       trunk/modules/core/m_sjoin.c (File Modified) 
+       trunk/src/channel.c (File Modified) 
+
+
+nenolod     2005/09/12 06:10:29 UTC    (20050912-172)
+  Log:
+  - A few minor fixes.
+  
+
+  Modified:
+       trunk/modules/core/m_join.c (File Modified) 
+       trunk/modules/m_services.c (File Modified) 
+
+
+nenolod     2005/09/12 04:15:44 UTC    (20050912-170)
+  Log:
+  - Fix netsplit obfuscation.
+  
+
+  Modified:
+       trunk/src/client.c (File Modified) 
+
+
+nenolod     2005/09/12 04:07:36 UTC    (20050912-168)
+  Log:
+  - Fix another /stats p related bug.
+  
+
+  Modified:
+       trunk/src/client.c (File Modified) 
+
+
+nenolod     2005/09/12 03:57:13 UTC    (20050912-166)
+  Log:
+  - Update example.conf.
+  
+
+  Modified:
+       trunk/doc/example.conf (File Modified) 
+
+
+nenolod     2005/09/12 03:52:56 UTC    (20050912-164)
+  Log:
+  - Fix a minor bug here, and re-release 1.0.
+  
+
+  Modified:
+       trunk/modules/core/m_nick.c (File Modified) 
+
+
+nenolod     2005/09/12 03:19:51 UTC    (20050912-162)
+  Log:
+  - Add bursted clients to /stats p list.
+  
+
+  Modified:
+       trunk/modules/core/m_nick.c (File Modified) 
+
+
+nenolod     2005/09/12 03:15:28 UTC    (20050912-160)
+  Log:
+  - Add identify_service, identify_command options to the example.conf,
+    newconf parser.
+  
+
+  Modified:
+       trunk/NEWS (File Modified) 
+       trunk/doc/example.conf (File Modified) 
+       trunk/src/newconf.c (File Modified) 
+
+
+nenolod     2005/09/12 03:00:04 UTC    (20050912-158)
+  Log:
+  - Add services shortcuts.
+  
+
+  Modified:
+       trunk/modules/Makefile.in (File Modified) 
+       trunk/modules/m_sshortcut.c (File Added) 
+
+
+nenolod     2005/09/12 02:46:00 UTC    (20050912-156)
+  Log:
+  - put back checks i removed by mistake
+  
+
+  Modified:
+       trunk/modules/core/m_join.c (File Modified) 
+
+
+nenolod     2005/09/12 02:42:09 UTC    (20050912-154)
+  Log:
+  - Implement channel mode +Q, which disables forwarding.
+  - Make forwarding usable by everyone.
+  - Implement channel mode +F which bypasses authority checks on a target 
+    set with this mode
+  - Update NEWS.
+  
+
+  Modified:
+       trunk/NEWS (File Modified) 
+       trunk/include/channel.h (File Modified) 
+       trunk/include/supported.h (File Modified) 
+       trunk/modules/core/m_join.c (File Modified) 
+       trunk/modules/core/m_mode.c (File Modified) 
+       trunk/src/messages.tab (File Modified) 
+
+
+nenolod     2005/09/12 02:13:26 UTC    (20050912-152)
+  Log:
+  - Fix account handling brokenness.
+  
+
+  Modified:
+       trunk/modules/m_services.c (File Modified) 
+
+
+jilles      2005/09/12 02:04:09 UTC    (20050912-150)
+  Log:
+  Identify to services via server password hack. Still
+  needs config file parts, like
+  identifyservice = "nickserv@services.int";
+  identifycommand = "IDENTIFY";
+  
+
+  Modified:
+       trunk/include/s_conf.h (File Modified) 
+       trunk/src/s_user.c (File Modified) 
+
+
+jilles      2005/09/12 01:59:46 UTC    (20050912-148)
+  Log:
+  Make send.c compile.
+  
+
+  Modified:
+       trunk/src/send.c (File Modified) 
+
+
+nenolod     2005/09/12 01:18:24 UTC    (20050912-146)
+  Log:
+  - Handle this better.
+  
+
+  Modified:
+       trunk/src/send.c (File Modified) 
+
+
+nenolod     2005/09/12 01:16:34 UTC    (20050912-144)
+  Log:
+  If the source is not a client, don't send to normal users.
+  
+
+  Modified:
+       trunk/src/send.c (File Modified) 
+
+
+nenolod     2005/09/12 01:07:01 UTC    (20050912-142)
+  Log:
+  - Make /wallops behave as wallops in other ircds.
+  
+
+  Modified:
+       trunk/modules/m_wallops.c (File Modified) 
+       trunk/src/send.c (File Modified) 
+
+
+nenolod     2005/09/12 00:53:16 UTC    (20050912-140)
+  Log:
+  - charybdis-1.0
+  
+
+  Modified:
+       trunk/NEWS (File Modified) 
+       trunk/configure (File Modified) 
+       trunk/configure.ac (File Modified) 
+
+
+nenolod     2005/09/12 00:48:18 UTC    (20050912-138)
+  Log:
+  - Remove efnet configuration.
+  - Rename example.conf as reference.conf, and replace the default 
+  example.conf with one suitable for AthemeNET.
+  - Update makefile to reflect these changes.
+  
+
+  Modified:
+       trunk/doc/Makefile.in (File Modified) 
+       trunk/doc/example.conf (File Modified) 
+       trunk/doc/example.efnet.conf (File Deleted) 
+       trunk/doc/reference.conf (File Added) 
+
+
+nenolod     2005/09/12 00:30:48 UTC    (20050912-136)
+  Log:
+  - Don't display opers who are /away.
+  
+
+  Modified:
+       trunk/modules/m_stats.c (File Modified) 
+
+
+jilles      2005/09/12 00:21:20 UTC    (20050912-134)
+  Log:
+  Put cmode +f in 004 and 005.
+  
+
+  Modified:
+       trunk/include/supported.h (File Modified) 
+       trunk/src/messages.tab (File Modified) 
+
+
+jilles      2005/09/12 00:15:13 UTC    (20050912-132)
+  Log:
+  Add user umode +Q which prevents a user from
+  being forwarded.
+  
+
+  Modified:
+       trunk/include/client.h (File Modified) 
+       trunk/modules/core/m_join.c (File Modified) 
+       trunk/src/messages.tab (File Modified) 
+       trunk/src/s_user.c (File Modified) 
+
+
+jilles      2005/09/11 23:47:02 UTC    (20050911-130)
+  Log:
+  Implement channel forwarding in m_join(). As in
+  hyperion, failing to join because of +i, +r or +j
+  can cause you to be forwarded, potentially
+  recursively. Unlike hyperion, a single numeric
+  is sent in case of a successful forward, otherwise
+  the ircd acts if there were no forward.
+  
+
+  Modified:
+       trunk/include/numeric.h (File Modified) 
+       trunk/modules/core/m_join.c (File Modified) 
+       trunk/src/messages.tab (File Modified) 
+
+
+jilles      2005/09/11 22:57:53 UTC    (20050911-128)
+  Log:
+  Allow servers to set oper-only cmodes as well.
+  
+
+  Modified:
+       trunk/modules/core/m_mode.c (File Modified) 
+
+
+jilles      2005/09/11 22:48:37 UTC    (20050911-126)
+  Log:
+  Add cmode +f which takes a channel name, settable
+  only by opers for now. Does not do anything yet.
+  
+
+  Modified:
+       trunk/include/channel.h (File Modified) 
+       trunk/modules/core/m_join.c (File Modified) 
+       trunk/modules/core/m_mode.c (File Modified) 
+       trunk/modules/core/m_sjoin.c (File Modified) 
+       trunk/src/channel.c (File Modified) 
+
+
+jilles      2005/09/11 20:48:09 UTC    (20050911-124)
+  Log:
+  Fully initialize 'mode' in ms_join() and ms_sjoin()
+  to avoid old +j garbage from being used.
+  
+
+  Modified:
+       trunk/modules/core/m_join.c (File Modified) 
+       trunk/modules/core/m_sjoin.c (File Modified) 
+
+
+jilles      2005/09/11 19:41:53 UTC    (20050911-122)
+  Log:
+  - only touch join_count/join_delta if join throttling
+    is enabled on the channel
+  - reset join_count/join_delta to 0 if -j is set
+  
+
+  Modified:
+       trunk/modules/core/m_join.c (File Modified) 
+       trunk/modules/core/m_mode.c (File Modified) 
+       trunk/modules/core/m_sjoin.c (File Modified) 
+
+
+jilles      2005/09/11 18:57:20 UTC    (20050911-120)
+  Log:
+  Also start a new "period" for join throttling for remote joins,
+  if necessary.  Make the code slightly clearer.
+  
+
+  Modified:
+       trunk/modules/core/m_join.c (File Modified) 
+       trunk/src/channel.c (File Modified) 
+
+
+jilles      2005/09/11 18:12:20 UTC    (20050911-118)
+  Log:
+  Some +j improvements, still broken.
+  
+
+  Modified:
+       trunk/modules/core/m_join.c (File Modified) 
+       trunk/modules/core/m_sjoin.c (File Modified) 
+
+
+jilles      2005/09/11 16:44:36 UTC    (20050911-116)
+  Log:
+  Only do +z processing for +m channels the sender is on,
+  as bans/quiets are currently only checked locally.
+  
+
+  Modified:
+       trunk/modules/core/m_message.c (File Modified) 
+
+
+jilles      2005/09/11 16:01:02 UTC    (20050911-114)
+  Log:
+  - Add max_bans_large configuration option, defaulting to 500, to
+    limit the number of bans in a +L channel
+  - Change b/e/I to b/e/I/q in texts
+  
+
+  Modified:
+       trunk/doc/example.conf (File Modified) 
+       trunk/include/s_conf.h (File Modified) 
+       trunk/modules/core/m_mode.c (File Modified) 
+       trunk/modules/m_info.c (File Modified) 
+       trunk/src/newconf.c (File Modified) 
+       trunk/src/s_conf.c (File Modified) 
+
+
+jilles      2005/09/11 15:20:38 UTC    (20050911-112)
+  Log:
+  Store invite for +gi channels.
+  Note that +gi is significantly weaker access control than +i.
+  
+
+  Modified:
+       trunk/modules/m_invite.c (File Modified) 
+
+
+jilles      2005/09/11 14:38:35 UTC    (20050911-110)
+  Log:
+  Nonops are allowed to see +q lists.
+  
+
+  Modified:
+       trunk/modules/core/m_mode.c (File Modified) 
+
+
+jilles      2005/09/11 14:27:59 UTC    (20050911-108)
+  Log:
+  Invalidate can_send() cache on -q.
+  
+
+  Modified:
+       trunk/modules/core/m_mode.c (File Modified) 
+
+
+nenolod     2005/09/11 07:01:01 UTC    (20050911-106)
+  Log:
+  - Make sure sjoin doesnt crash the ircd if it's blank. :X
+  
+
+  Modified:
+       trunk/modules/core/m_sjoin.c (File Modified) 
+
+
+nenolod     2005/09/11 06:28:20 UTC    (20050911-104)
+  Log:
+  - Allow blank SJOINs -- for permanant channels.
+  
+
+  Modified:
+       trunk/modules/core/m_sjoin.c (File Modified) 
+
+
+nenolod     2005/09/11 06:12:40 UTC    (20050911-102)
+  Log:
+  - Burst permanant channels.
+  
+
+  Modified:
+       trunk/src/s_serv.c (File Modified) 
+
+
+nenolod     2005/09/11 06:08:42 UTC    (20050911-100)
+  Log:
+  - Fix handling of permanant channels.
+  
+
+  Modified:
+       trunk/modules/core/m_join.c (File Modified) 
+
+
+nenolod     2005/09/11 03:37:47 UTC    (20050911-98)
+  Log:
+  - Run indent on core modules.
+  - Add propagation of join throttle settings.
+  
+
+  Modified:
+       trunk/modules/core/m_die.c (File Modified) 
+       trunk/modules/core/m_error.c (File Modified) 
+       trunk/modules/core/m_join.c (File Modified) 
+       trunk/modules/core/m_kick.c (File Modified) 
+       trunk/modules/core/m_kill.c (File Modified) 
+       trunk/modules/core/m_message.c (File Modified) 
+       trunk/modules/core/m_mode.c (File Modified) 
+       trunk/modules/core/m_nick.c (File Modified) 
+       trunk/modules/core/m_part.c (File Modified) 
+       trunk/modules/core/m_quit.c (File Modified) 
+       trunk/modules/core/m_server.c (File Modified) 
+       trunk/modules/core/m_sjoin.c (File Modified) 
+       trunk/modules/core/m_squit.c (File Modified) 
+
+
+nenolod     2005/09/11 00:31:11 UTC    (20050911-96)
+  Log:
+  - Fix mistake in commit message.
+  
+
+  Modified:
+       trunk/ChangeLog (File Modified) 
+
+
+nenolod     2005/09/11 00:30:36 UTC    (20050911-94)
+  Log:
+  - Channel throttling.
+  
+
+  Modified:
+       trunk/NEWS (File Modified) 
+       trunk/include/supported.h (File Modified) 
+       trunk/modules/core/m_mode.c (File Modified) 
+       trunk/src/messages.tab (File Modified) 
+
+
+nenolod     2005/09/10 23:56:31 UTC    (20050910-92)
+  Log:
+  - Channel throttle logic fixes.
+  
+
+  Modified:
+       trunk/include/channel.h (File Modified) 
+
+
+nenolod     2005/09/10 23:55:45 UTC    (20050910-90)
+  Log:
+  - Add the throttle logic.
+  
+
+  Modified:
+       trunk/include/channel.h (File Modified) 
+       trunk/include/numeric.h (File Modified) 
+       trunk/modules/core/m_join.c (File Modified) 
+       trunk/src/channel.c (File Modified) 
+       trunk/src/messages.tab (File Modified) 
+
+
+nenolod     2005/09/10 20:10:09 UTC    (20050910-88)
+  Log:
+  - Cosmetic fixes to CREDITS.
+  
+
+  Modified:
+       trunk/CREDITS (File Modified) 
+
+
+nenolod     2005/09/10 19:54:51 UTC    (20050910-86)
+  Log:
+  - Better channel_modes() from ShadowIRCd 4.
+  
+
+  Modified:
+       trunk/include/channel.h (File Modified) 
+       trunk/src/channel.c (File Modified) 
+
+
+nenolod     2005/09/10 19:01:56 UTC    (20050910-84)
+  Log:
+  - Strip colour codes from parts.
+  
+
+  Modified:
+       trunk/modules/core/m_part.c (File Modified) 
+
+
+nenolod     2005/09/10 19:01:00 UTC    (20050910-82)
+  Log:
+  - Strip colour codes from quits.
+  
+
+  Modified:
+       trunk/modules/core/m_quit.c (File Modified) 
+
+
+nenolod     2005/09/10 18:59:00 UTC    (20050910-80)
+  Log:
+  - add +c/+g/+z to channel_modes().
+  
+
+  Modified:
+       trunk/src/channel.c (File Modified) 
+
+
+nenolod     2005/09/10 18:56:03 UTC    (20050910-78)
+  Log:
+  - Add +g to 004/005 numerics.
+  
+
+  Modified:
+       trunk/include/supported.h (File Modified) 
+       trunk/src/messages.tab (File Modified) 
+
+
+nenolod     2005/09/10 18:54:51 UTC    (20050910-76)
+  Log:
+  - Add +cgz to set_final_mode() in both join/sjoin.
+  - Implement channel mode +g: Free invite.
+  
+
+  Modified:
+       trunk/include/channel.h (File Modified) 
+       trunk/modules/core/m_join.c (File Modified) 
+       trunk/modules/core/m_mode.c (File Modified) 
+       trunk/modules/core/m_sjoin.c (File Modified) 
+       trunk/modules/m_invite.c (File Modified) 
+
+
+nenolod     2005/09/10 18:16:51 UTC    (20050910-74)
+  Log:
+  - Make sure /stats p uses the right list.
+  
+
+  Modified:
+       trunk/modules/m_stats.c (File Modified) 
+
+
+nenolod     2005/09/10 18:16:27 UTC    (20050910-72)
+  Log:
+  - local oper list becomes local_oper_list.
+  - all opers are stored on oper_list for /stats p.
+  
+
+  Modified:
+       trunk/include/ircd.h (File Modified) 
+       trunk/modules/m_stats.c (File Modified) 
+       trunk/modules/m_trace.c (File Modified) 
+       trunk/src/client.c (File Modified) 
+       trunk/src/ircd.c (File Modified) 
+       trunk/src/s_user.c (File Modified) 
+       trunk/src/send.c (File Modified) 
+
+
+nenolod     2005/09/10 07:03:09 UTC    (20050910-70)
+  Log:
+  - Remove ENABLE_SERVICES legacy define.
+  
+
+  Modified:
+       trunk/configure (File Modified) 
+       trunk/configure.ac (File Modified) 
+       trunk/include/client.h (File Modified) 
+       trunk/include/m_info.h (File Modified) 
+       trunk/include/s_conf.h (File Modified) 
+       trunk/modules/Makefile.in (File Modified) 
+       trunk/modules/core/m_kick.c (File Modified) 
+       trunk/modules/core/m_mode.c (File Modified) 
+       trunk/modules/core/m_nick.c (File Modified) 
+       trunk/modules/core/m_sjoin.c (File Modified) 
+       trunk/modules/m_services.c (File Modified) 
+       trunk/src/channel.c (File Modified) 
+       trunk/src/newconf.c (File Modified) 
+       trunk/src/s_conf.c (File Modified) 
+       trunk/src/s_serv.c (File Modified) 
+       trunk/src/s_user.c (File Modified) 
+
+
+nenolod     2005/09/10 06:47:19 UTC    (20050910-68)
+  Log:
+  - New reject message, ala ircu.
+  
+
+  Modified:
+       trunk/src/reject.c (File Modified) 
+
+
+nenolod     2005/09/10 06:27:05 UTC    (20050910-66)
+  Log:
+  - Reduce 'broadcast storm' effect in m_chghost.
+  
+
+  Modified:
+       trunk/modules/m_chghost.c (File Modified) 
+
+
+nenolod     2005/09/10 06:22:38 UTC    (20050910-64)
+  Log:
+  - Add +z to RPL_ISUPPORT, RPL_MYINFO.
+  
+
+  Modified:
+       trunk/include/supported.h (File Modified) 
+       trunk/src/messages.tab (File Modified) 
+
+
+nenolod     2005/09/10 06:21:43 UTC    (20050910-62)
+  Log:
+  - Implement +z.
+  
+
+  Modified:
+       trunk/include/channel.h (File Modified) 
+       trunk/modules/core/m_message.c (File Modified) 
+       trunk/modules/core/m_mode.c (File Modified) 
+
+
+nenolod     2005/09/10 06:03:27 UTC    (20050910-60)
+  Log:
+  - use sendto_one_numeric() in some places.
+  
+
+  Modified:
+       trunk/modules/core/m_mode.c (File Modified) 
+
+
+nenolod     2005/09/10 05:40:25 UTC    (20050910-58)
+  Log:
+  - Implement channel mode +c -- colour stripping.
+  
+
+  Modified:
+       trunk/include/irc_string.h (File Modified) 
+       trunk/include/supported.h (File Modified) 
+       trunk/modules/core/m_message.c (File Modified) 
+       trunk/modules/core/m_mode.c (File Modified) 
+       trunk/src/irc_string.c (File Modified) 
+       trunk/src/messages.tab (File Modified) 
+
+
+nenolod     2005/09/10 05:29:17 UTC    (20050910-56)
+  Log:
+  - Add +qLP to CHANMODES 005 numeric.
+  
+
+  Modified:
+       trunk/include/supported.h (File Modified) 
+
+
+nenolod     2005/09/10 05:12:55 UTC    (20050910-54)
+  Log:
+  Move credits files to doc/.
+  
+
+  Modified:
+       trunk/Hybrid-team (File Deleted) 
+       trunk/Ratbox-team (File Deleted) 
+       trunk/doc/Hybrid-team (File Added) 
+       trunk/doc/Ratbox-team (File Added) 
+
+
+nenolod     2005/09/10 05:11:15 UTC    (20050910-52)
+  Log:
+  - Rename Ratbox credits as Ratbox-team.
+  - Add in our own CREDITS.
+  
+
+  Modified:
+       trunk/CREDITS (File Deleted) 
+       trunk/CREDITS (File Added) 
+       trunk/Ratbox-team (File Added) 
+
+
+nenolod     2005/09/10 05:03:03 UTC    (20050910-50)
+  Log:
+  - Quietcache fixes.
+  
+
+  Modified:
+       trunk/modules/core/m_mode.c (File Modified) 
+
+
+nenolod     2005/09/10 04:43:41 UTC    (20050910-48)
+  Log:
+  - Rebuild configure.
+  
+
+  Modified:
+       trunk/autom4te.cache/ (File Deleted) 
+       trunk/configure (File Modified) 
+
+
+nenolod     2005/09/10 03:25:41 UTC    (20050910-46)
+  Log:
+  Add +q to messages.tab.
+  
+
+  Modified:
+       trunk/src/messages.tab (File Modified) 
+
+
+nenolod     2005/09/10 03:17:39 UTC    (20050910-44)
+  Log:
+  - port m_sjoin stuff to TS6 JOIN syntax.
+  
+
+  Modified:
+       trunk/modules/core/m_join.c (File Modified) 
+
+
+nenolod     2005/09/10 03:15:50 UTC    (20050910-42)
+  Log:
+  - Implement channel mode +q (quiet)
+  
+
+  Modified:
+       trunk/include/channel.h (File Modified) 
+       trunk/modules/core/m_mode.c (File Modified) 
+       trunk/src/channel.c (File Modified) 
+
+
+jilles      2005/09/10 03:03:05 UTC    (20050910-40)
+  Log:
+  Add +L/+P for set_final_mode().
+  
+
+  Modified:
+       trunk/modules/core/m_sjoin.c (File Modified) 
+
+
+jilles      2005/09/10 02:59:22 UTC    (20050910-38)
+  Log:
+  Add +L/+P in channel_modes().
+  
+
+  Modified:
+       trunk/src/channel.c (File Modified) 
+
+
+jilles      2005/09/10 02:55:10 UTC    (20050910-36)
+  Log:
+  - Use MODE_PERMANENT, not MODE_PERMANANT
+  - Actually use chm_staff()
+  
+  It compiles but is not otherwise tested.
+  
+
+  Modified:
+       trunk/include/channel.h (File Modified) 
+       trunk/modules/core/m_mode.c (File Modified) 
+       trunk/modules/core/m_sjoin.c (File Modified) 
+       trunk/src/channel.c (File Modified) 
+
+
+nenolod     2005/09/10 02:53:04 UTC    (20050910-34)
+  Log:
+  - Ok, patchlevel.h is fixed now.
+  
+
+  Modified:
+       trunk/include/patchlevel.h (File Modified) 
+
+
+nenolod     2005/09/10 02:45:47 UTC    (20050910-32)
+  Log:
+  - *sigh*
+  
+
+  Modified:
+       trunk/include/patchlevel.h (File Modified) 
+       trunk/src/version.c.SH (File Modified) 
+
+
+nenolod     2005/09/10 02:43:00 UTC    (20050910-30)
+  Log:
+  - Fix compilation issue with version.c.
+  
+
+  Modified:
+       trunk/src/version.c.SH (File Modified) 
+
+
+nenolod     2005/09/10 02:33:47 UTC    (20050910-28)
+  Log:
+  - Server hostmasking fixed in +datadrain ala hybrid 7.2, so we remove 
+    this from the BUGS file.
+  
+
+  Modified:
+       trunk/BUGS (File Modified) 
+
+
+jilles      2005/09/10 02:30:22 UTC    (20050910-26)
+  Log:
+  Mangle all netsplit messages if flatten links is enabled.
+  
+
+  Modified:
+       trunk/src/client.c (File Modified) 
+
+
+nenolod     2005/09/10 02:26:22 UTC    (20050910-24)
+  Log:
+  - jilles pointed out that /stats p needed severe changes -- implement 
+    them
+  
+
+  Modified:
+       trunk/modules/m_stats.c (File Modified) 
+
+
+nenolod     2005/09/10 02:24:18 UTC    (20050910-22)
+  Log:
+  Rename RELNOTES to NEWS.
+  
+
+  Modified:
+       trunk/NEWS (File Added) 
+       trunk/RELNOTES (File Deleted) 
+
+
+nenolod     2005/09/10 02:24:03 UTC    (20050910-20)
+  Log:
+  Update RELNOTES.
+  
+
+  Modified:
+       trunk/RELNOTES (File Modified) 
+
+
+nenolod     2005/09/10 02:22:34 UTC    (20050910-18)
+  Log:
+  - Make /stats p work globally.
+  - Change 'OPER(s)' to 'staff members'
+  
+
+  Modified:
+       trunk/modules/m_stats.c (File Modified) 
+
+
+nenolod     2005/09/10 02:19:01 UTC    (20050910-16)
+  Log:
+  - add modes, +LP to RPL_MYINFO.
+  
+
+  Modified:
+       trunk/src/messages.tab (File Modified) 
+
+
+nenolod     2005/09/10 02:16:42 UTC    (20050910-14)
+  Log:
+  More stuff to RELNOTES.
+  
+
+  Modified:
+       trunk/RELNOTES (File Modified) 
+
+
+nenolod     2005/09/10 01:32:27 UTC    (20050910-12)
+  Log:
+  - Implement +P.
+  
+
+  Modified:
+       trunk/modules/core/m_sjoin.c (File Modified) 
+       trunk/src/channel.c (File Modified) 
+
+
+nenolod     2005/09/10 01:28:47 UTC    (20050910-10)
+  Log:
+  - Implement list limit exceed modes -- +L.
+  
+
+  Modified:
+       trunk/modules/core/m_mode.c (File Modified) 
+
+
+nenolod     2005/09/10 01:26:55 UTC    (20050910-8)
+  Log:
+  - Add handlers for modes +L, +P.
+  
+
+  Modified:
+       trunk/include/channel.h (File Modified) 
+       trunk/modules/core/m_mode.c (File Modified) 
+
+
+nenolod     2005/09/10 01:02:21 UTC    (20050910-6)
+  Log:
+  Update properties on *everything*.
+  
+
+  Modified:
+       trunk/.cvsignore  (Property Modified)
+       trunk/.indent.pro  (Property Modified)
+       trunk/BUGS (File Modified) (Property Modified)
+       trunk/CREDITS (File Modified) (Property Modified)
+       trunk/ChangeLog  (Property Modified)
+       trunk/Hybrid-team (File Modified) (Property Modified)
+       trunk/INSTALL (File Modified) (Property Modified)
+       trunk/LICENSE (File Modified) (Property Modified)
+       trunk/Makefile.in (File Modified) (Property Modified)
+       trunk/README.FIRST (File Modified) (Property Modified)
+       trunk/RELNOTES (File Modified) (Property Modified)
+       trunk/SVN-Access  (Property Modified)
+       trunk/aclocal.m4 (File Modified) (Property Modified)
+       trunk/adns/.cvsignore  (Property Modified)
+       trunk/adns/COPYING  (Property Modified)
+       trunk/adns/GPL-vs-LGPL  (Property Modified)
+       trunk/adns/Makefile.in (File Modified) (Property Modified)
+       trunk/adns/README  (Property Modified)
+       trunk/adns/README.ircd  (Property Modified)
+       trunk/adns/adns.h (File Modified) (Property Modified)
+       trunk/adns/check.c (File Modified) (Property Modified)
+       trunk/adns/dlist.h (File Modified) (Property Modified)
+       trunk/adns/event.c (File Modified) (Property Modified)
+       trunk/adns/general.c (File Modified) (Property Modified)
+       trunk/adns/internal.h (File Modified) (Property Modified)
+       trunk/adns/parse.c (File Modified) (Property Modified)
+       trunk/adns/query.c (File Modified) (Property Modified)
+       trunk/adns/reply.c (File Modified) (Property Modified)
+       trunk/adns/setup.c (File Modified) (Property Modified)
+       trunk/adns/transmit.c (File Modified) (Property Modified)
+       trunk/adns/tvarith.h (File Modified) (Property Modified)
+       trunk/adns/types.c (File Modified) (Property Modified)
+       trunk/configure (File Modified) (Property Modified)
+       trunk/configure.ac (File Modified) (Property Modified)
+       trunk/contrib/.cvsignore  (Property Modified)
+       trunk/contrib/.indent.pro  (Property Modified)
+       trunk/contrib/Makefile.in (File Modified) (Property Modified)
+       trunk/contrib/README (File Modified) (Property Modified)
+       trunk/contrib/example_module.c (File Modified) (Property Modified)
+       trunk/contrib/m_42.c (File Modified) (Property Modified)
+       trunk/contrib/m_clearchan.c (File Modified) (Property Modified)
+       trunk/contrib/m_flags.c (File Modified) (Property Modified)
+       trunk/contrib/m_force.c (File Modified) (Property Modified)
+       trunk/contrib/m_mkpasswd.c (File Modified) (Property Modified)
+       trunk/contrib/m_ojoin.c (File Modified) (Property Modified)
+       trunk/contrib/m_okick.c (File Modified) (Property Modified)
+       trunk/contrib/m_olist.c (File Modified) (Property Modified)
+       trunk/contrib/m_opme.c (File Modified) (Property Modified)
+       trunk/contrib/spy_admin_notice.c (File Modified) (Property Modified)
+       trunk/contrib/spy_info_notice.c (File Modified) (Property Modified)
+       trunk/contrib/spy_links_notice.c (File Modified) (Property Modified)
+       trunk/contrib/spy_motd_notice.c (File Modified) (Property Modified)
+       trunk/contrib/spy_stats_notice.c (File Modified) (Property Modified)
+       trunk/contrib/spy_stats_p_notice.c (File Modified) (Property Modified)
+       trunk/contrib/spy_trace_notice.c (File Modified) (Property Modified)
+       trunk/contrib/spy_whois_notice.c (File Modified) (Property Modified)
+       trunk/contrib/spy_whois_notice_global.c (File Modified) (Property Modified)
+       trunk/doc/.cvsignore  (Property Modified)
+       trunk/doc/CIDR.txt (File Modified) (Property Modified)
+       trunk/doc/Makefile.in (File Modified) (Property Modified)
+       trunk/doc/README.cidr_bans (File Modified) (Property Modified)
+       trunk/doc/Tao-of-IRC.940110  (Property Modified)
+       trunk/doc/challenge.txt (File Modified) (Property Modified)
+       trunk/doc/example.conf (File Modified) (Property Modified)
+       trunk/doc/example.efnet.conf (File Modified) (Property Modified)
+       trunk/doc/hooks.txt (File Modified) (Property Modified)
+       trunk/doc/index.txt (File Modified) (Property Modified)
+       trunk/doc/ircd.8 (File Modified) (Property Modified)
+       trunk/doc/ircd.motd  (Property Modified)
+       trunk/doc/logfiles.txt (File Modified) (Property Modified)
+       trunk/doc/modeg.txt (File Modified) (Property Modified)
+       trunk/doc/modes.txt (File Modified) (Property Modified)
+       trunk/doc/monitor.txt (File Modified) (Property Modified)
+       trunk/doc/old/Authors  (Property Modified)
+       trunk/doc/operguide.txt (File Modified) (Property Modified)
+       trunk/doc/opermyth.txt  (Property Modified)
+       trunk/doc/server-version-info (File Modified) (Property Modified)
+       trunk/doc/services.txt (File Modified) (Property Modified)
+       trunk/doc/technical/README.TSora  (Property Modified)
+       trunk/doc/technical/cluster.txt (File Modified) (Property Modified)
+       trunk/doc/technical/event.txt (File Modified) (Property Modified)
+       trunk/doc/technical/fd-management.txt (File Modified) (Property Modified)
+       trunk/doc/technical/file-management.txt (File Modified) (Property Modified)
+       trunk/doc/technical/hostmask.txt (File Modified) (Property Modified)
+       trunk/doc/technical/index.txt (File Modified) (Property Modified)
+       trunk/doc/technical/linebuf.txt (File Modified) (Property Modified)
+       trunk/doc/technical/network.txt (File Modified) (Property Modified)
+       trunk/doc/technical/rfc1459.txt  (Property Modified)
+       trunk/doc/technical/send.txt (File Modified) (Property Modified)
+       trunk/doc/technical/ts5.txt (File Modified) (Property Modified)
+       trunk/doc/technical/ts6.txt (File Modified) (Property Modified)
+       trunk/doc/tgchange.txt (File Modified) (Property Modified)
+       trunk/doc/whats-new-2.0.txt (File Modified) (Property Modified)
+       trunk/doc/whats-new-2.1.txt (File Modified) (Property Modified)
+       trunk/help/Makefile.in (File Modified) (Property Modified)
+       trunk/help/opers/accept  (Property Modified)
+       trunk/help/opers/admin  (Property Modified)
+       trunk/help/opers/away  (Property Modified)
+       trunk/help/opers/capab  (Property Modified)
+       trunk/help/opers/challenge  (Property Modified)
+       trunk/help/opers/close  (Property Modified)
+       trunk/help/opers/cmode  (Property Modified)
+       trunk/help/opers/cnotice  (Property Modified)
+       trunk/help/opers/connect  (Property Modified)
+       trunk/help/opers/cprivmsg  (Property Modified)
+       trunk/help/opers/credits  (Property Modified)
+       trunk/help/opers/die  (Property Modified)
+       trunk/help/opers/dline  (Property Modified)
+       trunk/help/opers/eob  (Property Modified)
+       trunk/help/opers/error  (Property Modified)
+       trunk/help/opers/etrace  (Property Modified)
+       trunk/help/opers/gline  (Property Modified)
+       trunk/help/opers/help  (Property Modified)
+       trunk/help/opers/index  (Property Modified)
+       trunk/help/opers/info  (Property Modified)
+       trunk/help/opers/invite  (Property Modified)
+       trunk/help/opers/ison  (Property Modified)
+       trunk/help/opers/join  (Property Modified)
+       trunk/help/opers/kick  (Property Modified)
+       trunk/help/opers/kill  (Property Modified)
+       trunk/help/opers/kline  (Property Modified)
+       trunk/help/opers/knock  (Property Modified)
+       trunk/help/opers/links  (Property Modified)
+       trunk/help/opers/list  (Property Modified)
+       trunk/help/opers/locops  (Property Modified)
+       trunk/help/opers/lusers  (Property Modified)
+       trunk/help/opers/modlist  (Property Modified)
+       trunk/help/opers/modload  (Property Modified)
+       trunk/help/opers/modrestart  (Property Modified)
+       trunk/help/opers/modunload  (Property Modified)
+       trunk/help/opers/motd  (Property Modified)
+       trunk/help/opers/names  (Property Modified)
+       trunk/help/opers/nick  (Property Modified)
+       trunk/help/opers/notice  (Property Modified)
+       trunk/help/opers/oper  (Property Modified)
+       trunk/help/opers/operspy  (Property Modified)
+       trunk/help/opers/operwall  (Property Modified)
+       trunk/help/opers/part  (Property Modified)
+       trunk/help/opers/pass  (Property Modified)
+       trunk/help/opers/ping  (Property Modified)
+       trunk/help/opers/pong  (Property Modified)
+       trunk/help/opers/post  (Property Modified)
+       trunk/help/opers/privmsg  (Property Modified)
+       trunk/help/opers/quit  (Property Modified)
+       trunk/help/opers/rehash  (Property Modified)
+       trunk/help/opers/restart  (Property Modified)
+       trunk/help/opers/resv  (Property Modified)
+       trunk/help/opers/server  (Property Modified)
+       trunk/help/opers/set  (Property Modified)
+       trunk/help/opers/sjoin  (Property Modified)
+       trunk/help/opers/squit  (Property Modified)
+       trunk/help/opers/stats  (Property Modified)
+       trunk/help/opers/svinfo  (Property Modified)
+       trunk/help/opers/testgecos  (Property Modified)
+       trunk/help/opers/testline  (Property Modified)
+       trunk/help/opers/testmask  (Property Modified)
+       trunk/help/opers/time  (Property Modified)
+       trunk/help/opers/topic  (Property Modified)
+       trunk/help/opers/trace  (Property Modified)
+       trunk/help/opers/uhelp  (Property Modified)
+       trunk/help/opers/umode  (Property Modified)
+       trunk/help/opers/undline  (Property Modified)
+       trunk/help/opers/ungline  (Property Modified)
+       trunk/help/opers/unkline  (Property Modified)
+       trunk/help/opers/unresv  (Property Modified)
+       trunk/help/opers/unxline  (Property Modified)
+       trunk/help/opers/user  (Property Modified)
+       trunk/help/opers/userhost  (Property Modified)
+       trunk/help/opers/users  (Property Modified)
+       trunk/help/opers/version  (Property Modified)
+       trunk/help/opers/wallops  (Property Modified)
+       trunk/help/opers/who  (Property Modified)
+       trunk/help/opers/whois  (Property Modified)
+       trunk/help/opers/whowas  (Property Modified)
+       trunk/help/opers/xline  (Property Modified)
+       trunk/help/users/index  (Property Modified)
+       trunk/help/users/info  (Property Modified)
+       trunk/help/users/notice  (Property Modified)
+       trunk/help/users/privmsg  (Property Modified)
+       trunk/help/users/stats  (Property Modified)
+       trunk/help/users/umode  (Property Modified)
+       trunk/include/.cvsignore  (Property Modified)
+       trunk/include/.indent.pro  (Property Modified)
+       trunk/include/balloc.h (File Modified) (Property Modified)
+       trunk/include/cache.h (File Modified) (Property Modified)
+       trunk/include/channel.h (File Modified) (Property Modified)
+       trunk/include/class.h (File Modified) (Property Modified)
+       trunk/include/client.h (File Modified) (Property Modified)
+       trunk/include/commio.h (File Modified) (Property Modified)
+       trunk/include/common.h (File Modified) (Property Modified)
+       trunk/include/config.h (File Modified) (Property Modified)
+       trunk/include/config.h.dist (File Modified) (Property Modified)
+       trunk/include/defaults.h (File Modified) (Property Modified)
+       trunk/include/event.h (File Modified) (Property Modified)
+       trunk/include/hash.h (File Modified) (Property Modified)
+       trunk/include/hook.h (File Modified) (Property Modified)
+       trunk/include/hostmask.h (File Modified) (Property Modified)
+       trunk/include/irc_string.h (File Modified) (Property Modified)
+       trunk/include/ircd.h (File Modified) (Property Modified)
+       trunk/include/ircd_defs.h (File Modified) (Property Modified)
+       trunk/include/ircd_getopt.h (File Modified) (Property Modified)
+       trunk/include/ircd_signal.h (File Modified) (Property Modified)
+       trunk/include/linebuf.h (File Modified) (Property Modified)
+       trunk/include/listener.h (File Modified) (Property Modified)
+       trunk/include/m_info.h (File Modified) (Property Modified)
+       trunk/include/memory.h (File Modified) (Property Modified)
+       trunk/include/modules.h (File Modified) (Property Modified)
+       trunk/include/monitor.h (File Modified) (Property Modified)
+       trunk/include/msg.h (File Modified) (Property Modified)
+       trunk/include/newconf.h (File Modified) (Property Modified)
+       trunk/include/numeric.h (File Modified) (Property Modified)
+       trunk/include/packet.h (File Modified) (Property Modified)
+       trunk/include/parse.h (File Modified) (Property Modified)
+       trunk/include/patchlevel.h (File Modified) (Property Modified)
+       trunk/include/patricia.h (File Modified) (Property Modified)
+       trunk/include/reject.h (File Modified) (Property Modified)
+       trunk/include/res.h (File Modified) (Property Modified)
+       trunk/include/restart.h (File Modified) (Property Modified)
+       trunk/include/s_auth.h (File Modified) (Property Modified)
+       trunk/include/s_conf.h (File Modified) (Property Modified)
+       trunk/include/s_gline.h (File Modified) (Property Modified)
+       trunk/include/s_log.h (File Modified) (Property Modified)
+       trunk/include/s_newconf.h (File Modified) (Property Modified)
+       trunk/include/s_serv.h (File Modified) (Property Modified)
+       trunk/include/s_stats.h (File Modified) (Property Modified)
+       trunk/include/s_user.h (File Modified) (Property Modified)
+       trunk/include/s_zip.h (File Modified) (Property Modified)
+       trunk/include/scache.h (File Modified) (Property Modified)
+       trunk/include/send.h (File Modified) (Property Modified)
+       trunk/include/serno.h  (Property Modified)
+       trunk/include/setup.h.in  (Property Modified)
+       trunk/include/sprintf_irc.h (File Modified) (Property Modified)
+       trunk/include/stdinc.h (File Modified) (Property Modified)
+       trunk/include/supported.h (File Modified) (Property Modified)
+       trunk/include/tools.h (File Modified) (Property Modified)
+       trunk/include/whowas.h (File Modified) (Property Modified)
+       trunk/install-sh (File Modified) (Property Modified)
+       trunk/modules/.cvsignore  (Property Modified)
+       trunk/modules/.depend  (Property Modified)
+       trunk/modules/.indent.pro  (Property Modified)
+       trunk/modules/Makefile.in (File Modified) (Property Modified)
+       trunk/modules/core/m_die.c (File Modified) (Property Modified)
+       trunk/modules/core/m_error.c (File Modified) (Property Modified)
+       trunk/modules/core/m_join.c (File Modified) (Property Modified)
+       trunk/modules/core/m_kick.c (File Modified) (Property Modified)
+       trunk/modules/core/m_kill.c (File Modified) (Property Modified)
+       trunk/modules/core/m_message.c (File Modified) (Property Modified)
+       trunk/modules/core/m_mode.c (File Modified) (Property Modified)
+       trunk/modules/core/m_nick.c (File Modified) (Property Modified)
+       trunk/modules/core/m_part.c (File Modified) (Property Modified)
+       trunk/modules/core/m_quit.c (File Modified) (Property Modified)
+       trunk/modules/core/m_server.c (File Modified) (Property Modified)
+       trunk/modules/core/m_sjoin.c (File Modified) (Property Modified)
+       trunk/modules/core/m_squit.c (File Modified) (Property Modified)
+       trunk/modules/m_accept.c (File Modified) (Property Modified)
+       trunk/modules/m_admin.c (File Modified) (Property Modified)
+       trunk/modules/m_away.c (File Modified) (Property Modified)
+       trunk/modules/m_cap.c (File Modified) (Property Modified)
+       trunk/modules/m_capab.c (File Modified) (Property Modified)
+       trunk/modules/m_challenge.c (File Modified) (Property Modified)
+       trunk/modules/m_chghost.c (File Modified) (Property Modified)
+       trunk/modules/m_close.c (File Modified) (Property Modified)
+       trunk/modules/m_cmessage.c (File Modified) (Property Modified)
+       trunk/modules/m_connect.c (File Modified) (Property Modified)
+       trunk/modules/m_dline.c (File Modified) (Property Modified)
+       trunk/modules/m_encap.c (File Modified) (Property Modified)
+       trunk/modules/m_etrace.c (File Modified) (Property Modified)
+       trunk/modules/m_gline.c (File Modified) (Property Modified)
+       trunk/modules/m_help.c (File Modified) (Property Modified)
+       trunk/modules/m_info.c (File Modified) (Property Modified)
+       trunk/modules/m_invite.c (File Modified) (Property Modified)
+       trunk/modules/m_ison.c (File Modified) (Property Modified)
+       trunk/modules/m_kline.c (File Modified) (Property Modified)
+       trunk/modules/m_knock.c (File Modified) (Property Modified)
+       trunk/modules/m_links.c (File Modified) (Property Modified)
+       trunk/modules/m_list.c (File Modified) (Property Modified)
+       trunk/modules/m_locops.c (File Modified) (Property Modified)
+       trunk/modules/m_lusers.c (File Modified) (Property Modified)
+       trunk/modules/m_map.c (File Modified) (Property Modified)
+       trunk/modules/m_monitor.c (File Modified) (Property Modified)
+       trunk/modules/m_motd.c (File Modified) (Property Modified)
+       trunk/modules/m_names.c (File Modified) (Property Modified)
+       trunk/modules/m_oper.c (File Modified) (Property Modified)
+       trunk/modules/m_operspy.c (File Modified) (Property Modified)
+       trunk/modules/m_pass.c (File Modified) (Property Modified)
+       trunk/modules/m_ping.c (File Modified) (Property Modified)
+       trunk/modules/m_pong.c (File Modified) (Property Modified)
+       trunk/modules/m_post.c (File Modified) (Property Modified)
+       trunk/modules/m_rehash.c (File Modified) (Property Modified)
+       trunk/modules/m_restart.c (File Modified) (Property Modified)
+       trunk/modules/m_resv.c (File Modified) (Property Modified)
+       trunk/modules/m_services.c (File Modified) (Property Modified)
+       trunk/modules/m_set.c (File Modified) (Property Modified)
+       trunk/modules/m_stats.c (File Modified) (Property Modified)
+       trunk/modules/m_svinfo.c (File Modified) (Property Modified)
+       trunk/modules/m_tb.c (File Modified) (Property Modified)
+       trunk/modules/m_testline.c (File Modified) (Property Modified)
+       trunk/modules/m_testmask.c (File Modified) (Property Modified)
+       trunk/modules/m_time.c (File Modified) (Property Modified)
+       trunk/modules/m_topic.c (File Modified) (Property Modified)
+       trunk/modules/m_trace.c (File Modified) (Property Modified)
+       trunk/modules/m_unreject.c (File Modified) (Property Modified)
+       trunk/modules/m_user.c (File Modified) (Property Modified)
+       trunk/modules/m_userhost.c (File Modified) (Property Modified)
+       trunk/modules/m_users.c (File Modified) (Property Modified)
+       trunk/modules/m_version.c (File Modified) (Property Modified)
+       trunk/modules/m_wallops.c (File Modified) (Property Modified)
+       trunk/modules/m_who.c (File Modified) (Property Modified)
+       trunk/modules/m_whois.c (File Modified) (Property Modified)
+       trunk/modules/m_whowas.c (File Modified) (Property Modified)
+       trunk/modules/m_xline.c (File Modified) (Property Modified)
+       trunk/modules/static_modules.c.SH (File Modified) (Property Modified)
+       trunk/servlink/.cvsignore  (Property Modified)
+       trunk/servlink/.indent.pro  (Property Modified)
+       trunk/servlink/Makefile.in (File Modified) (Property Modified)
+       trunk/servlink/README (File Modified) (Property Modified)
+       trunk/servlink/TODO (File Modified) (Property Modified)
+       trunk/servlink/control.c (File Modified) (Property Modified)
+       trunk/servlink/control.h (File Modified) (Property Modified)
+       trunk/servlink/io.c (File Modified) (Property Modified)
+       trunk/servlink/io.h (File Modified) (Property Modified)
+       trunk/servlink/servlink.c (File Modified) (Property Modified)
+       trunk/servlink/servlink.h (File Modified) (Property Modified)
+       trunk/src/.cvsignore  (Property Modified)
+       trunk/src/.depend  (Property Modified)
+       trunk/src/.indent.pro  (Property Modified)
+       trunk/src/Makefile.in (File Modified) (Property Modified)
+       trunk/src/adns.c (File Modified) (Property Modified)
+       trunk/src/balloc.c (File Modified) (Property Modified)
+       trunk/src/cache.c (File Modified) (Property Modified)
+       trunk/src/channel.c (File Modified) (Property Modified)
+       trunk/src/class.c (File Modified) (Property Modified)
+       trunk/src/client.c (File Modified) (Property Modified)
+       trunk/src/commio.c (File Modified) (Property Modified)
+       trunk/src/devpoll.c (File Modified) (Property Modified)
+       trunk/src/epoll.c (File Modified) (Property Modified)
+       trunk/src/event.c (File Modified) (Property Modified)
+       trunk/src/getopt.c (File Modified) (Property Modified)
+       trunk/src/hash.c (File Modified) (Property Modified)
+       trunk/src/hook.c (File Modified) (Property Modified)
+       trunk/src/hostmask.c (File Modified) (Property Modified)
+       trunk/src/irc_string.c (File Modified) (Property Modified)
+       trunk/src/ircd.c (File Modified) (Property Modified)
+       trunk/src/ircd_lexer.l (File Modified) (Property Modified)
+       trunk/src/ircd_parser.y (File Modified) (Property Modified)
+       trunk/src/ircd_signal.c (File Modified) (Property Modified)
+       trunk/src/kdparse.c (File Modified) (Property Modified)
+       trunk/src/kqueue.c (File Modified) (Property Modified)
+       trunk/src/linebuf.c (File Modified) (Property Modified)
+       trunk/src/listener.c (File Modified) (Property Modified)
+       trunk/src/match.c (File Modified) (Property Modified)
+       trunk/src/memory.c (File Modified) (Property Modified)
+       trunk/src/messages.tab (File Modified) (Property Modified)
+       trunk/src/modules.c (File Modified) (Property Modified)
+       trunk/src/monitor.c (File Modified) (Property Modified)
+       trunk/src/newconf.c (File Modified) (Property Modified)
+       trunk/src/numeric.c (File Modified) (Property Modified)
+       trunk/src/packet.c (File Modified) (Property Modified)
+       trunk/src/parse.c (File Modified) (Property Modified)
+       trunk/src/patricia.c (File Modified) (Property Modified)
+       trunk/src/poll.c (File Modified) (Property Modified)
+       trunk/src/reject.c (File Modified) (Property Modified)
+       trunk/src/restart.c (File Modified) (Property Modified)
+       trunk/src/s_auth.c (File Modified) (Property Modified)
+       trunk/src/s_conf.c (File Modified) (Property Modified)
+       trunk/src/s_gline.c (File Modified) (Property Modified)
+       trunk/src/s_log.c (File Modified) (Property Modified)
+       trunk/src/s_newconf.c (File Modified) (Property Modified)
+       trunk/src/s_serv.c (File Modified) (Property Modified)
+       trunk/src/s_stats.c (File Modified) (Property Modified)
+       trunk/src/s_user.c (File Modified) (Property Modified)
+       trunk/src/scache.c (File Modified) (Property Modified)
+       trunk/src/select.c (File Modified) (Property Modified)
+       trunk/src/send.c (File Modified) (Property Modified)
+       trunk/src/snprintf.c (File Modified) (Property Modified)
+       trunk/src/tools.c (File Modified) (Property Modified)
+       trunk/src/version.c.SH (File Modified) (Property Modified)
+       trunk/src/whowas.c (File Modified) (Property Modified)
+       trunk/tools/.cvsignore  (Property Modified)
+       trunk/tools/Makefile.in (File Modified) (Property Modified)
+       trunk/tools/README (File Modified) (Property Modified)
+       trunk/tools/README.mkpasswd (File Modified) (Property Modified)
+       trunk/tools/convertilines.c (File Modified) (Property Modified)
+       trunk/tools/convertklines.c (File Modified) (Property Modified)
+       trunk/tools/mkkeypair  (Property Modified)
+       trunk/tools/mkpasswd.c (File Modified) (Property Modified)
+       trunk/tools/rsa_respond/.cvsignore  (Property Modified)
+       trunk/tools/rsa_respond/Makefile (File Modified) (Property Modified)
+       trunk/tools/rsa_respond/README (File Modified) (Property Modified)
+       trunk/tools/rsa_respond/challenge.irc (File Modified) (Property Modified)
+       trunk/tools/rsa_respond/challenge.pl (File Modified) (Property Modified)
+       trunk/tools/rsa_respond/respond.c (File Modified) (Property Modified)
+       trunk/tools/rsa_respond/rsa_respond-insecure.diff (File Modified) (Property Modified)
+       trunk/tools/untabify (File Modified) (Property Modified)
+       trunk/tools/viconf.c (File Modified) (Property Modified)
+
+
+nenolod     2005/09/10 00:57:52 UTC    (20050910-4)
+  Log:
+  - Update RELNOTES.
+  
+
+  Modified:
+       trunk/RELNOTES (File Modified) 
+
+
+nenolod     2005/09/10 00:50:51 UTC    (20050910-2)
+  Log:
+  - Make version.c use our serial, not ratbox's.
+  
+
+  Modified:
+       trunk/src/version.c.SH (File Modified) 
+
+
+leeh        2005/09/06 15:59:08 UTC    (20050906_2-20748)
+  Log:
+  - update RELNOTES
+  - revved patchlevel to 2.1.5
+  
+
+  Modified:
+       ircd-ratbox/branches/RATBOX_2_1/RELNOTES (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/include/patchlevel.h (File Modified) 
+
+
+leeh        2005/09/06 15:58:31 UTC    (20050906_1-20746)
+  Log:
+  - fix buffer overflow and unterminated buffer when removing TS6 bans
+  - fix rebuilding of SJOIN
+  
+
+  Modified:
+       ircd-ratbox/branches/RATBOX_2_1/modules/core/m_sjoin.c (File Modified) 
+
+
+androsyn    2005/09/06 02:31:24 UTC    (20050906_0-20728)
+  Log:
+  have servlink report if it gets an uncompressed error message when it gets inflate failures
+
+  Modified:
+       ircd-ratbox/branches/RATBOX_2_1/servlink/io.c (File Modified) 
+
+
+leeh        2005/08/31 20:59:02 UTC    (20050831_0-20702)
+  Log:
+  - extend our copyrights to 2005.
+  
+
+  Modified:
+       ircd-ratbox/branches/RATBOX_2_1/modules/core/m_die.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/core/m_error.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/core/m_join.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/core/m_kick.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/core/m_kill.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/core/m_message.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/core/m_mode.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/core/m_nick.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/core/m_part.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/core/m_quit.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/core/m_server.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/core/m_sjoin.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/core/m_squit.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_accept.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_admin.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_away.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_capab.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_challenge.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_close.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_connect.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_dline.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_encap.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_etrace.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_gline.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_help.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_info.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_invite.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_ison.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_kline.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_knock.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_links.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_list.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_locops.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_lusers.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_motd.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_names.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_oper.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_operspy.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_pass.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_ping.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_pong.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_post.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_rehash.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_restart.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_resv.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_set.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_stats.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_svinfo.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_tb.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_testline.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_topic.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_trace.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_unreject.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_user.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_userhost.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_users.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_version.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_wallops.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_who.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_whois.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_whowas.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_xline.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/static_modules.c.SH (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/adns.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/balloc.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/cache.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/channel.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/class.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/client.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/commio.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/devpoll.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/epoll.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/event.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/getopt.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/hash.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/hostmask.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/irc_string.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/ircd.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/kdparse.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/kqueue.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/linebuf.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/listener.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/memory.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/modules.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/numeric.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/packet.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/parse.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/poll.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/reject.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/restart.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/s_auth.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/s_conf.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/s_gline.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/s_log.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/s_newconf.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/s_serv.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/s_stats.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/s_user.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/scache.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/select.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/send.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/tools.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/version.c.SH (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/whowas.c (File Modified) 
+
+
+leeh        2005/08/26 13:07:25 UTC    (20050826_1-20692)
+  Log:
+  - update RELNOTES
+  - revved patchlevel to 2.1.4
+  
+
+  Modified:
+       ircd-ratbox/branches/RATBOX_2_1/RELNOTES (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/include/patchlevel.h (File Modified) 
+
+
+leeh        2005/08/26 12:22:52 UTC    (20050826_0-20690)
+  Log:
+  - add TARGMAX to 005
+  - remove the +1 from ->uid in struct Client
+  - fix checking of accept entries in m_accept.c
+  
+
+  Modified:
+       ircd-ratbox/branches/RATBOX_2_1/include/client.h (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/include/supported.h (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_accept.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/s_user.c (File Modified) 
+
+
+leeh        2005/08/23 19:28:33 UTC    (20050823_0-20664)
+  Log:
+  - via jilles, fix possibility of RPL_WHOISCHANNELS being cut when we
+    send it over TS6
+  
+
+  Modified:
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_whois.c (File Modified) 
+
+
+leeh        2005/08/22 20:13:32 UTC    (20050822_1-20640)
+  Log:
+  - remove an unused variable
+  
+
+  Modified:
+       ircd-ratbox/branches/RATBOX_2_1/src/channel.c (File Modified) 
+
+
+androsyn    2005/08/22 10:38:59 UTC    (20050822_0-20638)
+  Log:
+  don't burst a TS5 name in burst_TS6. -via jillies
+
+  Modified:
+       ircd-ratbox/branches/RATBOX_2_1/src/s_serv.c (File Modified) 
+
+
+leeh        2005/08/21 12:17:12 UTC    (20050821_1-20626)
+  Log:
+  - via jilles, make nickchanges invalidate any cached bans for
+    quiet_on_ban
+  
+
+  Modified:
+       ircd-ratbox/branches/RATBOX_2_1/include/channel.h (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/core/m_nick.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_services.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/channel.c (File Modified) 
+
+
+leeh        2005/08/21 11:25:46 UTC    (20050821_0-20624)
+  Log:
+  - fix some char vs byte usage to make adns compile cleanly with gcc4
+  
+
+  Modified:
+       ircd-ratbox/branches/RATBOX_2_1/adns/event.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/adns/general.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/adns/internal.h (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/adns/parse.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/adns/query.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/adns/reply.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/adns/transmit.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/adns/types.c (File Modified) 
+
+
+androsyn    2005/07/31 05:12:43 UTC    (20050731_0-20607)
+  Log:
+  userhost should allow 5 userhost checks, not 4
+
+  Modified:
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_userhost.c (File Modified) 
+
+
+leeh        2005/07/17 20:10:30 UTC    (20050717_2-20587)
+  Log:
+  - another darwin fix
+  
+
+  Modified:
+       ircd-ratbox/branches/RATBOX_2_1/src/monitor.c (File Modified) 
+
+
+leeh        2005/07/17 18:55:27 UTC    (20050717_1-20583)
+  Log:
+  - darwin fixes
+  
+
+  Modified:
+       ircd-ratbox/branches/RATBOX_2_1/adns/Makefile.in (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/include/ircd_defs.h (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/include/newconf.h (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/include/s_conf.h (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/Makefile.in (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_challenge.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/hash.c (File Modified) 
+       ircd-ratbox/branches/RATBOX_2_1/src/whowas.c (File Modified) 
+
+
+leeh        2005/07/17 17:00:02 UTC    (20050717_0-20575)
+  Log:
+  - remove bogus extern of abort_list
+  
+
+  Modified:
+       ircd-ratbox/branches/RATBOX_2_1/include/ircd.h (File Modified) 
+
+
+androsyn    2005/07/08 00:37:30 UTC    (20050708_0-20553)
+  Log:
+  svn repo access stuff
+
+  Modified:
+       ircd-ratbox/branches/RATBOX_2_1/SVN-Access (File Added) 
+
+
+androsyn    2005/07/07 21:01:50 UTC    (20050707_1-20547)
+  Log:
+  test commit
+  
+
+  Modified:
+       ircd-ratbox/branches/RATBOX_2_1/RELNOTES (File Modified) 
+
+
+androsyn    2005/07/07 21:01:50 UTC    (20050707_0-20547)
+  Log:
+  test commit
+  
+
+  Modified:
+       ircd-ratbox/branches/RATBOX_2_1/RELNOTES (File Modified) 
+
+
+androsyn    2005/07/05 14:01:52 UTC    (20050705_2-19423)
+  Log:
+  revert omotd..i thought it was a good idea..oh well
+
+  Modified:
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_motd.c (File Modified) 
+
+
+androsyn    2005/07/05 04:55:42 UTC    (20050705_1-19411)
+  Log:
+  Commas are bad things in channel keys
+  
+
+  Modified:
+       ircd-ratbox/branches/RATBOX_2_1/modules/core/m_mode.c (File Modified) 
+
+
+androsyn    2005/07/05 04:16:51 UTC    (20050705_0-19405)
+  Log:
+  Add OMOTD command to display oper motd
+  
+
+  Modified:
+       ircd-ratbox/branches/RATBOX_2_1/modules/m_motd.c (File Modified) 
+
+
+androsyn    2005/07/04 08:27:58 UTC    (20050704_0-19391)
+  Log:
+  set m->prev = NULL in dlinkAdd, as it could possibly cause issues
+
+  Modified:
+       ircd-ratbox/branches/RATBOX_2_1/include/tools.h (File Modified) 
+
+
+leeh        2005/06/22 22:10:50 UTC    (20050622_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    modules              m_whois.c 
+  Log:
+  - stop testing whois for protocol violations, as they can be caused in
+    ircds going all the way back to the original ircd2.8
+  
+  Revision   Changes    Path
+  1.147.4.1  +20 -2     ircd-ratbox/modules/m_whois.c
+
+
+
+leeh        2005/06/16 23:10:21 UTC    (20050616_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    modules              m_time.c 
+  Log:
+  - remove some 2.2 code
+  
+  Revision  Changes    Path
+  1.45.8.2  +5 -4      ircd-ratbox/modules/m_time.c
+
+
+
+androsyn    2005/06/15 18:55:24 UTC    (20050615_2)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    modules              m_time.c 
+  Log:
+  backport of the silly december 31st bug
+  
+  Revision  Changes    Path
+  1.45.8.1  +6 -7      ircd-ratbox/modules/m_time.c
+
+
+
+leeh        2005/06/15 13:51:57 UTC    (20050615_1)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    .                    RELNOTES 
+    include              patchlevel.h 
+  Log:
+  - revved patchlevel to 2.1.3
+  
+  Revision   Changes    Path
+  1.114.2.3  +18 -0     ircd-ratbox/RELNOTES
+  7.73.2.3   +1 -1      ircd-ratbox/include/patchlevel.h
+
+
+
+leeh        2005/06/15 01:54:00 UTC    (20050615_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    include              client.h 
+    modules              m_accept.c 
+    modules/core         m_nick.c 
+    src                  client.c 
+  Log:
+  - stop removing a clients own list of accepted clients when they do a
+    nickchange
+  - clean up the accept code so its less retarded
+  
+  Revision   Changes    Path
+  7.266.4.3  +2 -2      ircd-ratbox/include/client.h
+  1.161.4.5  +16 -2     ircd-ratbox/modules/core/m_nick.c
+  1.59.4.1   +3 -2      ircd-ratbox/modules/m_accept.c
+  7.492.4.1  +9 -63     ircd-ratbox/src/client.c
+
+
+
+leeh        2005/06/14 12:44:47 UTC    (20050614_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    include              event.h 
+    modules              m_links.c 
+    src                  event.c ircd.c newconf.c 
+  Log:
+  - remove a defn of links_cache_list in m_links.c which was causing
+    the flattened links update to be ignored
+  - add eventUpdate(), and make links_delay update on rehash
+  
+  Revision   Changes    Path
+  1.19.8.1   +2 -0      ircd-ratbox/include/event.h
+  1.70.4.1   +1 -2      ircd-ratbox/modules/m_links.c
+  7.47.4.1   +25 -0     ircd-ratbox/src/event.c
+  7.374.4.1  +1 -1      ircd-ratbox/src/ircd.c
+  7.202.4.5  +2 -0      ircd-ratbox/src/newconf.c
+
+
+
+leeh        2005/06/12 02:23:01 UTC    (20050612_2)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    doc                  services.txt 
+    src                  newconf.c 
+  Log:
+  - make the conf parser apply service {}; on rehash
+  
+  Revision   Changes    Path
+  7.2.4.2    +8 -2      ircd-ratbox/doc/services.txt
+  7.202.4.4  +24 -4     ircd-ratbox/src/newconf.c
+
+
+
+leeh        2005/06/12 02:10:30 UTC    (20050612_1)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    include              m_info.h 
+  Log:
+  - show ENABLE_SERVICES define in info
+  
+  Revision  Changes    Path
+  7.56.4.2  +6 -0      ircd-ratbox/include/m_info.h
+
+
+
+leeh        2005/06/12 01:44:37 UTC    (20050612_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    modules              m_services.c m_stats.c 
+  Log:
+  - via jilles, make m_services.c hook into stats U and display service
+    blocks
+  
+  Revision   Changes    Path
+  1.6.4.7    +20 -1     ircd-ratbox/modules/m_services.c
+  1.243.4.3  +4 -4      ircd-ratbox/modules/m_stats.c
+
+
+
+leeh        2005/06/11 20:33:12 UTC    (20050611_3)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    .                    configure configure.ac 
+  Log:
+  - default build to -O2
+  
+  Revision   Changes    Path
+  7.249.2.2  +4 -4      ircd-ratbox/configure
+  7.63.2.2   +4 -4      ircd-ratbox/configure.ac
+
+
+
+leeh        2005/06/11 20:26:02 UTC    (20050611_2)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    doc                  example.conf example.efnet.conf 
+    include              client.h s_conf.h s_newconf.h 
+    modules              m_info.c 
+    modules/core         m_join.c m_nick.c 
+    src                  channel.c newconf.c s_conf.c s_user.c 
+  Log:
+  - remove no_oper_resvs from general {};
+  - add resv_exempt to auth {}; flags, exempts a user from nick/channel resvs
+  
+  Revision   Changes    Path
+  7.261.4.3  +1 -3      ircd-ratbox/doc/example.conf
+  7.89.4.3   +3 -3      ircd-ratbox/doc/example.efnet.conf
+  7.266.4.2  +3 -0      ircd-ratbox/include/client.h
+  7.315.4.1  +3 -2      ircd-ratbox/include/s_conf.h
+  7.46.4.1   +2 -3      ircd-ratbox/include/s_newconf.h
+  1.164.4.1  +4 -4      ircd-ratbox/modules/core/m_join.c
+  1.161.4.4  +2 -2      ircd-ratbox/modules/core/m_nick.c
+  1.122.4.1  +1 -7      ircd-ratbox/modules/m_info.c
+  7.436.4.1  +1 -1      ircd-ratbox/src/channel.c
+  7.202.4.3  +1 -1      ircd-ratbox/src/newconf.c
+  7.511.4.2  +0 -1      ircd-ratbox/src/s_conf.c
+  7.342.4.1  +8 -0      ircd-ratbox/src/s_user.c
+
+
+
+leeh        2005/06/11 20:06:22 UTC    (20050611_1)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    modules/core         m_mode.c m_nick.c 
+    src                  s_newconf.c 
+  Log:
+  - 2.0 sync:
+    - raise max temptime to a year
+    - tidy up BMASK
+    - require 9 parameters in ms_nick(), 10 in ms_uid()
+  
+  Revision   Changes    Path
+  1.121.4.2  +23 -9     ircd-ratbox/modules/core/m_mode.c
+  1.161.4.3  +23 -3     ircd-ratbox/modules/core/m_nick.c
+  7.67.4.1   +2 -2      ircd-ratbox/src/s_newconf.c
+
+
+
+leeh        2005/06/11 16:35:25 UTC    (20050611_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    modules              m_services.c 
+  Log:
+  - only show services logged in info when its a local client
+  
+  Revision  Changes    Path
+  1.6.4.6   +4 -1      ircd-ratbox/modules/m_services.c
+
+
+
+androsyn    2005/06/03 19:12:17 UTC    (20050603_1)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    src                  match.c 
+  Log:
+  passing a pointer to a pointer is not what was intended, oops
+  
+  Revision  Changes    Path
+  7.42.4.1  +3 -3      ircd-ratbox/src/match.c
+
+
+
+leeh        2005/06/03 11:18:11 UTC    (20050603_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    doc                  services.txt 
+  Log:
+  - update services.txt with FNC
+  
+  Revision  Changes    Path
+  7.2.4.1   +7 -0      ircd-ratbox/doc/services.txt
+
+
+
+androsyn    2005/05/30 16:47:27 UTC    (20050530_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    modules              m_resv.c 
+  Log:
+  use target_server and not parv[3] to check if the target server is us. thanks to jilles for the patch
+  
+  Revision  Changes    Path
+  1.74.4.3  +2 -2      ircd-ratbox/modules/m_resv.c
+
+
+
+leeh        2005/05/19 12:44:47 UTC    (20050519_1)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    src                  s_auth.c 
+  Log:
+  - add some uniqueness into auth process for bopm
+  
+  Revision   Changes    Path
+  7.192.4.3  +5 -0      ircd-ratbox/src/s_auth.c
+
+
+
+leeh        2005/05/19 08:50:26 UTC    (20050519_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    contrib              m_mkpasswd.c m_ojoin.c m_olist.c m_opme.c 
+  Log:
+  - make contrib/ compile
+  
+  Revision  Changes    Path
+  1.12.8.1  +2 -1      ircd-ratbox/contrib/m_mkpasswd.c
+  1.24.6.1  +2 -1      ircd-ratbox/contrib/m_ojoin.c
+  1.14.6.1  +2 -1      ircd-ratbox/contrib/m_olist.c
+  1.44.6.1  +2 -1      ircd-ratbox/contrib/m_opme.c
+
+
+
+androsyn    2005/05/18 22:01:55 UTC    (20050518_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    modules              m_monitor.c 
+  Log:
+  Don't allow MONITOR from an unregistered client
+  
+  Revision  Changes    Path
+  1.3.4.1   +2 -2      ircd-ratbox/modules/m_monitor.c
+
+
+
+leeh        2005/05/17 13:16:11 UTC    (20050517_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    doc                  example.conf example.efnet.conf 
+    include              class.h 
+    src                  class.c messages.tab newconf.c 
+  Log:
+  - remove sendq_eob, its become more of a hindrance than a benefit.
+  - sync example.efnet.conf cluster {}; with example.conf
+  
+  Revision   Changes    Path
+  7.261.4.2  +0 -3      ircd-ratbox/doc/example.conf
+  7.89.4.2   +17 -12    ircd-ratbox/doc/example.efnet.conf
+  7.25.4.1   +0 -3      ircd-ratbox/include/class.h
+  7.68.4.1   +2 -8      ircd-ratbox/src/class.c
+  7.126.4.1  +1 -1      ircd-ratbox/src/messages.tab
+  7.202.4.2  +0 -7      ircd-ratbox/src/newconf.c
+
+
+
+leeh        2005/05/11 22:39:00 UTC    (20050511_5)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    .                    RELNOTES 
+    include              patchlevel.h 
+  Log:
+  - update RELNOTES
+  - revved patchlevel to 2.1.2
+  
+  Revision   Changes    Path
+  1.114.2.2  +17 -0     ircd-ratbox/RELNOTES
+  7.73.2.2   +1 -1      ircd-ratbox/include/patchlevel.h
+
+
+
+leeh        2005/05/11 22:29:18 UTC    (20050511_4)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    .                    configure configure.ac 
+  Log:
+  - raise default topiclen to 160.
+  
+  Revision   Changes    Path
+  7.249.2.1  +3 -3      ircd-ratbox/configure
+  7.63.2.1   +3 -3      ircd-ratbox/configure.ac
+
+
+
+leeh        2005/05/11 22:22:13 UTC    (20050511_3)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    modules              m_services.c 
+  Log:
+  - add a current tsinfo param to RSFNC, only accept the fnc if the clients
+    tsinfo matches this
+  
+  Revision  Changes    Path
+  1.6.4.5   +23 -7     ircd-ratbox/modules/m_services.c
+
+
+
+leeh        2005/05/11 21:58:41 UTC    (20050511_2)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    modules              m_services.c 
+  Log:
+  - monitor_signoff() the client we're nickchanging
+  
+  Revision  Changes    Path
+  1.6.4.4   +3 -1      ircd-ratbox/modules/m_services.c
+
+
+
+leeh        2005/05/11 21:52:51 UTC    (20050511_1)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    modules              m_trace.c 
+  Log:
+  - fix various UID problems with trace
+  
+  Revision   Changes    Path
+  1.107.4.1  +16 -9     ircd-ratbox/modules/m_trace.c
+
+
+
+leeh        2005/05/11 21:22:02 UTC    (20050511_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    help/opers           dline kline 
+    modules              m_resv.c m_stats.c 
+    modules/core         m_mode.c 
+  Log:
+  - sync with 2.0
+    - tidy up kline/dline help to note they dont accept nick as target
+    - disallow bans beginning with ':' over bmask
+    - disallow bans with a space in chm_ban
+    - stop counting hidden opers in stats p
+    - match() parameters in remote unresv were inverted, causing it to fail
+    - fix possibility of clients setting blank keys
+  
+  Revision   Changes    Path
+  1.2.18.1   +1 -4      ircd-ratbox/help/opers/dline
+  1.2.24.1   +1 -1      ircd-ratbox/help/opers/kline
+  1.121.4.1  +15 -5     ircd-ratbox/modules/core/m_mode.c
+  1.74.4.2   +2 -2      ircd-ratbox/modules/m_resv.c
+  1.243.4.2  +5 -3      ircd-ratbox/modules/m_stats.c
+
+
+
+leeh        2005/05/08 22:37:18 UTC    (20050508_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    src                  send.c 
+  Log:
+  - fix problems with amd64 and the way we do va_list
+  
+  Revision   Changes    Path
+  7.286.4.1  +35 -21    ircd-ratbox/src/send.c
+
+
+
+leeh        2005/05/07 13:35:57 UTC    (20050507_1)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    modules              m_services.c 
+  Log:
+  - tidy up the kill notifications for RSFNC
+  
+  Revision  Changes    Path
+  1.6.4.3   +9 -2      ircd-ratbox/modules/m_services.c
+
+
+
+leeh        2005/05/07 10:35:54 UTC    (20050507_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    include              s_serv.h 
+    modules              m_services.c 
+    src                  s_serv.c 
+  Log:
+  - some more rserv stuff:
+    - add RSFNC capability
+    - fix up RSFNC, kill existing clients if they exist.
+  
+  Revision   Changes    Path
+  7.97.4.1   +3 -1      ircd-ratbox/include/s_serv.h
+  1.6.4.2    +24 -13    ircd-ratbox/modules/m_services.c
+  7.426.4.1  +1 -0      ircd-ratbox/src/s_serv.c
+
+
+
+leeh        2005/05/06 23:50:29 UTC    (20050506_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    modules              m_services.c 
+  Log:
+  - first stab at a FNC implementation for rserv
+  
+  Revision  Changes    Path
+  1.6.4.1   +86 -2     ircd-ratbox/modules/m_services.c
+
+
+
+leeh        2005/05/03 09:30:51 UTC    (20050503_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    help/opers           umode 
+  Log:
+  - remove a tab
+  
+  Revision  Changes    Path
+  1.5.4.2   +1 -1      ircd-ratbox/help/opers/umode
+
+
+
+leeh        2005/05/02 22:46:52 UTC    (20050502_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    src                  newconf.c 
+  Log:
+  - add links_delay back
+  
+  Revision   Changes    Path
+  7.202.4.1  +15 -0     ircd-ratbox/src/newconf.c
+
+
+
+leeh        2005/04/27 21:50:30 UTC    (20050427_1)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    help/opers           umode 
+    help/users           umode 
+  Log:
+  - swap tabs for spaces
+  
+  Revision  Changes    Path
+  1.5.4.1   +1 -1      ircd-ratbox/help/opers/umode
+  1.2.4.1   +1 -1      ircd-ratbox/help/users/umode
+
+
+
+leeh        2005/04/27 21:38:20 UTC    (20050427_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    include              m_info.h 
+  Log:
+  - remove the CLIENT_FLOOD define from m_info.h, as the informations already
+    contained in the client_flood conf option
+  - remove a couple of unused defines from info
+  
+  Revision  Changes    Path
+  7.56.4.1  +0 -20     ircd-ratbox/include/m_info.h
+
+
+
+androsyn    2005/04/26 16:04:29 UTC    (20050426_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    src                  s_conf.c 
+  Log:
+  use the correct field and swap to host byte order when displaying the Unauthorised connection message
+  
+  Revision   Changes    Path
+  7.511.4.1  +2 -2      ircd-ratbox/src/s_conf.c
+
+
+
+leeh        2005/04/17 13:31:34 UTC    (20050417_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    doc                  example.conf example.efnet.conf 
+  Log:
+  - fix missing closing comment tag
+  
+  Revision   Changes    Path
+  7.261.4.1  +1 -1      ircd-ratbox/doc/example.conf
+  7.89.4.1   +1 -1      ircd-ratbox/doc/example.efnet.conf
+
+
+
+leeh        2005/04/12 18:44:21 UTC    (20050412_2)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    .                    RELNOTES 
+    include              patchlevel.h 
+  Log:
+  - revved patchlevel to 2.1.1
+  
+  Revision   Changes    Path
+  1.114.2.1  +11 -0     ircd-ratbox/RELNOTES
+  7.73.2.1   +1 -1      ircd-ratbox/include/patchlevel.h
+
+
+
+leeh        2005/04/12 18:36:31 UTC    (20050412_1)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    modules              m_kline.c 
+  Log:
+  - sync up remote kline reasons, so theyre consistent with what happens
+    when we add local klines - notably the "Temporary K-line x min" and
+    date added to reason.
+  
+  Revision   Changes    Path
+  1.200.4.1  +14 -5     ircd-ratbox/modules/m_kline.c
+
+
+
+leeh        2005/04/12 01:52:06 UTC    (20050412_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    doc                  monitor.txt 
+  Log:
+  - force the monitor spec to state RPL_MONONLINE must give n!u@h
+  
+  Revision  Changes    Path
+  1.3.4.2   +1 -4      ircd-ratbox/doc/monitor.txt
+
+
+
+androsyn    2005/04/08 22:00:05 UTC    (20050408_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    src                  commio.c 
+  Log:
+  used the data pointer we saved, not what just got nulled
+  
+  Revision  Changes    Path
+  1.27.4.1  +1 -1      ircd-ratbox/src/commio.c
+
+
+
+leeh        2005/04/05 12:14:32 UTC    (20050405_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    modules              m_resv.c m_xline.c 
+  Log:
+  - fix broken propagation of xline/resv
+  
+  Revision  Changes    Path
+  1.74.4.1  +2 -2      ircd-ratbox/modules/m_resv.c
+  1.67.4.1  +2 -2      ircd-ratbox/modules/m_xline.c
+
+
+
+leeh        2005/04/04 18:32:37 UTC    (20050404_1)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    src                  s_auth.c 
+  Log:
+  - properly increment bad auth count for stats T when we timeout an auth
+  
+  Revision   Changes    Path
+  7.192.4.2  +1 -0      ircd-ratbox/src/s_auth.c
+
+
+
+leeh        2005/04/04 17:24:14 UTC    (20050404_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    doc                  monitor.txt 
+    include              client.h 
+    modules/core         m_nick.c 
+  Log:
+  - fix a bit that didnt make sense in monitor.txt
+  - make HOSTIPLEN always v6 sized, so we can always store a v6 clients ip
+  
+  Revision   Changes    Path
+  1.3.4.1    +1 -1      ircd-ratbox/doc/monitor.txt
+  7.266.4.1  +2 -4      ircd-ratbox/include/client.h
+  1.161.4.2  +2 -13     ircd-ratbox/modules/core/m_nick.c
+
+
+
+androsyn    2005/03/28 21:55:44 UTC    (20050328_1)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    src                  s_auth.c 
+  Log:
+  removing dlink nodes from auth_poll_list twice is bad
+  
+  Revision   Changes    Path
+  7.192.4.1  +0 -1      ircd-ratbox/src/s_auth.c
+
+
+
+leeh        2005/03/28 02:17:38 UTC    (20050328_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    modules              m_stats.c 
+  Log:
+  - move stats L back to RPL_STATSLINKINFO, im not quite sure why this got
+    changed to RPL_STATSDEBUG
+  
+  Revision   Changes    Path
+  1.243.4.1  +4 -4      ircd-ratbox/modules/m_stats.c
+
+
+
+leeh        2005/03/27 02:19:04 UTC    (20050327_0)
+
+  Added files:           (Branch: RATBOX_2_1)
+    doc                  tgchange.txt 
+  Log:
+  - add some documentation about target change
+  
+  Revision  Changes    Path
+  1.1.2.1   +38 -0     ircd-ratbox/doc/tgchange.txt (new)
+
+
+
+leeh        2005/03/25 16:46:29 UTC    (20050325_1)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    include              supported.h 
+    modules/core         m_message.c 
+  Log:
+  - remove extra argument to 005
+  - disallow messaging of UIDs
+  
+  Revision   Changes    Path
+  7.5.4.2    +1 -1      ircd-ratbox/include/supported.h
+  1.162.4.2  +11 -3     ircd-ratbox/modules/core/m_message.c
+
+
+
+leeh        2005/03/25 14:20:13 UTC    (20050325_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    src                  parse.c 
+  Log:
+  - fix a longstanding parser bug with wrong limit checking, causing us to
+    accept one less parameter than we're allowed to accept.
+  
+  Revision   Changes    Path
+  7.187.4.1  +7 -4      ircd-ratbox/src/parse.c
+
+
+
+leeh        2005/03/24 13:41:45 UTC    (20050324_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    modules/core         m_message.c 
+  Log:
+  - exempt users messaging themselves from target change
+  
+  Revision   Changes    Path
+  1.162.4.1  +5 -1      ircd-ratbox/modules/core/m_message.c
+
+
+
+leeh        2005/03/22 13:15:53 UTC    (20050322_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    include              supported.h 
+  Log:
+  - stop violating MAXPARA on 005.
+  
+  Revision  Changes    Path
+  7.5.4.1   +3 -4      ircd-ratbox/include/supported.h
+
+
+
+leeh        2005/03/20 17:41:00 UTC    (20050320_1)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    modules/core         m_nick.c 
+  Log:
+  - dont store an ipv6 sockhost if we're not compiled with v6 support
+  
+  Revision   Changes    Path
+  1.161.4.1  +13 -2     ircd-ratbox/modules/core/m_nick.c
+
+
+
+leeh        2005/03/20 00:32:04 UTC    (20050320_0)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    include              stdinc.h 
+  Log:
+  - remove some vms includes
+  
+  Revision  Changes    Path
+  1.19.4.1  +0 -46     ircd-ratbox/include/stdinc.h
+
+
+
+leeh        2005/03/18 16:47:38 UTC    (20050318_1)
+
+  Modified files:        (Branch: RATBOX_2_1)
+    .                    ChangeLog 
+    include              serno.h 
+  Log:
+  - force commit for new branch
+  
+  Revision    Changes    Path
+  1.1694.2.1  +0 -0      ircd-ratbox/ChangeLog
+  7.5463.2.1  +0 -0      ircd-ratbox/include/serno.h
+
+
+
+leeh        2005/03/18 16:44:47 UTC    (20050318_0)
+
+  Modified files:
+    .                    RELNOTES configure configure.ac 
+    include              patchlevel.h 
+  Log:
+  - revved patchlevel to 2.1.0
+  
+  Revision  Changes    Path
+  1.114     +6 -2      ircd-ratbox/RELNOTES
+  7.249     +11 -11    ircd-ratbox/configure
+  7.63      +3 -3      ircd-ratbox/configure.ac
+  7.73      +1 -1      ircd-ratbox/include/patchlevel.h
+
+
+
+leeh        2005/03/04 13:31:32 EST    (20050304_2)
+
+  Modified files:
+    .                    RELNOTES 
+    include              patchlevel.h 
+  Log:
+  - update RELNOTES
+  - revved patchlevel to 2.1.0beta2
+  
+  Revision  Changes    Path
+  1.113     +12 -0     ircd-ratbox/RELNOTES
+  7.72      +1 -1      ircd-ratbox/include/patchlevel.h
+
+
+
+leeh        2005/03/04 13:27:05 EST    (20050304_1)
+
+  Modified files:
+    doc                  whats-new-2.1.txt 
+    src                  channel.c 
+  Log:
+  - update whats-new-2.1
+  - when we're handling global NAMES, dont output channels if there are no
+    members within them we can show.
+  
+  Revision  Changes    Path
+  7.3       +9 -2      ircd-ratbox/doc/whats-new-2.1.txt
+  7.436     +12 -2     ircd-ratbox/src/channel.c
+
+
+
+androsyn    2005/03/04 12:38:07 EST    (20050304_0)
+
+  Modified files:
+    src                  patricia.c 
+  Log:
+  That would be a node_heap not a prefix_heap..oops
+  
+  Revision  Changes    Path
+  7.30      +1 -1      ircd-ratbox/src/patricia.c
+
+
+
+androsyn    2005/02/26 19:38:35 EST    (20050227_4)
+
+  Modified files:
+    include              stdinc.h 
+  Log:
+  sort out some alloca related stupidness.  if we have gcc just use the builtin for it
+  otherwise..the other macros might work????
+  
+  Revision  Changes    Path
+  1.19      +15 -6     ircd-ratbox/include/stdinc.h
+
+
+
+androsyn    2005/02/26 19:26:04 EST    (20050227_3)
+
+  Modified files:
+    .                    configure configure.ac 
+  Log:
+  i hate autoconf
+  
+  Revision  Changes    Path
+  7.248     +5 -5      ircd-ratbox/configure
+  7.62      +5 -5      ircd-ratbox/configure.ac
+
+
+
+androsyn    2005/02/26 19:15:55 EST    (20050227_2)
+
+  Modified files:
+    .                    configure configure.ac 
+  Log:
+  i hate autoconf
+  
+  Revision  Changes    Path
+  7.247     +3 -2      ircd-ratbox/configure
+  7.61      +3 -2      ircd-ratbox/configure.ac
+
+
+
+androsyn    2005/02/26 19:13:45 EST    (20050227_1)
+
+  Modified files:
+    .                    configure configure.ac 
+  Log:
+  doh
+  
+  Revision  Changes    Path
+  7.246     +6 -6      ircd-ratbox/configure
+  7.60      +4 -4      ircd-ratbox/configure.ac
+
+
+
+androsyn    2005/02/26 19:10:17 EST    (20050227_0)
+
+  Modified files:
+    .                    configure configure.ac 
+    include              stdinc.h 
+  Log:
+  Doh these changes got put on RATBOX_2_0 when they were meant for
+  head..oops...
+  Also merged in the monitor heap size stuff, not that i think monitor has
+  been moved to head
+  
+  Revision  Changes    Path
+  7.245     +12 -3     ircd-ratbox/configure
+  7.59      +11 -3     ircd-ratbox/configure.ac
+  1.18      +57 -20    ircd-ratbox/include/stdinc.h
+
+
+
+androsyn    2005/02/26 18:52:24 EST    (20050226_0)
+
+  Modified files:
+    include              stdinc.h 
+  Log:
+  Add more robust alloca checking
+  
+  Revision  Changes    Path
+  1.17      +20 -11    ircd-ratbox/include/stdinc.h
+
+
+
+leeh        2005/02/24 15:27:17 EST    (20050224_9)
+
+  Modified files:
+    contrib              m_42.c 
+  Log:
+  - fix the copyright on m_42.c :p
+  
+  Revision  Changes    Path
+  1.4       +2 -2      ircd-ratbox/contrib/m_42.c
+
+
+
+leeh        2005/02/24 15:22:53 EST    (20050224_8)
+
+  Modified files:
+    include              supported.h 
+    modules              m_dline.c 
+  Log:
+  - fix a core in undline on bad masks
+  - remove an unwanted space from beginning of second 005 numeric
+  
+  Revision  Changes    Path
+  7.5       +1 -1      ircd-ratbox/include/supported.h
+  1.49      +8 -1      ircd-ratbox/modules/m_dline.c
+
+
+
+leeh        2005/02/24 15:18:59 EST    (20050224_7)
+
+  Modified files:
+    modules              m_monitor.c 
+  Log:
+  - use max_monitor when adding nicknames
+  - add in monitor s
+    that should be everything now..
+  
+  Revision  Changes    Path
+  1.3       +90 -1     ircd-ratbox/modules/m_monitor.c
+
+
+
+androsyn    2005/02/24 15:13:52 EST    (20050224_6)
+
+  Modified files:
+    contrib              m_42.c 
+  Log:
+  42
+  
+  Revision  Changes    Path
+  1.3       +1 -1      ircd-ratbox/contrib/m_42.c
+
+
+
+androsyn    2005/02/24 15:13:06 EST    (20050224_5)
+
+  Modified files:
+    contrib              m_42.c 
+  Log:
+  42
+  
+  Revision  Changes    Path
+  1.2       +1 -1      ircd-ratbox/contrib/m_42.c
+
+
+
+androsyn    2005/02/24 15:12:12 EST    (20050224_4)
+
+  Added files:
+    contrib              m_42.c 
+  Log:
+  The Answer to Life, the Universe, and Everything
+  
+  Revision  Changes    Path
+  1.1       +35 -0     ircd-ratbox/contrib/m_42.c (new)
+
+
+
+leeh        2005/02/24 14:53:04 EST    (20050224_3)
+
+  Modified files:
+    include              monitor.h 
+    modules              m_monitor.c 
+    src                  ircd.c monitor.c 
+  Log:
+  - call init_monitor() on startup
+  - add in support for adding/deleting/listing monitor entries
+  
+  Revision  Changes    Path
+  7.2       +3 -1      ircd-ratbox/include/monitor.h
+  1.2       +155 -1    ircd-ratbox/modules/m_monitor.c
+  7.374     +2 -0      ircd-ratbox/src/ircd.c
+  7.3       +15 -4     ircd-ratbox/src/monitor.c
+
+
+
+leeh        2005/02/23 21:20:10 EST    (20050224_2)
+
+  Modified files:
+    doc                  example.conf example.efnet.conf 
+    include              s_conf.h supported.h 
+    modules              Makefile.in 
+    src                  client.c newconf.c s_conf.c 
+  Added files:
+    modules              m_monitor.c 
+  Log:
+  - add the max_monitor config option
+  - advertise MONITOR=%d in 005
+  - clear a local clients monitor list on exit
+  - add the framework for the MONITOR command
+  - bed.
+  
+  Revision  Changes    Path
+  7.261     +5 -0      ircd-ratbox/doc/example.conf
+  7.89      +5 -0      ircd-ratbox/doc/example.efnet.conf
+  7.315     +1 -0      ircd-ratbox/include/s_conf.h
+  7.4       +4 -2      ircd-ratbox/include/supported.h
+  1.119     +1 -0      ircd-ratbox/modules/Makefile.in
+  1.1       +95 -0     ircd-ratbox/modules/m_monitor.c (new)
+  7.492     +1 -0      ircd-ratbox/src/client.c
+  7.202     +1 -0      ircd-ratbox/src/newconf.c
+  7.511     +1 -0      ircd-ratbox/src/s_conf.c
+
+
+
+leeh        2005/02/23 20:57:51 EST    (20050224_1)
+
+  Modified files:
+    .                    configure configure.ac 
+    include              setup.h.in 
+    src                  monitor.c 
+  Log:
+  - move MONITOR_HEAP_SIZE over to configure
+  
+  Revision  Changes    Path
+  7.244                ircd-ratbox/configure
+  7.58      +4 -2      ircd-ratbox/configure.ac
+  7.95      +3 -0      ircd-ratbox/include/setup.h.in
+  7.2       +0 -2      ircd-ratbox/src/monitor.c
+
+
+
+leeh        2005/02/23 20:48:08 EST    (20050224_0)
+
+  Modified files:
+    doc                  monitor.txt 
+    include              client.h numeric.h 
+    modules/core         m_nick.c 
+    src                  Makefile.in client.c messages.tab 
+                         s_user.c 
+  Added files:
+    include              monitor.h 
+    src                  monitor.c 
+  Log:
+  - first half of my server-side notify list implementation..
+  
+  Revision  Changes    Path
+  1.3       +2 -2      ircd-ratbox/doc/monitor.txt
+  7.266     +3 -0      ircd-ratbox/include/client.h
+  7.1       +30 -0     ircd-ratbox/include/monitor.h (new)
+  7.58      +6 -0      ircd-ratbox/include/numeric.h
+  1.161     +17 -3     ircd-ratbox/modules/core/m_nick.c
+  7.155     +1 -0      ircd-ratbox/src/Makefile.in
+  7.491     +3 -0      ircd-ratbox/src/client.c
+  7.126     +5 -5      ircd-ratbox/src/messages.tab
+  7.1       +182 -0    ircd-ratbox/src/monitor.c (new)
+  7.342     +2 -0      ircd-ratbox/src/s_user.c
+
+
+
+leeh        2005/02/23 18:42:59 EST    (20050223_0)
+
+  Modified files:
+    include              hash.h 
+  Log:
+  - double the size of the client and channel hashtables (64k -> 128k and
+    32k -> 64k).  The improvements are quite significant..
+  
+  Revision  Changes    Path
+  7.54      +4 -4      ircd-ratbox/include/hash.h
+
+
+
+leeh        2005/02/22 14:55:56 EST    (20050222_1)
+
+  Modified files:
+    doc                  monitor.txt 
+    modules              m_services.c 
+  Log:
+  - remove a couple of unused vars
+  - update monitor.txt
+  
+  Revision  Changes    Path
+  1.2       +14 -0     ircd-ratbox/doc/monitor.txt
+  1.6       +1 -4      ircd-ratbox/modules/m_services.c
+
+
+
+leeh        2005/02/21 19:47:24 EST    (20050222_0)
+
+  Added files:
+    doc                  monitor.txt 
+  Log:
+  - add in my documentation on the upcoming MONITOR command
+  
+  Revision  Changes    Path
+  1.1       +100 -0    ircd-ratbox/doc/monitor.txt (new)
+
+
+
+leeh        2005/02/21 12:09:34 EST    (20050221_0)
+
+  Modified files:
+    .                    configure configure.ac 
+    doc                  whats-new-2.1.txt 
+    tools                README.mkpasswd 
+  Removed files:
+    src                  crypt.c 
+  Log:
+  - update whats-new-2.1.txt some more
+  - we dont have vms mkpasswd anymore
+  - remove the unused crypt.c
+  
+  Revision  Changes    Path
+  7.243     +3 -6      ircd-ratbox/configure
+  7.57      +2 -4      ircd-ratbox/configure.ac
+  7.2       +2 -0      ircd-ratbox/doc/whats-new-2.1.txt
+  7.13      +0 -504    ircd-ratbox/src/crypt.c (dead)
+  1.9       +0 -3      ircd-ratbox/tools/README.mkpasswd
+
+
+
+leeh        2005/02/19 12:38:09 EST    (20050219_3)
+
+  Modified files:
+    doc                  example.conf example.efnet.conf 
+    include              ircd.h 
+    modules              m_pong.c 
+    src                  channel.c client.c ircd.c s_conf.c 
+  Log:
+  - rework the splitcode, splitservers is now how many servers we've marked as
+    EOB, rather than how many are linked.  Thus pull ourselves out of
+    splitmode immediately once this is satisfied
+  
+  Revision  Changes    Path
+  7.260     +8 -9      ircd-ratbox/doc/example.conf
+  7.88      +10 -11    ircd-ratbox/doc/example.efnet.conf
+  7.83      +1 -0      ircd-ratbox/include/ircd.h
+  1.60      +2 -1      ircd-ratbox/modules/m_pong.c
+  7.435     +16 -36    ircd-ratbox/src/channel.c
+  7.490     +2 -0      ircd-ratbox/src/client.c
+  7.373     +2 -1      ircd-ratbox/src/ircd.c
+  7.510     +11 -3     ircd-ratbox/src/s_conf.c
+
+
+
+leeh        2005/02/19 09:02:34 EST    (20050219_2)
+
+  Modified files:
+    doc                  example.conf example.efnet.conf 
+    include              ircd.h s_conf.h 
+    modules              m_set.c 
+    src                  channel.c ircd.c newconf.c s_conf.c 
+  Log:
+  - remove split_delay
+  
+  Revision  Changes    Path
+  7.259     +0 -5      ircd-ratbox/doc/example.conf
+  7.87      +0 -5      ircd-ratbox/doc/example.efnet.conf
+  7.82      +0 -1      ircd-ratbox/include/ircd.h
+  7.314     +0 -1      ircd-ratbox/include/s_conf.h
+  1.81      +1 -20     ircd-ratbox/modules/m_set.c
+  7.434     +2 -7      ircd-ratbox/src/channel.c
+  7.372     +0 -1      ircd-ratbox/src/ircd.c
+  7.201     +0 -1      ircd-ratbox/src/newconf.c
+  7.509     +0 -1      ircd-ratbox/src/s_conf.c
+
+
+
+leeh        2005/02/19 08:48:05 EST    (20050219_1)
+
+  Modified files:
+    include              client.h 
+    modules              m_cap.c m_who.c 
+    src                  channel.c 
+  Log:
+  - implemented multi-prefix client capability, which allows stacking of @+ in
+    names and who
+  
+  Revision  Changes    Path
+  7.265     +1 -1      ircd-ratbox/include/client.h
+  1.6       +6 -15     ircd-ratbox/modules/m_cap.c
+  1.115     +4 -3      ircd-ratbox/modules/m_who.c
+  7.433     +4 -6      ircd-ratbox/src/channel.c
+
+
+
+leeh        2005/02/19 06:27:58 EST    (20050219_0)
+
+  Modified files:
+    modules              m_etrace.c 
+    src                  newconf.c s_conf.c s_newconf.c 
+  Log:
+  - removed some unused vars/functions
+  
+  Revision  Changes    Path
+  1.15      +1 -2      ircd-ratbox/modules/m_etrace.c
+  7.200     +0 -15     ircd-ratbox/src/newconf.c
+  7.508     +0 -1      ircd-ratbox/src/s_conf.c
+  7.67      +0 -1      ircd-ratbox/src/s_newconf.c
+
+
+
+leeh        2005/02/16 12:58:24 EST    (20050216_2)
+
+  Modified files:
+    .                    RELNOTES configure configure.ac 
+    include              patchlevel.h 
+  Log:
+  - update configure to reflect this is 'devel'
+  - update RELNOTES
+  - revved patchlevel to 2.1.0beta1
+  
+  Revision  Changes    Path
+  1.112     +9 -1      ircd-ratbox/RELNOTES
+  7.242     +11 -11    ircd-ratbox/configure
+  7.56      +3 -3      ircd-ratbox/configure.ac
+  7.71      +1 -1      ircd-ratbox/include/patchlevel.h
+
+
+
+leeh        2005/02/16 12:46:30 EST    (20050216_1)
+
+  Modified files:
+    .                    configure configure.ac 
+    include              client.h numeric.h s_conf.h setup.h.in 
+                         supported.h 
+    modules              Makefile.in 
+    modules/core         m_nick.c 
+    src                  Makefile.in client.c ircd.c messages.tab 
+                         newconf.c s_conf.c s_user.c 
+  Removed files:
+    include              watch.h 
+    modules              m_watch.c 
+    src                  watch.c 
+  Log:
+  - remove watch, the protocol for this sucks so hard I just dont want it
+    here ;-)
+  
+  Revision  Changes    Path
+  7.241     +2 -12     ircd-ratbox/configure
+  7.55      +2 -4      ircd-ratbox/configure.ac
+  7.264     +0 -2      ircd-ratbox/include/client.h
+  7.57      +0 -11     ircd-ratbox/include/numeric.h
+  7.313     +0 -1      ircd-ratbox/include/s_conf.h
+  7.94      +0 -3      ircd-ratbox/include/setup.h.in
+  7.3       +2 -3      ircd-ratbox/include/supported.h
+  7.4       +0 -53     ircd-ratbox/include/watch.h (dead)
+  1.118     +0 -1      ircd-ratbox/modules/Makefile.in
+  1.160     +1 -16     ircd-ratbox/modules/core/m_nick.c
+  1.8       +0 -272    ircd-ratbox/modules/m_watch.c (dead)
+  7.154     +0 -1      ircd-ratbox/src/Makefile.in
+  7.489     +0 -3      ircd-ratbox/src/client.c
+  7.371     +0 -2      ircd-ratbox/src/ircd.c
+  7.125     +9 -9      ircd-ratbox/src/messages.tab
+  7.199     +0 -1      ircd-ratbox/src/newconf.c
+  7.507     +0 -1      ircd-ratbox/src/s_conf.c
+  7.341     +0 -2      ircd-ratbox/src/s_user.c
+  1.7       +0 -239    ircd-ratbox/src/watch.c (dead)
+
+
+
+leeh        2005/02/15 19:13:31 EST    (20050216_0)
+
+  Modified files:
+    include              stdinc.h 
+    src                  event.c ircd_lexer.l ircd_signal.c 
+                         modules.c 
+  Removed files:
+    servlink             descrip.mms 
+  Log:
+  - remove a few vms bits
+  
+  Revision  Changes    Path
+  1.16      +0 -46     ircd-ratbox/include/stdinc.h
+  1.4       +0 -15     ircd-ratbox/servlink/descrip.mms (dead)
+  7.47      +0 -54     ircd-ratbox/src/event.c
+  1.168     +1 -5      ircd-ratbox/src/ircd_lexer.l
+  7.27      +0 -25     ircd-ratbox/src/ircd_signal.c
+  7.152     +0 -3      ircd-ratbox/src/modules.c
+
+
+
+leeh        2005/02/15 18:53:32 EST    (20050215_0)
+
+  Modified files:
+    include              hostmask.h ircd.h s_conf.h s_newconf.h 
+    modules              m_dline.c m_kline.c m_rehash.c m_resv.c 
+                         m_xline.c 
+    src                  hostmask.c ircd.c ircd_signal.c s_conf.c 
+                         s_newconf.c 
+  Log:
+  - we now no longer rehash kline.conf etc on rehash, only ircd.conf
+  - SIGUSR2 or /rehash bans will now reread kline.conf etc.
+  
+  Revision  Changes    Path
+  1.42      +1 -0      ircd-ratbox/include/hostmask.h
+  7.81      +1 -0      ircd-ratbox/include/ircd.h
+  7.312     +1 -0      ircd-ratbox/include/s_conf.h
+  7.46      +1 -0      ircd-ratbox/include/s_newconf.h
+  1.48      +2 -2      ircd-ratbox/modules/m_dline.c
+  1.200     +2 -2      ircd-ratbox/modules/m_kline.c
+  1.89      +11 -1     ircd-ratbox/modules/m_rehash.c
+  1.74      +2 -2      ircd-ratbox/modules/m_resv.c
+  1.67      +2 -2      ircd-ratbox/modules/m_xline.c
+  7.106     +35 -1     ircd-ratbox/src/hostmask.c
+  7.370     +7 -0      ircd-ratbox/src/ircd.c
+  7.26      +10 -0     ircd-ratbox/src/ircd_signal.c
+  7.506     +59 -47    ircd-ratbox/src/s_conf.c
+  7.66      +7 -0      ircd-ratbox/src/s_newconf.c
+
+
+
+leeh        2005/02/13 10:21:41 EST    (20050213_4)
+
+  Modified files:
+    doc                  services.txt 
+  Added files:
+    doc                  whats-new-2.0.txt whats-new-2.1.txt 
+  Removed files:
+    doc                  whats-new.txt 
+  Log:
+  - move whats-new.txt to whats-new-2.0.txt
+  - add in whats-new-2.1.txt
+  - update services.txt with the whois for logged in users
+  
+  Revision  Changes    Path
+  7.2       +5 -0      ircd-ratbox/doc/services.txt
+  7.1       +113 -0    ircd-ratbox/doc/whats-new-2.0.txt (new)
+  7.1       +60 -0     ircd-ratbox/doc/whats-new-2.1.txt (new)
+  7.51      +0 -113    ircd-ratbox/doc/whats-new.txt (dead)
+
+
+
+leeh        2005/02/13 09:20:37 EST    (20050213_3)
+
+  Modified files:
+    include              supported.h 
+    modules/core         m_message.c 
+  Log:
+  - fix a compile error in m_message.c
+  - update 005 to the spec and add CPRIVMSG/CNOTICE
+  
+  Revision  Changes    Path
+  7.2       +31 -37    ircd-ratbox/include/supported.h
+  1.162     +2 -2      ircd-ratbox/modules/core/m_message.c
+
+
+
+leeh        2005/02/13 09:14:12 EST    (20050213_2)
+
+  Modified files:
+    src                  channel.c 
+  Log:
+  - fix the membership memleak
+  
+  Revision  Changes    Path
+  7.432     +0 -3      ircd-ratbox/src/channel.c
+
+
+
+leeh        2005/02/12 21:51:56 EST    (20050213_1)
+
+  Modified files:
+    include              client.h 
+    modules/core         m_message.c 
+  Log:
+  - add a bitmask to track when they send their first message, only allowing
+    clearing stuff after that.
+  
+  Revision  Changes    Path
+  7.263     +4 -0      ircd-ratbox/include/client.h
+  1.161     +13 -2     ircd-ratbox/modules/core/m_message.c
+
+
+
+leeh        2005/02/12 21:17:52 EST    (20050213_0)
+
+  Modified files:
+    include              patricia.h s_newconf.h 
+    modules/core         m_message.c 
+    src                  patricia.c s_newconf.c s_user.c 
+  Log:
+  - add in the patricia for tracking who fills up targets, give them a reduced
+    count on connect
+  
+  Revision  Changes    Path
+  7.20      +1 -1      ircd-ratbox/include/patricia.h
+  7.45      +17 -0     ircd-ratbox/include/s_newconf.h
+  1.160     +43 -4     ircd-ratbox/modules/core/m_message.c
+  7.29      +1 -1      ircd-ratbox/src/patricia.c
+  7.65      +36 -0     ircd-ratbox/src/s_newconf.c
+  7.340     +4 -0      ircd-ratbox/src/s_user.c
+
+
+
+leeh        2005/02/12 18:35:10 EST    (20050212_0)
+
+  Modified files:
+    include              ircd_defs.h 
+    src                  class.c reject.c 
+  Log:
+  - add a PATRICIA_BITS define, make calls to New_Patricia() use it.
+  
+  Revision  Changes    Path
+  7.55      +5 -0      ircd-ratbox/include/ircd_defs.h
+  7.68      +1 -5      ircd-ratbox/src/class.c
+  1.33      +1 -5      ircd-ratbox/src/reject.c
+
+
+
+androsyn    2005/02/11 17:11:57 EST    (20050211_1)
+
+  Modified files:
+    modules              m_watch.c 
+  Log:
+  remove stupid memory leak
+  
+  Revision  Changes    Path
+  1.7       +1 -2      ircd-ratbox/modules/m_watch.c
+
+
+
+leeh        2005/02/11 06:42:48 EST    (20050211_0)
+
+  Modified files:
+    modules              m_gline.c 
+  Log:
+  - workaround hyb6 allowing empty gline reasons
+  
+  Revision  Changes    Path
+  1.150     +10 -2     ircd-ratbox/modules/m_gline.c
+
+
+
+leeh        2005/02/09 14:39:13 EST    (20050209_2)
+
+  Modified files:
+    include              s_conf.h 
+    modules              m_dline.c m_kline.c m_rehash.c m_stats.c 
+    src                  ircd.c s_conf.c 
+  Log:
+  - move temp dlines and temp klines over to an array, rather than completely
+    seperate dlinks.
+  
+  Revision  Changes    Path
+  7.311     +11 -20    ircd-ratbox/include/s_conf.h
+  1.47      +4 -15     ircd-ratbox/modules/m_dline.c
+  1.199     +4 -15     ircd-ratbox/modules/m_kline.c
+  1.88      +42 -26    ircd-ratbox/modules/m_rehash.c
+  1.243     +22 -31    ircd-ratbox/modules/m_stats.c
+  7.369     +0 -5      ircd-ratbox/src/ircd.c
+  7.505     +78 -104   ircd-ratbox/src/s_conf.c
+
+
+
+leeh        2005/02/09 14:02:13 EST    (20050209_1)
+
+  Modified files:
+    include              s_user.h 
+    modules              m_cap.c m_pong.c m_user.c 
+    modules/core         m_nick.c 
+    src                  s_user.c 
+  Log:
+  - remove 'nick' param from register_local_user(), its not needed.
+  
+  Revision  Changes    Path
+  7.35      +1 -1      ircd-ratbox/include/s_user.h
+  1.159     +2 -2      ircd-ratbox/modules/core/m_nick.c
+  1.5       +2 -2      ircd-ratbox/modules/m_cap.c
+  1.59      +2 -3      ircd-ratbox/modules/m_pong.c
+  1.46      +2 -2      ircd-ratbox/modules/m_user.c
+  7.339     +6 -6      ircd-ratbox/src/s_user.c
+
+
+
+leeh        2005/02/09 13:12:53 EST    (20050209_0)
+
+  Modified files:
+    modules              m_cmessage.c 
+  Log:
+  - dont send numerics when we're dealing with CNOTICE
+  - add in checking for +g, and resetting idle
+  
+  Revision  Changes    Path
+  1.2       +41 -7     ircd-ratbox/modules/m_cmessage.c
+
+
+
+leeh        2005/02/08 11:37:50 EST    (20050208_2)
+
+  Modified files:
+    src                  s_newconf.c 
+  Log:
+  - fix operator blocks to work on ip spoofs
+  
+  Revision  Changes    Path
+  7.64      +9 -8      ircd-ratbox/src/s_newconf.c
+
+
+
+leeh        2005/02/07 19:23:22 EST    (20050208_1)
+
+  Modified files:
+    doc                  example.conf example.efnet.conf 
+    src                  newconf.c 
+  Log:
+  - removed ability to set klines/dlines/xlines/resvs in ircd.conf
+  
+  Revision  Changes    Path
+  7.258     +0 -39     ircd-ratbox/doc/example.conf
+  7.86      +0 -42     ircd-ratbox/doc/example.efnet.conf
+  7.198     +0 -272    ircd-ratbox/src/newconf.c
+
+
+
+leeh        2005/02/07 19:19:32 EST    (20050208_0)
+
+  Modified files:
+    src                  s_conf.c 
+  Log:
+  - added support for kline.conf.perm et al, these take the same formats
+    as their non-permanent partners, but you cant remove them via the ircd.
+  
+  Revision  Changes    Path
+  7.504     +33 -67    ircd-ratbox/src/s_conf.c
+
+
+
+leeh        2005/02/02 19:18:59 EST    (20050203_1)
+
+  Modified files:
+    help                 Makefile.in 
+    help/opers           index 
+    help/users           index 
+  Added files:
+    help/opers           cnotice cprivmsg 
+  Log:
+  - added help files for cprivmsg/cnotice
+  
+  Revision  Changes    Path
+  1.23      +3 -2      ircd-ratbox/help/Makefile.in
+  1.1       +5 -0      ircd-ratbox/help/opers/cnotice (new)
+  1.1       +5 -0      ircd-ratbox/help/opers/cprivmsg (new)
+  1.10      +19 -19    ircd-ratbox/help/opers/index
+  1.7       +10 -9     ircd-ratbox/help/users/index
+
+
+
+leeh        2005/02/02 19:14:25 EST    (20050203_0)
+
+  Modified files:
+    include              numeric.h 
+    modules              Makefile.in 
+    src                  messages.tab 
+  Added files:
+    modules              m_cmessage.c 
+  Log:
+  - implemented CPRIVMSG/CNOTICE, stolen from undernet.  Take the form:
+    CPRIVMSG <nick> <channel> :<text>.  Work if sender is +ov in channel, and
+    nick is a member.  These bypass any target change limitations.
+  - added ERR_VOICENEEDED, numeric 489.
+  
+  Revision  Changes    Path
+  7.56      +2 -0      ircd-ratbox/include/numeric.h
+  1.117     +1 -0      ircd-ratbox/modules/Makefile.in
+  1.1       +122 -0    ircd-ratbox/modules/m_cmessage.c (new)
+  7.124     +1 -1      ircd-ratbox/src/messages.tab
+
+
+
+leeh        2005/02/02 16:58:16 EST    (20050202_4)
+
+  Modified files:
+    help/opers           etrace 
+  Log:
+  - update etrace help
+  
+  Revision  Changes    Path
+  1.3       +7 -1      ircd-ratbox/help/opers/etrace
+
+
+
+leeh        2005/02/02 16:55:04 EST    (20050202_3)
+
+  Modified files:
+    modules              m_etrace.c 
+  Log:
+  - tidy up etrace slightly, stop showing fullcaps for spoofed users as mirc
+    can put its external ip address in there..
+  
+  Revision  Changes    Path
+  1.14      +31 -41    ircd-ratbox/modules/m_etrace.c
+
+
+
+leeh        2005/02/02 16:41:06 EST    (20050202_2)
+
+  Modified files:
+    modules              m_etrace.c 
+  Log:
+  - patch via nenolod, allows ETRACE <nick>, gets sent remotely over ENCAP
+    if its a non-local client.  These will just get "lost" if the remote
+    server doesnt support this..
+  
+  Revision  Changes    Path
+  1.13      +66 -4     ircd-ratbox/modules/m_etrace.c
+
+
+
+leeh        2005/02/02 16:12:12 EST    (20050202_1)
+
+  Modified files:
+    include              client.h numeric.h s_conf.h 
+    modules/core         m_message.c 
+    src                  messages.tab newconf.c s_conf.c 
+  Log:
+  - first part of the target change code, add the storage of targets for
+    localuser, throttle messages when they fill all the available slots
+  
+  Revision  Changes    Path
+  7.262     +5 -1      ircd-ratbox/include/client.h
+  7.55      +2 -0      ircd-ratbox/include/numeric.h
+  7.310     +1 -0      ircd-ratbox/include/s_conf.h
+  1.159     +65 -1     ircd-ratbox/modules/core/m_message.c
+  7.123     +1 -1      ircd-ratbox/src/messages.tab
+  7.197     +1 -0      ircd-ratbox/src/newconf.c
+  7.503     +1 -0      ircd-ratbox/src/s_conf.c
+
+
+
+leeh        2005/02/02 13:28:10 EST    (20050202_0)
+
+  Modified files:
+    modules              m_resv.c m_stats.c m_testline.c 
+    modules/core         m_join.c 
+    src                  hash.c kdparse.c messages.tab s_newconf.c 
+  Log:
+  - patch via nenolod, <nenolod -at- noderebellion.net> to add counter
+    tracking of when resvs get hit
+  
+  Revision  Changes    Path
+  1.164     +7 -1      ircd-ratbox/modules/core/m_join.c
+  1.73      +3 -1      ircd-ratbox/modules/m_resv.c
+  1.242     +5 -5      ircd-ratbox/modules/m_stats.c
+  1.55      +6 -1      ircd-ratbox/modules/m_testline.c
+  7.114     +3 -0      ircd-ratbox/src/hash.c
+  7.43      +2 -0      ircd-ratbox/src/kdparse.c
+  7.122     +1 -1      ircd-ratbox/src/messages.tab
+  7.63      +3 -0      ircd-ratbox/src/s_newconf.c
+
+
+
+leeh        2005/01/31 09:04:10 EST    (20050131_2)
+
+  Modified files:
+    src                  s_log.c 
+  Log:
+  - fflush() logfiles
+  
+  Revision  Changes    Path
+  7.79      +2 -0      ircd-ratbox/src/s_log.c
+
+
+
+leeh        2005/01/31 08:59:09 EST    (20050131_1)
+
+  Modified files:
+    src                  commio.c 
+  Log:
+  - rename fd_dump() to comm_dump()
+  
+  Revision  Changes    Path
+  1.27      +2 -2      ircd-ratbox/src/commio.c
+
+
+
+leeh        2005/01/30 19:16:08 EST    (20050131_0)
+
+  Modified files:
+    doc                  hooks.txt 
+    include              hook.h 
+    modules              m_services.c 
+    modules/core         m_server.c 
+    src                  hook.c s_serv.c 
+  Log:
+  - added hook for server_introduced
+  - fixed up services support for hooks
+  
+  Revision  Changes    Path
+  1.4       +10 -0     ircd-ratbox/doc/hooks.txt
+  1.31      +1 -0      ircd-ratbox/include/hook.h
+  1.152     +6 -1      ircd-ratbox/modules/core/m_server.c
+  1.5       +8 -22     ircd-ratbox/modules/m_services.c
+  7.36      +2 -0      ircd-ratbox/src/hook.c
+  7.426     +5 -0      ircd-ratbox/src/s_serv.c
+
+
+
+androsyn    2005/01/29 20:18:12 EST    (20050130_1)
+
+  Modified files:
+    src                  commio.c 
+  Log:
+  Add back in the comm_fd_hack thing for solaris
+  
+  Revision  Changes    Path
+  1.26      +26 -1     ircd-ratbox/src/commio.c
+
+
+
+androsyn    2005/01/29 19:59:17 EST    (20050130_0)
+
+  Modified files:
+    adns                 adns.h 
+    include              commio.h s_conf.h watch.h 
+    modules              m_dline.c m_kline.c m_resv.c m_stats.c 
+                         m_watch.c m_xline.c 
+    modules/core         m_nick.c 
+    src                  balloc.c cache.c client.c commio.c 
+                         epoll.c ircd.c ircd_lexer.l kdparse.c 
+                         listener.c s_auth.c s_conf.c s_log.c 
+                         s_serv.c watch.c 
+  Log:
+  Do the fb* to f* mangle and then fix watch to prevent stupid crap
+  
+  Revision  Changes    Path
+  1.18      +0 -2      ircd-ratbox/adns/adns.h
+  1.14      +6 -37     ircd-ratbox/include/commio.h
+  7.309     +6 -6      ircd-ratbox/include/s_conf.h
+  7.3       +2 -2      ircd-ratbox/include/watch.h
+  1.158     +3 -3      ircd-ratbox/modules/core/m_nick.c
+  1.46      +13 -13    ircd-ratbox/modules/m_dline.c
+  1.198     +12 -12    ircd-ratbox/modules/m_kline.c
+  1.72      +11 -11    ircd-ratbox/modules/m_resv.c
+  1.241     +3 -3      ircd-ratbox/modules/m_stats.c
+  1.6       +60 -21    ircd-ratbox/modules/m_watch.c
+  1.66      +16 -16    ircd-ratbox/modules/m_xline.c
+  7.85      +1 -1      ircd-ratbox/src/balloc.c
+  1.24      +5 -5      ircd-ratbox/src/cache.c
+  7.488     +4 -4      ircd-ratbox/src/client.c
+  1.25      +10 -280   ircd-ratbox/src/commio.c
+  1.33      +1 -1      ircd-ratbox/src/epoll.c
+  7.368     +4 -4      ircd-ratbox/src/ircd.c
+  1.167     +6 -6      ircd-ratbox/src/ircd_lexer.l
+  7.42      +8 -8      ircd-ratbox/src/kdparse.c
+  7.125     +8 -8      ircd-ratbox/src/listener.c
+  7.192     +6 -6      ircd-ratbox/src/s_auth.c
+  7.502     +21 -21    ircd-ratbox/src/s_conf.c
+  7.78      +20 -20    ircd-ratbox/src/s_log.c
+  7.425     +8 -8      ircd-ratbox/src/s_serv.c
+  1.6       +22 -15    ircd-ratbox/src/watch.c
+
+
+
+androsyn    2005/01/29 12:18:38 EST    (20050129_0)
+
+  Modified files:
+    modules/core         m_mode.c 
+  Log:
+  remove two unused variables
+  
+  Revision  Changes    Path
+  1.121     +1 -3      ircd-ratbox/modules/core/m_mode.c
+
+
+
+leeh        2005/01/28 15:31:40 EST    (20050128_1)
+
+  Modified files:
+    modules              m_kline.c 
+    src                  s_conf.c 
+  Log:
+  - mo_kline() needs minpara of 3, not 2
+  - drop ms_kline() minpara to 5, to counter a bug in 1.5-3
+  - require me.info is never blank
+  
+  Revision  Changes    Path
+  1.197     +9 -2      ircd-ratbox/modules/m_kline.c
+  7.501     +2 -2      ircd-ratbox/src/s_conf.c
+
+
+
+leeh        2005/01/28 15:26:28 EST    (20050128_0)
+
+  Modified files:
+    modules/core         m_mode.c m_sjoin.c 
+  Log:
+  - patch via jilles to fix +eI lists being shown to lusers when handling
+    protocol stuff over TS6
+  
+  Revision  Changes    Path
+  1.120     +7 -3      ircd-ratbox/modules/core/m_mode.c
+  1.205     +8 -8      ircd-ratbox/modules/core/m_sjoin.c
+
+
+
+leeh        2005/01/25 19:47:38 EST    (20050126_0)
+
+  Modified files:
+    include              channel.h 
+    modules/core         m_join.c m_mode.c m_sjoin.c 
+    src                  channel.c messages.tab s_serv.c 
+  Log:
+  - remove loc_channel_modes(), made channel_modes() handle IsMe() and make
+    an operspy call with &me
+  - remove modebuf/parabuf params from channel_modes(), we now generate a
+    buffer internally which we return.
+  
+  Revision  Changes    Path
+  7.163     +1 -1      ircd-ratbox/include/channel.h
+  1.163     +12 -14    ircd-ratbox/modules/core/m_join.c
+  1.119     +4 -47     ircd-ratbox/modules/core/m_mode.c
+  1.204     +9 -12     ircd-ratbox/modules/core/m_sjoin.c
+  7.431     +25 -18    ircd-ratbox/src/channel.c
+  7.121     +1 -1      ircd-ratbox/src/messages.tab
+  7.424     +6 -14     ircd-ratbox/src/s_serv.c
+
+
+
+alz         2005/01/25 18:09:18 EST    (20050125_5)
+
+  Modified files:
+    doc                  example.conf example.efnet.conf 
+    include              s_conf.h 
+    modules              m_info.c 
+    src                  listener.c newconf.c s_conf.c 
+  Log:
+  Added dline_with_reason config option (default yes):
+  
+  /* dline reason: show the user the dline reason when they connect
+   * and are dlined.
+   */
+  dline_with_reason = yes;
+  
+  Revision  Changes    Path
+  7.257     +6 -1      ircd-ratbox/doc/example.conf
+  7.85      +6 -1      ircd-ratbox/doc/example.efnet.conf
+  7.308     +1 -0      ircd-ratbox/include/s_conf.h
+  1.122     +7 -1      ircd-ratbox/modules/m_info.c
+  7.124     +1 -1      ircd-ratbox/src/listener.c
+  7.196     +1 -0      ircd-ratbox/src/newconf.c
+  7.500     +1 -0      ircd-ratbox/src/s_conf.c
+
+
+
+leeh        2005/01/25 13:21:17 EST    (20050125_4)
+
+  Modified files:
+    src                  newconf.c 
+  Log:
+  - make conf_set_generic_string() test len exists before it uses it.
+  
+  Revision  Changes    Path
+  7.195     +1 -1      ircd-ratbox/src/newconf.c
+
+
+
+leeh        2005/01/25 13:10:56 EST    (20050125_3)
+
+  Modified files:
+    doc                  example.conf 
+    src                  newconf.c 
+  Log:
+  - rename 'type' to 'flags' in cluster {};
+  - add stacking of servers in cluster {}; documented in example.conf
+  
+  Revision  Changes    Path
+  7.256     +18 -10    ircd-ratbox/doc/example.conf
+  7.194     +39 -7     ircd-ratbox/src/newconf.c
+
+
+
+alz         2005/01/25 12:48:54 EST    (20050125_2)
+
+  Modified files:
+    include              s_conf.h 
+    src                  listener.c s_conf.c 
+  Log:
+  Added dline reasons, connecting/banned clients now see ban reason.
+  
+  Revision  Changes    Path
+  7.307     +1 -1      ircd-ratbox/include/s_conf.h
+  7.123     +17 -4     ircd-ratbox/src/listener.c
+  7.499     +5 -5      ircd-ratbox/src/s_conf.c
+
+
+
+leeh        2005/01/25 07:44:37 EST    (20050125_1)
+
+  Modified files:
+    doc                  example.conf example.efnet.conf 
+    src                  newconf.c 
+  Log:
+  - implement stacking of shared {}; blocks, documented in example.conf
+  
+  Revision  Changes    Path
+  7.255     +26 -13    ircd-ratbox/doc/example.conf
+  7.84      +27 -14    ircd-ratbox/doc/example.efnet.conf
+  7.193     +51 -36    ircd-ratbox/src/newconf.c
+
+
+
+leeh        2005/01/24 19:08:29 EST    (20050125_0)
+
+  Modified files:
+    doc                  example.conf 
+    include              client.h s_conf.h 
+    modules/core         m_join.c 
+    src                  newconf.c s_user.c 
+  Log:
+  - added jupe_exempt to auth {};, exempts the user from generating warnings
+    when they attempt to join juped channels.
+  
+  Revision  Changes    Path
+  7.254     +2 -0      ircd-ratbox/doc/example.conf
+  7.261     +3 -0      ircd-ratbox/include/client.h
+  7.306     +2 -0      ircd-ratbox/include/s_conf.h
+  1.162     +5 -2      ircd-ratbox/modules/core/m_join.c
+  7.192     +1 -0      ircd-ratbox/src/newconf.c
+  7.338     +8 -0      ircd-ratbox/src/s_user.c
+
+
+
+leeh        2005/01/24 18:57:02 EST    (20050124_6)
+
+  Modified files:
+    src                  newconf.c 
+  Log:
+  - rework shared {};, the format is now:
+    shared {
+        oper = "flame@*.leeh.co.uk", "*.lan";
+        flags = kline;
+    };
+  
+    With no privs:
+    shared {
+        oper = "flame@*.leeh.co.uk", "*.lan";
+        flags = none;
+    };
+  
+  Revision  Changes    Path
+  7.191     +55 -23    ircd-ratbox/src/newconf.c
+
+
+
+leeh        2005/01/24 17:25:58 EST    (20050124_5)
+
+  Modified files:
+    include              modules.h 
+  Log:
+  - fix the prototype on load_static_modules()
+  
+  Revision  Changes    Path
+  7.61      +1 -1      ircd-ratbox/include/modules.h
+
+
+
+leeh        2005/01/24 16:00:30 EST    (20050124_4)
+
+  Modified files:
+    modules              m_cap.c 
+  Log:
+  - have cap end call register_local_user() with its own copy of
+    source_p->username so its safe for unidented users..
+  
+  Revision  Changes    Path
+  1.4       +6 -2      ircd-ratbox/modules/m_cap.c
+
+
+
+leeh        2005/01/24 15:48:09 EST    (20050124_3)
+
+  Modified files:
+    include              newconf.h s_conf.h 
+    modules              m_info.c 
+    src                  newconf.c s_conf.c s_log.c 
+  Log:
+  - move the conf parser over to a table based structure, with generic setting
+    of integers/strings
+  
+  Revision  Changes    Path
+  7.34      +9 -8      ircd-ratbox/include/newconf.h
+  7.305     +13 -13    ircd-ratbox/include/s_conf.h
+  1.121     +13 -16    ircd-ratbox/modules/m_info.c
+  7.190     +264 -808  ircd-ratbox/src/newconf.c
+  7.498     +11 -13    ircd-ratbox/src/s_conf.c
+  7.77      +13 -13    ircd-ratbox/src/s_log.c
+
+
+
+leeh        2005/01/24 13:11:30 EST    (20050124_2)
+
+  Modified files:
+    doc                  example.conf 
+    src                  newconf.c 
+  Log:
+  - added stacking of ips in exempt {};
+  
+  Revision  Changes    Path
+  7.253     +4 -0      ircd-ratbox/doc/example.conf
+  7.189     +11 -30    ircd-ratbox/src/newconf.c
+
+
+
+leeh        2005/01/24 12:59:57 EST    (20050124_1)
+
+  Modified files:
+    include              tools.h 
+    src                  channel.c client.c hash.c hook.c 
+                         newconf.c s_user.c watch.c 
+  Log:
+  - moved dlinkFind*() to be (node, list) rather than (list, node) so its
+    consistent with the rest of the dlink code.
+  
+  Revision  Changes    Path
+  1.54      +7 -7      ircd-ratbox/include/tools.h
+  7.430     +2 -2      ircd-ratbox/src/channel.c
+  7.487     +6 -6      ircd-ratbox/src/client.c
+  7.113     +5 -5      ircd-ratbox/src/hash.c
+  7.35      +1 -1      ircd-ratbox/src/hook.c
+  7.188     +2 -2      ircd-ratbox/src/newconf.c
+  7.337     +1 -1      ircd-ratbox/src/s_user.c
+  1.5       +4 -4      ircd-ratbox/src/watch.c
+
+
+
+leeh        2005/01/24 12:47:13 EST    (20050124_0)
+
+  Modified files:
+    modules              m_cap.c 
+  Log:
+  - cheap hack on sticky capabs..
+  
+  Revision  Changes    Path
+  1.3       +4 -2      ircd-ratbox/modules/m_cap.c
+
+
+
+leeh        2005/01/22 11:36:54 EST    (20050122_0)
+
+  Modified files:
+    modules              m_cap.c 
+  Log:
+  - updated my clicap implementation to match the spec so far..
+  
+  Revision  Changes    Path
+  1.2       +84 -11    ircd-ratbox/modules/m_cap.c
+
+
+
+leeh        2005/01/21 07:14:43 EST    (20050121_2)
+
+  Modified files:
+    doc                  hooks.txt 
+    include              hook.h 
+    modules              m_services.c 
+    src                  hook.c s_serv.c 
+  Log:
+  - added hooks for when we're sending a burst
+  - rewrote hooks.txt
+  - fix up the hooks ive already done in services compatibility, ill add the
+    hooks for server/client introductions in a bit.
+  
+  Revision  Changes    Path
+  1.3       +71 -33    ircd-ratbox/doc/hooks.txt
+  1.30      +4 -0      ircd-ratbox/include/hook.h
+  1.4       +24 -35    ircd-ratbox/modules/m_services.c
+  7.34      +7 -0      ircd-ratbox/src/hook.c
+  7.423     +26 -2     ircd-ratbox/src/s_serv.c
+
+
+
+leeh        2005/01/21 06:34:03 EST    (20050121_1)
+
+  Modified files:
+    contrib              example_module.c spy_admin_notice.c 
+                         spy_info_notice.c spy_links_notice.c 
+                         spy_motd_notice.c spy_stats_notice.c 
+                         spy_stats_p_notice.c spy_trace_notice.c 
+                         spy_whois_notice.c 
+                         spy_whois_notice_global.c 
+    include              hook.h 
+    modules              m_admin.c m_info.c m_links.c m_motd.c 
+                         m_services.c m_stats.c m_trace.c 
+                         m_whois.c static_modules.c.SH 
+    modules/core         m_server.c 
+    src                  client.c hook.c ircd.c modules.c packet.c 
+                         s_auth.c s_serv.c s_user.c send.c 
+  Log:
+  - add a better implementation of the hook system, its now a slow leaking
+    array and events are created whenever we try adding a hook for it, or
+    theyre registered for the caller.
+  
+    Ive temporarily fucked services support and removed most of the other
+    hooks.. I shall fix this soon.
+  
+  Revision  Changes    Path
+  1.13      +6 -7      ircd-ratbox/contrib/example_module.c
+  1.14      +6 -8      ircd-ratbox/contrib/spy_admin_notice.c
+  1.14      +6 -8      ircd-ratbox/contrib/spy_info_notice.c
+  1.20      +8 -8      ircd-ratbox/contrib/spy_links_notice.c
+  1.14      +6 -8      ircd-ratbox/contrib/spy_motd_notice.c
+  1.21      +22 -22    ircd-ratbox/contrib/spy_stats_notice.c
+  1.13      +6 -8      ircd-ratbox/contrib/spy_stats_p_notice.c
+  1.15      +10 -12    ircd-ratbox/contrib/spy_trace_notice.c
+  1.20      +15 -14    ircd-ratbox/contrib/spy_whois_notice.c
+  1.9       +14 -14    ircd-ratbox/contrib/spy_whois_notice_global.c
+  1.29      +34 -70    ircd-ratbox/include/hook.h
+  1.151     +1 -3      ircd-ratbox/modules/core/m_server.c
+  1.62      +5 -6      ircd-ratbox/modules/m_admin.c
+  1.120     +5 -6      ircd-ratbox/modules/m_info.c
+  1.70      +6 -6      ircd-ratbox/modules/m_links.c
+  1.58      +5 -6      ircd-ratbox/modules/m_motd.c
+  1.3       +13 -1     ircd-ratbox/modules/m_services.c
+  1.240     +10 -11    ircd-ratbox/modules/m_stats.c
+  1.107     +8 -9      ircd-ratbox/modules/m_trace.c
+  1.147     +8 -8      ircd-ratbox/modules/m_whois.c
+  1.10      +2 -2      ircd-ratbox/modules/static_modules.c.SH
+  7.486     +1 -28     ircd-ratbox/src/client.c
+  7.33      +131 -137  ircd-ratbox/src/hook.c
+  7.367     +1 -1      ircd-ratbox/src/ircd.c
+  7.151     +6 -10     ircd-ratbox/src/modules.c
+  7.138     +10 -14    ircd-ratbox/src/packet.c
+  7.191     +0 -3      ircd-ratbox/src/s_auth.c
+  7.422     +0 -16     ircd-ratbox/src/s_serv.c
+  7.336     +0 -6      ircd-ratbox/src/s_user.c
+  7.286     +8 -6      ircd-ratbox/src/send.c
+
+
+
+leeh        2005/01/20 19:19:20 EST    (20050121_0)
+
+  Modified files:
+    include              hostmask.h 
+  Log:
+  - remove an unused struct
+  
+  Revision  Changes    Path
+  1.41      +0 -9      ircd-ratbox/include/hostmask.h
+
+
+
+leeh        2005/01/20 13:38:39 EST    (20050120_1)
+
+  Modified files:
+    .                    configure configure.ac 
+    include              client.h numeric.h patchlevel.h 
+    modules              Makefile.in 
+    src                  messages.tab s_user.c 
+  Added files:
+    modules              m_cap.c 
+  Log:
+  - drop back to -O0, fix patchlevel.h
+  - first stab at client capabilities.. this still needs work.
+  
+  Revision  Changes    Path
+  7.240     +3 -3      ircd-ratbox/configure
+  7.54      +3 -3      ircd-ratbox/configure.ac
+  7.260     +3 -0      ircd-ratbox/include/client.h
+  7.54      +2 -0      ircd-ratbox/include/numeric.h
+  7.70      +1 -3      ircd-ratbox/include/patchlevel.h
+  1.116     +1 -0      ircd-ratbox/modules/Makefile.in
+  1.1       +405 -0    ircd-ratbox/modules/m_cap.c (new)
+  7.120     +1 -1      ircd-ratbox/src/messages.tab
+  7.335     +3 -0      ircd-ratbox/src/s_user.c
+
+
+
+leeh        2005/01/20 06:04:41 EST    (20050120_0)
+
+  Modified files:
+    .                    ChangeLog RELNOTES 
+    include              config.h config.h.dist memory.h 
+                         patchlevel.h 
+    modules              m_stats.c 
+    src                  commio.c crypt.c getopt.c ircd.c s_serv.c 
+  Removed files:
+    .                    README.VMS clean.com make.com 
+    include              setup.h_vms 
+    modules              descrip.mms static_modules_c.com 
+    modules/core         descrip.mms 
+    src                  descrip.mms qio.c version.com 
+    tools                descrip.mms mkpasswd_vms.c 
+  Log:
+  - clean changelog, relnotes
+  - mark patchlevel as 2.1.0beta
+  - remove VMS support
+  
+  Revision  Changes    Path
+  1.1613    +0 -27165  ircd-ratbox/ChangeLog
+  7.2       +0 -46     ircd-ratbox/README.VMS (dead)
+  1.111     +1 -348    ircd-ratbox/RELNOTES
+  7.2       +0 -10     ircd-ratbox/clean.com (dead)
+  7.182     +0 -42     ircd-ratbox/include/config.h
+  7.79      +0 -42     ircd-ratbox/include/config.h.dist
+  7.50      +0 -4      ircd-ratbox/include/memory.h
+  7.69      +1 -6      ircd-ratbox/include/patchlevel.h
+  7.16      +0 -124    ircd-ratbox/include/setup.h_vms (dead)
+  7.2       +0 -58     ircd-ratbox/make.com (dead)
+  1.5       +0 -24     ircd-ratbox/modules/core/descrip.mms (dead)
+  1.10      +0 -33     ircd-ratbox/modules/descrip.mms (dead)
+  1.239     +1 -10     ircd-ratbox/modules/m_stats.c
+  1.6       +0 -125    ircd-ratbox/modules/static_modules_c.com (dead)
+  1.24      +7 -30     ircd-ratbox/src/commio.c
+  7.12      +0 -4      ircd-ratbox/src/crypt.c
+  7.15      +0 -44     ircd-ratbox/src/descrip.mms (dead)
+  7.24      +0 -4      ircd-ratbox/src/getopt.c
+  7.366     +4 -19     ircd-ratbox/src/ircd.c
+  7.8       +0 -221    ircd-ratbox/src/qio.c (dead)
+  7.421     +1 -8      ircd-ratbox/src/s_serv.c
+  7.8       +0 -101    ircd-ratbox/src/version.com (dead)
+  7.9       +0 -25     ircd-ratbox/tools/descrip.mms (dead)
+  7.4       +0 -458    ircd-ratbox/tools/mkpasswd_vms.c (dead)
+
+
+
+androsyn    2005/01/18 11:55:13 EST    (20050118_7)
+
+  Modified files:
+    include              watch.h 
+    src                  watch.c 
+  Log:
+  not using the return values on a few watch functions so make them void
+  
+  Revision  Changes    Path
+  7.2       +5 -5      ircd-ratbox/include/watch.h
+  1.4       +19 -28    ircd-ratbox/src/watch.c
+
+
+androsyn    2005/01/14 13:10:41 EST    (20050114_5)
+
+  Modified files:
+    modules              m_watch.c 
+  Log:
+  Make watch throttle, don't accept letter commands stacked
+  
+  Revision  Changes    Path
+  1.5       +126 -122  ircd-ratbox/modules/m_watch.c
+
+
+
+androsyn    2005/01/14 13:06:06 EST    (20050114_4)
+
+  Modified files:
+    modules              m_gline.c 
+  Log:
+  fix merge error
+  
+  Revision  Changes    Path
+  1.149     +1 -1      ircd-ratbox/modules/m_gline.c
+
+
+
+androsyn    2005/01/14 12:12:37 EST    (20050114_3)
+
+  Modified files:
+    .                    ChangeLog README.FIRST RELNOTES configure 
+                         configure.ac 
+    adns                 adns.h internal.h parse.c transmit.c 
+                         types.c 
+    contrib              example_module.c spy_admin_notice.c 
+                         spy_info_notice.c spy_links_notice.c 
+                         spy_motd_notice.c spy_stats_notice.c 
+                         spy_stats_p_notice.c spy_trace_notice.c 
+                         spy_whois_notice.c 
+                         spy_whois_notice_global.c 
+    doc                  example.conf example.efnet.conf ircd.motd 
+                         server-version-info whats-new.txt 
+    help/opers           umode xline 
+    help/users           umode 
+    include              cache.h channel.h class.h client.h 
+                         commio.h config.h config.h.dist hash.h 
+                         hook.h hostmask.h irc_string.h ircd.h 
+                         ircd_defs.h m_info.h memory.h msg.h 
+                         newconf.h numeric.h packet.h patchlevel.h 
+                         patricia.h s_conf.h s_gline.h s_newconf.h 
+                         s_serv.h s_user.h scache.h serno.h 
+                         setup.h.in sprintf_irc.h stdinc.h tools.h 
+    modules              .depend Makefile.in m_admin.c m_away.c 
+                         m_dline.c m_encap.c m_gline.c m_info.c 
+                         m_kline.c m_links.c m_list.c m_lusers.c 
+                         m_motd.c m_oper.c m_operspy.c m_rehash.c 
+                         m_restart.c m_resv.c m_set.c m_stats.c 
+                         m_svinfo.c m_testline.c m_testmask.c 
+                         m_topic.c m_trace.c m_watch.c m_who.c 
+                         m_whois.c m_whowas.c m_xline.c 
+                         static_modules.c.SH 
+    modules/core         m_error.c m_message.c m_mode.c m_quit.c 
+                         m_server.c m_squit.c 
+    src                  .depend Makefile.in adns.c balloc.c 
+                         cache.c channel.c class.c client.c 
+                         commio.c crypt.c devpoll.c epoll.c 
+                         event.c getopt.c hash.c hook.c hostmask.c 
+                         irc_string.c ircd.c ircd_lexer.l 
+                         ircd_parser.y ircd_signal.c listener.c 
+                         modules.c newconf.c numeric.c packet.c 
+                         parse.c patricia.c poll.c reject.c 
+                         restart.c s_auth.c s_conf.c s_log.c 
+                         s_newconf.c s_serv.c s_user.c scache.c 
+                         select.c send.c snprintf.c tools.c 
+                         version.c.SH watch.c whowas.c 
+    tools                README.mkpasswd mkpasswd.c 
+  Added files:
+    .                    README.VMS clean.com make.com 
+    doc                  services.txt 
+    include              common.h s_stats.h setup.h_vms 
+                         supported.h 
+    modules              descrip.mms m_challenge.c m_etrace.c 
+                         m_invite.c m_names.c m_pass.c m_ping.c 
+                         m_pong.c m_services.c m_tb.c m_user.c 
+                         m_users.c m_version.c 
+                         static_modules_c.com 
+    modules/core         descrip.mms m_join.c m_kick.c m_nick.c 
+                         m_part.c m_sjoin.c 
+    servlink             descrip.mms 
+    src                  descrip.mms kdparse.c messages.tab qio.c 
+                         s_gline.c s_stats.c version.com 
+    tools                descrip.mms mkpasswd_vms.c 
+  Removed files:
+    doc                  005.txt 
+    include              banconf.h 
+    modules/core         channels.c users.c 
+    src                  banconf.c 
+  Log:
+  merge from RATBOX_2_0
+  
+  Revision  Changes       Path
+  1.1601    +25853 -1906  ircd-ratbox/ChangeLog
+  7.40      +1 -0         ircd-ratbox/README.FIRST
+  7.1       +46 -0        ircd-ratbox/README.VMS (new)
+  1.110     +114 -6       ircd-ratbox/RELNOTES
+  1.17      +4 -0         ircd-ratbox/adns/adns.h
+  1.17      +4 -4         ircd-ratbox/adns/internal.h
+  1.12      +38 -38       ircd-ratbox/adns/parse.c
+  1.15      +3 -3         ircd-ratbox/adns/transmit.c
+  1.19      +13 -13       ircd-ratbox/adns/types.c
+  7.1       +10 -0        ircd-ratbox/clean.com (new)
+  7.239     +47 -29       ircd-ratbox/configure
+  7.53      +40 -32       ircd-ratbox/configure.ac
+  1.12      +7 -6         ircd-ratbox/contrib/example_module.c
+  1.13      +9 -7         ircd-ratbox/contrib/spy_admin_notice.c
+  1.13      +9 -7         ircd-ratbox/contrib/spy_info_notice.c
+  1.19      +9 -9         ircd-ratbox/contrib/spy_links_notice.c
+  1.13      +9 -7         ircd-ratbox/contrib/spy_motd_notice.c
+  1.20      +22 -22       ircd-ratbox/contrib/spy_stats_notice.c
+  1.12      +8 -6         ircd-ratbox/contrib/spy_stats_p_notice.c
+  1.14      +12 -12       ircd-ratbox/contrib/spy_trace_notice.c
+  1.19      +14 -15       ircd-ratbox/contrib/spy_whois_notice.c
+  1.8       +14 -14       ircd-ratbox/contrib/spy_whois_notice_global.c
+  1.2       +0 -46        ircd-ratbox/doc/005.txt (dead)
+  7.252     +68 -22       ircd-ratbox/doc/example.conf
+  7.83      +70 -19       ircd-ratbox/doc/example.efnet.conf
+  7.4       +2 -2         ircd-ratbox/doc/ircd.motd
+  7.18      +2 -0         ircd-ratbox/doc/server-version-info
+  7.1       +37 -0        ircd-ratbox/doc/services.txt (new)
+  7.50      +21 -3        ircd-ratbox/doc/whats-new.txt
+  1.5       +2 -1         ircd-ratbox/help/opers/umode
+  1.7       +1 -1         ircd-ratbox/help/opers/xline
+  1.2       +1 -0         ircd-ratbox/help/users/umode
+  7.3       +0 -15        ircd-ratbox/include/banconf.h (dead)
+  1.7       +8 -0         ircd-ratbox/include/cache.h
+  7.162     +18 -16       ircd-ratbox/include/channel.h
+  7.25      +4 -0         ircd-ratbox/include/class.h
+  7.259     +34 -28       ircd-ratbox/include/client.h
+  1.13      +45 -7        ircd-ratbox/include/commio.h
+  7.9       +68 -0        ircd-ratbox/include/common.h (new)
+  7.181     +74 -16       ircd-ratbox/include/config.h
+  7.78      +74 -16       ircd-ratbox/include/config.h.dist
+  7.53      +2 -0         ircd-ratbox/include/hash.h
+  1.28      +73 -27       ircd-ratbox/include/hook.h
+  1.40      +15 -2        ircd-ratbox/include/hostmask.h
+  7.61      +7 -1         ircd-ratbox/include/irc_string.h
+  7.80      +6 -31        ircd-ratbox/include/ircd.h
+  7.54      +4 -0         ircd-ratbox/include/ircd_defs.h
+  7.56      +14 -8        ircd-ratbox/include/m_info.h
+  7.49      +4 -0         ircd-ratbox/include/memory.h
+  7.53      +2 -0         ircd-ratbox/include/msg.h
+  7.33      +9 -9         ircd-ratbox/include/newconf.h
+  7.53      +12 -8        ircd-ratbox/include/numeric.h
+  7.27      +1 -1         ircd-ratbox/include/packet.h
+  7.68      +7 -1         ircd-ratbox/include/patchlevel.h
+  7.19      +25 -1        ircd-ratbox/include/patricia.h
+  7.304     +80 -25       ircd-ratbox/include/s_conf.h
+  7.20      +12 -0        ircd-ratbox/include/s_gline.h
+  7.44      +1 -48        ircd-ratbox/include/s_newconf.h
+  7.97      +7 -1         ircd-ratbox/include/s_serv.h
+  7.20      +80 -0        ircd-ratbox/include/s_stats.h (new)
+  7.34      +13 -9        ircd-ratbox/include/s_user.h
+  7.15      +1 -1         ircd-ratbox/include/scache.h
+  7.5366    +1 -1         ircd-ratbox/include/serno.h
+  7.93      +3 -0         ircd-ratbox/include/setup.h.in
+  7.15      +124 -0       ircd-ratbox/include/setup.h_vms (new)
+  7.18      +2 -7         ircd-ratbox/include/sprintf_irc.h
+  1.15      +47 -47       ircd-ratbox/include/stdinc.h
+  7.1       +124 -0       ircd-ratbox/include/supported.h (new)
+  1.53      +10 -10       ircd-ratbox/include/tools.h
+  7.1       +58 -0        ircd-ratbox/make.com (new)
+  1.45      +338 -182     ircd-ratbox/modules/.depend
+  1.115     +20 -4        ircd-ratbox/modules/Makefile.in
+  1.14      +0 -1963      ircd-ratbox/modules/core/channels.c (dead)
+  1.4       +24 -0        ircd-ratbox/modules/core/descrip.mms (new)
+  1.11      +2 -1         ircd-ratbox/modules/core/m_error.c
+  1.161     +747 -0       ircd-ratbox/modules/core/m_join.c (new)
+  1.81      +201 -0       ircd-ratbox/modules/core/m_kick.c (new)
+  1.158     +6 -186       ircd-ratbox/modules/core/m_message.c
+  1.118     +97 -195      ircd-ratbox/modules/core/m_mode.c
+  1.157     +1026 -0      ircd-ratbox/modules/core/m_nick.c (new)
+  1.94      +155 -0       ircd-ratbox/modules/core/m_part.c (new)
+  1.50      +5 -2         ircd-ratbox/modules/core/m_quit.c
+  1.150     +10 -987      ircd-ratbox/modules/core/m_server.c
+  1.203     +759 -0       ircd-ratbox/modules/core/m_sjoin.c (new)
+  1.82      +3 -2         ircd-ratbox/modules/core/m_squit.c
+  1.26      +0 -2316      ircd-ratbox/modules/core/users.c (dead)
+  1.9       +33 -0        ircd-ratbox/modules/descrip.mms (new)
+  1.61      +6 -5         ircd-ratbox/modules/m_admin.c
+  1.59      +3 -3         ircd-ratbox/modules/m_away.c
+  1.72      +273 -0       ircd-ratbox/modules/m_challenge.c (new)
+  1.45      +229 -44      ircd-ratbox/modules/m_dline.c
+  1.21      +2 -1         ircd-ratbox/modules/m_encap.c
+  1.12      +154 -0       ircd-ratbox/modules/m_etrace.c (new)
+  1.148     +29 -82       ircd-ratbox/modules/m_gline.c
+  1.119     +50 -42       ircd-ratbox/modules/m_info.c
+  1.83      +203 -0       ircd-ratbox/modules/m_invite.c (new)
+  1.196     +154 -5       ircd-ratbox/modules/m_kline.c
+  1.69      +8 -64        ircd-ratbox/modules/m_links.c
+  1.80      +4 -4         ircd-ratbox/modules/m_list.c
+  1.46      +2 -37        ircd-ratbox/modules/m_lusers.c
+  1.57      +6 -5         ircd-ratbox/modules/m_motd.c
+  1.81      +193 -0       ircd-ratbox/modules/m_names.c (new)
+  1.90      +4 -299       ircd-ratbox/modules/m_oper.c
+  1.6       +2 -1         ircd-ratbox/modules/m_operspy.c
+  1.49      +101 -0       ircd-ratbox/modules/m_pass.c (new)
+  1.58      +115 -0       ircd-ratbox/modules/m_ping.c (new)
+  1.58      +134 -0       ircd-ratbox/modules/m_pong.c (new)
+  1.87      +34 -60       ircd-ratbox/modules/m_rehash.c
+  1.46      +2 -1         ircd-ratbox/modules/m_restart.c
+  1.71      +98 -3        ircd-ratbox/modules/m_resv.c
+  1.2       +172 -0       ircd-ratbox/modules/m_services.c (new)
+  1.80      +31 -1        ircd-ratbox/modules/m_set.c
+  1.238     +173 -570     ircd-ratbox/modules/m_stats.c
+  1.63      +2 -1         ircd-ratbox/modules/m_svinfo.c
+  1.9       +115 -0       ircd-ratbox/modules/m_tb.c (new)
+  1.54      +7 -6         ircd-ratbox/modules/m_testline.c
+  1.4       +2 -1         ircd-ratbox/modules/m_testmask.c
+  1.90      +2 -127       ircd-ratbox/modules/m_topic.c
+  1.106     +12 -105      ircd-ratbox/modules/m_trace.c
+  1.45      +107 -0       ircd-ratbox/modules/m_user.c (new)
+  1.45      +72 -0        ircd-ratbox/modules/m_users.c (new)
+  1.68      +157 -0       ircd-ratbox/modules/m_version.c (new)
+  1.4       +1 -2         ircd-ratbox/modules/m_watch.c
+  1.114     +2 -1         ircd-ratbox/modules/m_who.c
+  1.146     +14 -11       ircd-ratbox/modules/m_whois.c
+  1.51      +2 -1         ircd-ratbox/modules/m_whowas.c
+  1.65      +105 -13      ircd-ratbox/modules/m_xline.c
+  1.9       +2 -2         ircd-ratbox/modules/static_modules.c.SH
+  1.5       +125 -0       ircd-ratbox/modules/static_modules_c.com (new)
+  1.3       +15 -0        ircd-ratbox/servlink/descrip.mms (new)
+  7.48      +162 -119     ircd-ratbox/src/.depend
+  7.153     +3 -1         ircd-ratbox/src/Makefile.in
+  7.75      +5 -5         ircd-ratbox/src/adns.c
+  7.84      +1 -1         ircd-ratbox/src/balloc.c
+  7.7       +0 -355       ircd-ratbox/src/banconf.c (dead)
+  1.23      +75 -7        ircd-ratbox/src/cache.c
+  7.429     +342 -79      ircd-ratbox/src/channel.c
+  7.67      +42 -2        ircd-ratbox/src/class.c
+  7.485     +245 -85      ircd-ratbox/src/client.c
+  1.23      +349 -43      ircd-ratbox/src/commio.c
+  7.11      +4 -0         ircd-ratbox/src/crypt.c
+  7.14      +44 -0        ircd-ratbox/src/descrip.mms (new)
+  7.36      +3 -1         ircd-ratbox/src/devpoll.c
+  1.32      +4 -8         ircd-ratbox/src/epoll.c
+  7.46      +63 -6        ircd-ratbox/src/event.c
+  7.23      +4 -0         ircd-ratbox/src/getopt.c
+  7.112     +8 -7         ircd-ratbox/src/hash.c
+  7.32      +135 -133     ircd-ratbox/src/hook.c
+  7.105     +117 -17      ircd-ratbox/src/hostmask.c
+  7.76      +79 -26       ircd-ratbox/src/irc_string.c
+  7.365     +56 -48       ircd-ratbox/src/ircd.c
+  1.166     +11 -7        ircd-ratbox/src/ircd_lexer.l
+  1.275     +1 -0         ircd-ratbox/src/ircd_parser.y
+  7.25      +25 -10       ircd-ratbox/src/ircd_signal.c
+  7.41      +309 -0       ircd-ratbox/src/kdparse.c (new)
+  7.122     +14 -13       ircd-ratbox/src/listener.c
+  7.119     +1025 -0      ircd-ratbox/src/messages.tab (new)
+  7.150     +17 -8        ircd-ratbox/src/modules.c
+  7.187     +1196 -344    ircd-ratbox/src/newconf.c
+  7.35      +34 -1003     ircd-ratbox/src/numeric.c
+  7.137     +55 -42       ircd-ratbox/src/packet.c
+  7.187     +8 -15        ircd-ratbox/src/parse.c
+  7.28      +2 -4         ircd-ratbox/src/patricia.c
+  7.82      +3 -1         ircd-ratbox/src/poll.c
+  7.7       +221 -0       ircd-ratbox/src/qio.c (new)
+  1.32      +8 -3         ircd-ratbox/src/reject.c
+  7.34      +1 -0         ircd-ratbox/src/restart.c
+  7.190     +60 -52       ircd-ratbox/src/s_auth.c
+  7.497     +892 -156     ircd-ratbox/src/s_conf.c
+  7.1       +167 -0       ircd-ratbox/src/s_gline.c (new)
+  7.76      +32 -35       ircd-ratbox/src/s_log.c
+  7.62      +10 -329      ircd-ratbox/src/s_newconf.c
+  7.420     +999 -4       ircd-ratbox/src/s_serv.c
+  7.40      +385 -0       ircd-ratbox/src/s_stats.c (new)
+  7.334     +773 -2       ircd-ratbox/src/s_user.c
+  7.27      +2 -1         ircd-ratbox/src/scache.c
+  7.44      +2 -0         ircd-ratbox/src/select.c
+  7.285     +12 -12       ircd-ratbox/src/send.c
+  1.16      +0 -58        ircd-ratbox/src/snprintf.c
+  7.46      +0 -1         ircd-ratbox/src/tools.c
+  7.28      +4 -1         ircd-ratbox/src/version.c.SH
+  7.7       +101 -0       ircd-ratbox/src/version.com (new)
+  1.3       +4 -4         ircd-ratbox/src/watch.c
+  7.32      +1 -0         ircd-ratbox/src/whowas.c
+  1.8       +5 -0         ircd-ratbox/tools/README.mkpasswd
+  7.8       +25 -0        ircd-ratbox/tools/descrip.mms (new)
+  7.16      +2 -30        ircd-ratbox/tools/mkpasswd.c
+  7.3       +458 -0       ircd-ratbox/tools/mkpasswd_vms.c (new)
+
+
+
+androsyn    2005/01/13 22:17:53 EST    (20050114_2)
+
+  Modified files:        (Branch: RATBOX_2_0)
+    src                  client.c 
+  Log:
+  a remote client is never going to have a watch list..duh
+  
+  Revision    Changes    Path
+  7.463.2.13  +0 -1      ircd-ratbox/src/client.c
+
+
+
+androsyn    2005/01/13 20:49:55 EST    (20050114_1)
+
+  Added files:           (Branch: RATBOX_2_0)
+    modules              m_watch.c 
+  Log:
+  get that one too
+  
+  Revision  Changes    Path
+  1.3.2.1   +231 -0    ircd-ratbox/modules/m_watch.c (new)
+
+
+
+androsyn    2005/01/13 20:39:28 EST    (20050114_0)
+
+  Added files:           (Branch: RATBOX_2_0)
+    include              watch.h 
+    src                  watch.c 
+  Log:
+  helps if we actually include the .c/.h files
+  
+  Revision  Changes    Path
+  7.1.2.1   +53 -0     ircd-ratbox/include/watch.h (new)
+  1.2.2.1   +241 -0    ircd-ratbox/src/watch.c (new)
+
+
+
+androsyn    2005/01/13 13:57:16 EST    (20050113_0)
+
+  Modified files:        (Branch: RATBOX_2_0)
+    .                    configure configure.ac 
+    include              client.h numeric.h s_conf.h setup.h.in 
+                         supported.h 
+    modules              Makefile.in 
+    modules/core         m_nick.c 
+    src                  Makefile.in client.c ircd.c messages.tab 
+                         newconf.c s_conf.c s_user.c 
+  Log:
+  backport watch from devel
+  
+  Revision    Changes    Path
+  7.229.2.10  +12 -2     ircd-ratbox/configure
+  7.43.2.10   +4 -2      ircd-ratbox/configure.ac
+  7.246.2.12  +4 -0      ircd-ratbox/include/client.h
+  7.46.2.5    +10 -0     ircd-ratbox/include/numeric.h
+  7.278.2.9   +1 -0      ircd-ratbox/include/s_conf.h
+  7.89.2.3    +3 -0      ircd-ratbox/include/setup.h.in
+  1.41.2.3    +4 -2      ircd-ratbox/include/supported.h
+  1.98.2.3    +1 -0      ircd-ratbox/modules/Makefile.in
+  1.152.2.5   +24 -5     ircd-ratbox/modules/core/m_nick.c
+  7.148.2.1   +1 -0      ircd-ratbox/src/Makefile.in
+  7.463.2.12  +4 -0      ircd-ratbox/src/client.c
+  7.343.2.3   +2 -0      ircd-ratbox/src/ircd.c
+  7.114.2.9   +10 -10    ircd-ratbox/src/messages.tab
+  7.156.2.16  +7 -0      ircd-ratbox/src/newconf.c
+  7.470.2.8   +1 -0      ircd-ratbox/src/s_conf.c
+  7.323.2.10  +2 -0      ircd-ratbox/src/s_user.c
+
+
+
+leeh        2005/01/12 10:12:40 EST    (20050112_1)
+
+  Modified files:        (Branch: RATBOX_2_0)
+    include              numeric.h 
+    modules              m_services.c m_whois.c 
+    src                  messages.tab 
+  Log:
+  - add RPL_WHOISLOGGEDIN, make m_services.c hook into whois and output this
+    when the user is logged in
+  
+  Revision   Changes    Path
+  7.46.2.4   +1 -0      ircd-ratbox/include/numeric.h
+  1.1.2.3    +18 -1     ircd-ratbox/modules/m_services.c
+  1.140.2.3  +4 -1      ircd-ratbox/modules/m_whois.c
+  7.114.2.8  +2 -2      ircd-ratbox/src/messages.tab
+
+
+
+leeh        2005/01/11 19:47:14 EST    (20050112_0)
+
+  Modified files:        (Branch: RATBOX_2_0)
+    include              supported.h 
+  Added files:           (Branch: RATBOX_2_0)
+    doc                  services.txt 
+  Log:
+  - add +r to 005
+  - added doc/services.txt, outlining the compatibility code
+  
+  Revision  Changes    Path
+  1.1.2.1   +37 -0     ircd-ratbox/doc/services.txt (new)
+  1.41.2.2  +9 -2      ircd-ratbox/include/supported.h
+
+
+
+leeh        2005/01/11 18:38:10 EST    (20050111_5)
+
+  Modified files:        (Branch: RATBOX_2_0)
+    include              client.h hook.h 
+    modules              m_services.c 
+    modules/core         m_server.c 
+    src                  hook.c s_serv.c 
+  Log:
+  - more services compatibility code:
+    - hook into a server being linked, mark it FLAGS_SERVICE if we find an
+      appropriate service {}; entry, only accept SU from these.
+    - hook into us finishing nick burst, and have services burst a list of
+      logged in users
+  
+  Revision    Changes    Path
+  7.246.2.11  +1 -0      ircd-ratbox/include/client.h
+  1.25.2.1    +2 -0      ircd-ratbox/include/hook.h
+  1.133.2.1   +4 -1      ircd-ratbox/modules/core/m_server.c
+  1.1.2.2     +52 -5     ircd-ratbox/modules/m_services.c
+  7.30.2.1    +6 -0      ircd-ratbox/src/hook.c
+  7.406.2.9   +7 -1      ircd-ratbox/src/s_serv.c
+
+
+
+leeh        2005/01/11 17:32:42 EST    (20050111_4)
+
+  Modified files:        (Branch: RATBOX_2_0)
+    .                    configure configure.ac 
+    include              client.h 
+    modules              Makefile.in 
+    src                  channel.c 
+  Added files:           (Branch: RATBOX_2_0)
+    modules              m_services.c 
+  Log:
+  - more services compatibility code:
+    - encap handlers for SU (services marking client as logged in)
+    - and for LOGIN (servers bursting logged in status)
+    - move suser from Client -> User
+  
+  Revision    Changes    Path
+  7.229.2.9   +9 -3      ircd-ratbox/configure
+  7.43.2.9    +7 -2      ircd-ratbox/configure.ac
+  7.246.2.10  +5 -4      ircd-ratbox/include/client.h
+  1.98.2.2    +3 -1      ircd-ratbox/modules/Makefile.in
+  1.1.2.1     +108 -0    ircd-ratbox/modules/m_services.c (new)
+  7.417.2.5   +1 -1      ircd-ratbox/src/channel.c
+
+
+
+leeh        2005/01/11 16:46:34 EST    (20050111_3)
+
+  Modified files:        (Branch: RATBOX_2_0)
+    include              ircd_defs.h 
+  Log:
+  - whoops, missing #endif
+  
+  Revision  Changes    Path
+  7.50.4.7  +1 -0      ircd-ratbox/include/ircd_defs.h
+
+
+
+leeh        2005/01/11 15:56:57 EST    (20050111_2)
+
+  Modified files:        (Branch: RATBOX_2_0)
+    include              ircd_defs.h 
+  Log:
+  - cygwin doesnt have struct sockaddr_in6, so make GET_SS_LEN() when we dont
+    have ipv6 just report sizeof(struct sockaddr_in)
+  
+  Revision  Changes    Path
+  7.50.4.6  +3 -0      ircd-ratbox/include/ircd_defs.h
+
+
+
+leeh        2005/01/10 20:19:35 EST    (20050111_1)
+
+  Modified files:        (Branch: RATBOX_2_0)
+    src                  newconf.c 
+  Log:
+  - fix a gcc warning
+  
+  Revision    Changes    Path
+  7.156.2.15  +3 -2      ircd-ratbox/src/newconf.c
+
+
+
+leeh        2005/01/10 20:10:35 EST    (20050111_0)
+
+  Modified files:        (Branch: RATBOX_2_0)
+    adns                 internal.h parse.c transmit.c types.c 
+  Log:
+  - fbsd5.3 has introduced fls(), so rename fls -> flstate in adns to avoid
+    conflict
+  
+  Revision   Changes    Path
+  1.12.14.4  +4 -4      ircd-ratbox/adns/internal.h
+  1.9.6.4    +38 -38    ircd-ratbox/adns/parse.c
+  1.13.6.3   +3 -3      ircd-ratbox/adns/transmit.c
+  1.14.6.4   +13 -13    ircd-ratbox/adns/types.c
+
+
+
+leeh        2005/01/10 17:48:48 EST    (20050110_3)
+
+  Modified files:        (Branch: RATBOX_2_0)
+    modules              m_xline.c 
+  Log:
+  - send out the reformatted xline to opers (\s -> ' ')
+  
+  Revision  Changes    Path
+  1.52.2.6  +3 -3      ircd-ratbox/modules/m_xline.c
+
+
+
+leeh        2005/01/10 16:18:53 EST    (20050110_2)
+
+  Modified files:        (Branch: RATBOX_2_0)
+    help/opers           umode 
+    help/users           umode 
+    include              client.h supported.h 
+    src                  messages.tab s_user.c send.c 
+  Log:
+  - alzs diff to add usermode +D, "deaf", which shields a user from seeing
+    channel privmsgs.
+  
+  Revision   Changes    Path
+  1.3.6.2    +1 -0      ircd-ratbox/help/opers/umode
+  1.1.22.1   +1 -0      ircd-ratbox/help/users/umode
+  7.246.2.9  +5 -2      ircd-ratbox/include/client.h
+  1.41.2.1   +9 -9      ircd-ratbox/include/supported.h
+  7.114.2.7  +1 -1      ircd-ratbox/src/messages.tab
+  7.323.2.9  +2 -1      ircd-ratbox/src/s_user.c
+  7.280.2.2  +3 -0      ircd-ratbox/src/send.c
+
+
+
+leeh        2005/01/10 14:50:47 EST    (20050110_1)
+
+  Modified files:        (Branch: RATBOX_2_0)
+    doc                  example.conf example.efnet.conf 
+  Log:
+  - I dont remember ts6 desyncing on bans, so im not sure why the example
+    confs say so.
+  
+  Revision   Changes    Path
+  7.243.2.9  +1 -2      ircd-ratbox/doc/example.conf
+  7.75.2.10  +1 -2      ircd-ratbox/doc/example.efnet.conf
+
+
+
+leeh        2005/01/10 13:31:10 EST    (20050110_0)
+
+  Modified files:        (Branch: RATBOX_2_0)
+    .                    configure configure.ac 
+    include              channel.h client.h numeric.h s_conf.h 
+                         s_serv.h setup.h.in 
+    modules/core         m_join.c m_kick.c m_mode.c m_nick.c 
+                         m_sjoin.c 
+    src                  channel.c messages.tab newconf.c s_conf.c 
+                         s_serv.c s_user.c 
+  Log:
+  - added --enable-services to configure, which enables some ratbox-services
+    compatibility code:
+      - chanmode +r, registered users only
+      - usermode +S, prevents deop/kick of a service
+      - service { }; block in conf for the above umode
+  
+  Revision    Changes    Path
+  7.229.2.8   +28 -16    ircd-ratbox/configure
+  7.43.2.8    +19 -16    ircd-ratbox/configure.ac
+  7.152.4.5   +4 -3      ircd-ratbox/include/channel.h
+  7.246.2.8   +10 -4     ircd-ratbox/include/client.h
+  7.46.2.3    +2 -1      ircd-ratbox/include/numeric.h
+  7.278.2.8   +4 -0      ircd-ratbox/include/s_conf.h
+  7.94.2.1    +2 -1      ircd-ratbox/include/s_serv.h
+  7.89.2.2    +3 -0      ircd-ratbox/include/setup.h.in
+  1.156.2.1   +9 -1      ircd-ratbox/modules/core/m_join.c
+  1.79.2.1    +11 -1     ircd-ratbox/modules/core/m_kick.c
+  1.112.2.4   +56 -1     ircd-ratbox/modules/core/m_mode.c
+  1.152.2.4   +24 -1     ircd-ratbox/modules/core/m_nick.c
+  1.201.2.4   +9 -1      ircd-ratbox/modules/core/m_sjoin.c
+  7.417.2.4   +14 -1     ircd-ratbox/src/channel.c
+  7.114.2.6   +2 -2      ircd-ratbox/src/messages.tab
+  7.156.2.14  +35 -0     ircd-ratbox/src/newconf.c
+  7.470.2.7   +15 -0     ircd-ratbox/src/s_conf.c
+  7.406.2.8   +3 -0      ircd-ratbox/src/s_serv.c
+  7.323.2.8   +12 -0     ircd-ratbox/src/s_user.c
+
+
+
+leeh        2005/01/09 08:23:30 EST    (20050109_0)
+
+  Modified files:        (Branch: RATBOX_2_0)
+    help/opers           umode 
+  Log:
+  - remove a tab, and add +C to opers umode help
+  
+  Revision  Changes    Path
+  1.3.6.1   +1 -0      ircd-ratbox/help/opers/umode
+
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..fe8f958
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,266 @@
+                            Hybrid INSTALL Document
+
+   $Id: INSTALL 1837 2006-08-22 14:05:58Z nenolod $
+
+   Copyright (c) 2001 by ircd-hybrid team
+   Copyright (c) 2002-2004 ircd-ratbox development team
+
+     ----------------------------------------------------------------------
+
+   +------------------------------------------------------------------------+
+   | Note for those who dont bother reading docs                            |
+   |                                                                        |
+   | Reading INSTALL is now a must, as the old DPATH is now specified when  |
+   | configure is run.                                                      |
+   |                                                                        |
+   | - You now need to ./configure --prefix="/path/to/install/it"           |
+   |                                                                        |
+   |   Important: The old config format WILL NOT WORK. Please see point 6!  |
+   |                                                                        |
+   |   The old kline format WILL NOT WORK. Please see point 7!              |
+   +------------------------------------------------------------------------+
+
+     ----------------------------------------------------------------------
+
+                                  HOW TO BUILD
+
+   As of hybrid-4, the distribution uses GNU autoconf instead of the old
+   Config script. The Makefile has also been updated to include CFLAGS
+   defines for popular modern OSes.
+
+   1. 
+
+       Read the ChangeLog file to find out about the exciting new features in
+       this version. Other good reads are doc/whats-new.txt, BUGS,
+       doc/example.conf, and README.FIRST.
+
+       An example.conf for EFnet is in doc/ with the values "approved" on 12
+       December 2001.
+
+   2. 
+
+       Run the configure script. It will create include/setup.h and the
+       Makefiles to match your system. In ircd-ratbox, the paths are now handled
+       with the --prefix option to configure, not in config.h.
+       /usr/local/ircd is the default if no prefix is specified.
+
+       ./configure --prefix="/usr/local/ircd"
+
+         Note: There are some special optional parameters to the configure
+         script that some admins may wish to use.
+
+          * 
+
+            --enable-kqueue - Use the superior kqueue(2) system call as
+            opposed to the default poll(2). This is currently only available
+            on FreeBSD 4.1 or higher.
+
+          * 
+
+            --enable-devpoll - Enable the superior /dev/poll support on
+            Solaris. Linux /dev/poll is broken and will not work with this
+            option.
+
+          * 
+
+            --enable-epoll - Enable the superior Linux Edge-Triggered Polling
+            system. This is currently only available on 2.5 Linux kernel
+            versions or later.
+
+          * 
+
+            --enable-openssl - Enable the openssl dependent crypto functions.
+            This will allow CHALLENGE to work and encrypted links. On systems
+            where the configure script can automatically detect OpenSSL, this
+            option is not necessary. If configure cannot find OpenSSL, you
+            must specify a path with this option
+            (--enable-openssl=/path/to/openssl)
+
+          * 
+
+            --enable-ipv6 - Enable IPv6 support.
+
+          * 
+
+            --disable-shared-modules - Disable module support. This option is
+            more secure, but reduces a lot of the flexibility in Hybrid 7.
+            This may need to be used on some systems without a working dl
+            library.
+
+          * 
+
+            --disable-assert - Disable some of the debugging code. This
+            should be used on all production servers for maximum speed and to
+            prevent cores from things that shouldn't normally happen.
+
+          * 
+
+            --enable-small-net - Tunes the server for smaller networks by
+            reducing the startup memory footprint. This should really only be
+            used for *small* networks, as this tends to be a performance hit
+            on larger networks.
+
+          * 
+
+            --with-nicklen - Sets the maximum NICK length. Note that this
+            must be consistant across your entire network.
+
+          * 
+
+            --with-maxclients - Sets the maximum number of clients support by
+            the server. Note that this also twiddles the HARD_FDLIMIT_ define
+            so it is no longer necessary to modify include/config.h for this.
+            If HARD_FDLIMIT_ ends up being larger that FD_SETSIZE when using
+            select() for your I/O loop, s_bsd_select.c will refuse to compile
+            (and tell you to use poll instead). Take this error's advice and
+            use --enable-poll or something a bit more efficient. You'll be
+            happier at the end of the day for it.
+
+   3. 
+
+       Look over the "include/config.h" file. This allows you to change the
+       few remaining hard coded options of how the ircd will operate. Most
+       admins will only have to change a few settings. USE_SYSLOG is the only
+       one that most admins will need to edit.
+
+         Note: Note that you must have permission by the sysadmin to send
+         messages to the system log files.
+
+         All other settings in config.h are not necessary to edit.
+
+   4. 
+
+       make should build ircd.
+
+   5. 
+
+       make install will install the server, modules(1), and tools in the
+       path defined in config.h and the prefix specified when configure was
+       run.
+
+       (1) Unless the server was compiled without module support.
+
+   6. 
+
+       If you wish to enable the user log, oper log, and failed oper log,
+       issue these commands at the shell prompt (in the prefix directory)
+
+ $ touch logs/userlog
+ $ touch logs/operlog
+ $ touch logs/foperlog
+
+         Note: If you use different names in ircd.conf, you must 'touch' the
+         specific names.
+
+   7. 
+
+       If you are upgrading from Hybrid 5 or Hybrid 6, the config file has
+       changed drastically...
+
+       There is a utility to convert your old config file to the new format.
+       In prefix/bin there is something called "convertconf". Its usage is:
+       ./convertconf (old config file to convert) (converted file name)
+
+       Convertconf will NOT convert I: lines.  You must use "convertilines"
+       for this which contains a much superior method of conversion and
+       will group I: together under one auth {};.
+
+       Once this is done, move your new config to prefix/etc/ircd.conf and
+       EDIT IT! There are still things that need changing in the config,
+       including the fact that classes MUST be above auth/connect blocks!
+
+   8. 
+
+       If you are upgrading from Hybrid 5 or Hybrid 6, the kline file has
+       also changed...
+
+       There is a utility to convert the old kline configuration file to the
+       new format. In prefix/bin there is a program called "convertklines".
+       Its usage is: ./convertklines (old kline.conf filename) (new
+       kline.conf filename) (dline.conf filename).
+
+       Once this is done, move the new files into the prefix/etc/ directory
+       under their proper names. By default, the kline file is named
+       kline.conf and the dline file is named dline.conf.
+
+     ----------------------------------------------------------------------
+
+                                HOW TO GET HELP
+
+   Send Check or Money Order to... just kidding! You're on your own for
+   support. Try asking other ircd-ratbox admins on EFnet if you can't fix it
+   yourself. If you do fix anything, however, please send context or unified
+   diffs to ircd-ratbox@lists.ratbox.org so the fixes can be incorporated into
+   the next release of ircd-hybrid. If ratbox crashes on you, PLEASE contact
+   ircd-ratbox@lists.ratbox.org ASAP with a backtrace of the core.
+
+   DISCUSSION: There is a mailing list for discussion of ratbox issues,
+    To subscribe, visit:
+       http://lists.ratbox.org/cgi-bin/mailman/listinfo/ircd-ratbox
+       
+     ----------------------------------------------------------------------
+
+                                     NOTES
+
+   The best way to get a backtrace of the core is to follow this sequence of
+   instructions:
+
+   1. 
+
+       Change to the directory containing the core file
+
+   2. 
+
+       Run gdb on the binary and the core file. With an unmodified ircd-ratbox
+       installation, an example command line is below (in the /usr/local/ircd
+       directory)
+
+ $ gdb bin/ircd ircd.core
+
+   3. 
+
+       At the "(gdb)" prompt, enter the command "bt"
+
+   4. 
+
+       Save the output of the backtrace command and send it to
+       ircd-ratbox@lists.ratbox.org
+
+   5. 
+
+       Be sure to save the ircd binary, the modules, and the core file in a
+       safe place in case the developers need to look deeper than a backtrace
+       provides.
+
+     ----------------------------------------------------------------------
+
+                                 OPENSSL NOTES
+
+   Older FreeBSD machines sometimes have the obsolete ports version of
+   OpenSSL libcrypto in /usr/local/lib. When configure is used with
+   --enable-openssl, and libintl is detected in /usr/local/lib, the
+   /usr/local/lib directory will be searched BEFORE the system /usr/lib for
+   libraries by the linker. The linker may try to link to the old
+   /usr/local/lib libcrypto instead of the system /usr/lib libcrypto. Some
+   older versions may cause error messages similar to the following:
+
+ gcc -g -O2 -DIRCD_PREFIX=\"/home/wcampbel/ircd\" -Wl,-export-dynamic
+ -L/usr/local/lib -o ircd blalloc.o channel.o vchannel.o class.o client.o
+ dline_conf.o event.o fdlist.o fileio.o hash.o irc_string.o ircd.o ircdauth.o
+ ircd_signal.o linebuf.o list.o listener.o m_error.o match.o memdebug.o
+ modules.o motd.o mtrie_conf.o oldparse.o numeric.o packet.o parse.o res.o rsa.o
+ restart.o s_auth.o s_bsd.o s_bsd_kqueue.o s_conf.o s_debug.o s_gline.o s_log.o
+ s_misc.o s_serv.o s_stats.o s_user.o scache.o send.o sprintf_irc.o tools.o
+ whowas.o lex.yy.o y.tab.o version.o -lintl -ldescrypt  -lcrypto -lfl
+ rsa.o: In function `get_randomness':
+ /home/wcampbel/dev/ircd-ratbox/src/rsa.c(.text+0x60): undefined reference to
+ `RAND_pseudo_bytes'
+ /usr/local/lib/libcrypto.so: undefined reference to `ERR_load_RSAREF_strings'
+ /usr/local/lib/libcrypto.so: undefined reference to `RSA_PKCS1_RSAref'
+ *** Error code 1
+
+   If this is the case, you may need to rerun configure without the
+   --enable-openssl option, manually edit src/Makefile and modules/Makefile
+   to put -L/usr/lib before the -L/usr/local/lib in LDFLAGS, or remove the
+   old OpenSSL from /usr/local, and recompile all applications that use
+   libcrypto to use the system one.
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..4c9f54a
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,341 @@
+# $Id: LICENSE 6 2005-09-10 01:02:21Z nenolod $
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU 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.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), 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 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 show them these terms so they know 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.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  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 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 derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  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 License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+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.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary 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
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 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 Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing 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 for copying, distributing or modifying
+the Program or works based on it.
+
+  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.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. 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 this 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
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. 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
+
+  11. 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.
+
+  12. 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
+           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 the public, 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 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
+
+
+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) 19yy 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 is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Makefile.in b/Makefile.in
new file mode 100644 (file)
index 0000000..cf5061b
--- /dev/null
@@ -0,0 +1,147 @@
+#************************************************************************
+#*   IRC - Internet Relay Chat, Makefile
+#*   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.
+#*
+#*   $Id: Makefile.in 1347 2006-05-17 14:49:13Z nenolod $
+#*/
+
+RM=@RM@
+prefix         = @prefix@
+exec_prefix    = @exec_prefix@
+bindir         = @bindir@
+mandir         = @mandir@
+moduledir      = @moduledir@
+helpdir                = @helpdir@
+confdir                = @confdir@
+logdir         = @logdir@
+
+# Default CFLAGS
+# CFLAGS = -g -O2 -DNDEBUG
+CFLAGS         = @CFLAGS@
+# Developers CFLAGS
+#CFLAGS= -g -O2 -Wunused -Wall -ggdb -pedantic -Wshadow -Wmissing-declarations
+
+# Default make flags - you may want to uncomment this on a multicpu machine
+#MFLAGS = -j 4
+
+#
+# For developers
+#CFLAGS= -g -O2 -Wall
+
+# You may need to define the FD_SETSIZE in order to overrule
+# the system one.
+#CFLAGS= -DNDEBUG -g -O2 -D"FD_SETSIZE=1024"
+SHELL=/bin/sh
+SUBDIRS=modules extensions libcharybdis src tools servlink doc help
+CLEANDIRS = ${SUBDIRS}
+RSA_FILES=rsa_respond/README rsa_respond/respond.c rsa_respond/Makefile
+
+MAKE = make ${MFLAGS} 
+
+all:   build
+
+
+autoconf: configure.ac
+       autoconf
+       autoheader
+       ${RM} -f config.cache
+
+build:
+       -@if [ ! -f include/setup.h ] ; then \
+               echo "Hmm...doesn't look like you've run configure..."; \
+               echo "Doing so now."; \
+               sh configure; \
+       fi
+       @for i in $(SUBDIRS); do \
+               echo "build ==> $$i";\
+               cd $$i;\
+               ${MAKE} build || exit; cd ..;\
+       done
+
+clean:
+       ${RM} -f *~ core rsa_respond.tar rsa_respond.tar.gz
+       @for i in $(CLEANDIRS); do \
+               echo "clean ==> $$i";\
+               cd $$i;\
+               ${MAKE} clean; cd ..;\
+       done
+       -@if [ -f include/setup.h ] ; then \
+       echo "To really restart installation, make distclean" ; \
+       fi
+
+distclean:
+       ${RM} -f Makefile *~ *.rej *.orig core ircd.core
+       ${RM} -f config.status config.cache config.log
+       cd include; ${RM} -f setup.h *~ *.rej *.orig ; cd ..
+       @for i in $(CLEANDIRS); do \
+               echo "distclean ==> $$i";\
+               cd $$i;\
+               ${MAKE} distclean; cd ..;\
+       done
+
+depend:
+       @for i in $(SUBDIRS); do \
+               echo "depend ==> $$i";\
+               cd $$i;\
+               ${MAKE} depend; cd ..;\
+       done
+
+lint:
+       @for i in $(SUBDIRS); do \
+               echo "lint ==> $$i";\
+               cd $$i;\
+               ${MAKE} lint; cd ..;\
+       done
+
+install-mkdirs:
+       @echo "ircd: setting up ircd directory structure"
+       -@if test ! -d $(DESTDIR)$(prefix); then \
+               mkdir $(DESTDIR)$(prefix); \
+       fi
+       -@if test ! -d $(DESTDIR)$(bindir); then \
+               mkdir $(DESTDIR)$(bindir); \
+       fi
+       -@if test ! -d $(DESTDIR)$(confdir); then \
+               mkdir $(DESTDIR)$(confdir); \
+       fi
+       -@if test ! -d $(DESTDIR)$(mandir); then \
+               mkdir $(DESTDIR)$(mandir); \
+       fi
+       -@if test ! -d $(DESTDIR)$(moduledir); then \
+               mkdir $(DESTDIR)$(moduledir); \
+       fi
+       -@if test ! -d $(DESTDIR)$(helpdir); then \
+               mkdir $(DESTDIR)$(helpdir); \
+       fi
+       -@if test ! -d $(DESTDIR)$(logdir); then \
+               mkdir $(DESTDIR)$(logdir); \
+       fi
+       
+install: install-mkdirs all
+       @for i in $(SUBDIRS); do \
+               echo "install ==> $$i";\
+               cd $$i;\
+               ${MAKE} install; \
+               cd ..; \
+       done
+
+rsa_respond:
+       @cd tools;\
+       echo "Creating rsa_respond.tar.gz";\
+       tar cf ../rsa_respond.tar $(RSA_FILES);\
+       cd ..;\
+       gzip rsa_respond.tar
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..9374992
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,336 @@
+This is charybdis 2.1.2, Copyright (c) 2005-2006 Charybdis team.
+See LICENSE for licensing details (GPL v2).
+
+-- charybdis-2.1.2
+
+- Fix bug that could cause all hostmangled users to be exempted when a
+  single ban exception existed on a channel.
+- Tweak \s code a little.
+- Add a minor clarification to the SGML docs.
+- Avoid truncation in ip_cloaking (by removing components on the other side).
+  Note that this may cause channel +bqeI modes set on such very long hosts
+  to no longer match.
+
+-- charybdis-2.1.1
+
+- Search the shortest list (user's/channel's) when looking up channel
+  memberships.
+- Make the SID-collision notice look right under all conditions.
+- Move kills from services from +s to +k snomask.
+- When no_tilde is present on an auth{} block, check the non-tilde version
+  of the user@host against k:lines as well.
+- Put full reason in the SQUIT reason when a server is rejected for
+  insufficient parameters being passed to a command.
+- Don't redirect users to an existing domain, irc.fi.
+- Improve communication of servlink-related error messages.
+
+-- charybdis-2.1.0
+
+- Our official website is now http;//www.ircd-charybdis.org/.
+- Make RPL_ISUPPORT (005 numeric) modularizable.
+- Also do forwarding if the channel limit (+l) is exceeded.
+- Don't count opers on service{} servers in /lusers.
+- Allow servers to send to @#chan and +#chan.
+- Allow +S clients (services) to send to channels and @/+ channels always.
+- Allow normal match() on IP address also in /masktrace.
+- Add new testmask from ratbox 2.2. Allows matches on nick, ip and gecos
+  in addition to user and host, and is fully analogous to masktrace.
+  The numeric has changed from 724 to 727 and fields in it have changed.
+- Show IP addresses to opers in /whowas.
+- Add extb_extgecos extban option ($x:nick!user@host#gecos), from sorcery
+  modules.
+- Add extb_canjoin extban option ($j:#channel), matches if the user is banned
+  from the other channel.
+- Allow opers to /who based on realhost.
+- Allow opers to /masktrace, /testmask based on realhost.
+- Add general::operspy_dont_care_user_info, limits operspy accountability to
+  channel-related information.
+- Make host mangling more reliable.
+- Prevent ban evasion by enabling/disabling host mangling.
+- Add EUID, sends real host and services account in the same command as other
+  user information.
+- Make it possible to send CHGHOST without ENCAP (fixes problems with old
+  services).
+- Allow service{} servers to manipulate the nick delay table (for "nickserv
+  enforcement", aka SVSHOLD).
+- Send server notices about connections initiated by remote opers network wide.
+- Fix too early truncation of JOIN channel list.
+- Make the newconf system available to modules.
+- Add /stats s to the hurt module to list active hurts.
+- Add general::servicestring, shown in /whois for opered services (+oS).
+- Show real host/IP behind dynamic spoof in /whois to the user themselves
+  and opers.
+- Document option to disable nick delay.
+- Improve logging of server connections.
+- Clean up handling of hostnames in connect blocks.
+- Remove support for resolving ip6.int, people should be using ip6.arpa.
+- Unbreak --disable-balloc (useful for debugging with tools like valgrind).
+- Make Solaris 10 I/O ports code compile.
+- Add WEBIRC module to allow showing the real host/IP of CGI:IRC users.
+- Comment out blacklist{} block in example confs, as AHBL requires
+  notification before use.
+- Fix some bugs relating to the resolver.
+
+-- charybdis-2.0.0
+
+- Replace ADNS with a new smaller resolver from ircu and hybrid.
+- Make services shortcuts (/chanserv etc) configurable in ircd.conf.
+- Add extban: extensible +bqeI matching via modules. Syntax is
+  $<type>[:<data>]. By default no modules are loaded.
+- Add DNS blacklist checking.
+- Change operator{} block user@host from host to orighost. This means that
+  services/+h spoofs do not work in operator{} blocks; auth{} spoofs still
+  work. Check your operator{} blocks!
+- Split contrib/ into extensions/ and unsupported/.
+- Change CHGHOST do show the change to all other clients on common channels
+  with quit/join/mode.
+- Add /rehash nickdelay to clear out the nickdelay tables.
+- Glines are now disabled in the example confs.
+- Show more error messages on stderr.
+- Add OMODE command to extensions/ for easier oper mode hacking.
+- Add HURT system to extensions/; this shuns clients matching certain host/ip
+  unless and until they identify to services. Mainly intended for SorceryNet.
+- Show SASL success and failure counts in /stats t.
+- Allow more frequent autoconnects to servers.
+- Messaging services by nickname no longer uses target change slots.
+- Only accept SASL from servers in a service{} block.
+- New auth{} flag need_sasl to reject users who haven't done SASL
+  authentication.
+- Expand blah.blah and blah:blah to *!*@... instead of ...!*@* for bans
+- Don't allow opers to fake locops/operwall to +w.
+- Documentation updates.
+- Many bugfixes.
+
+-- charybdis-1.1.0
+
+- Implement SAFELIST.
+- Incorporate ircu's match() algorithm.
+- Improve usermode modularization.
+- Seperate server notices into a seperate snomask, freeing up many
+  usermodes to be used.
+- Add support for SIGNON originating from Hyperion2.
+- Modularize many server notices into seperate modules.
+- Add hooks for can_join and can_create_channel.
+- Add support for SASL authentication.
+- Add introduce_user hook for adding new messages when a user is bursted.
+- Move a large part of the ircd into libcharybdis.
+- Don't complain "unknown user mode" if a user tries to unset
+  a mode they do not have access to.
+- Update our challenge specification to the challenge implementation in
+  ratbox 2.2 for interoperability.
+- Make +f notices network-wide (local host, global host,
+  global user@host, local class), other notices tied to +f remain local.
+- Allow ENCAP REALHOST outside of netburst.
+- Add general::global_snotices option to make server notices be
+  network-wide or not.
+- Add sno_farconnect.c to contrib, provides farconnect support.
+  Could be useful for BOPM.
+- Add sno_routing.c which displays information about netsplits, netjoins
+  and the clients affected by them.
+- Add CHANTRACE and TRACEMASK commands from ratbox 3.0
+- Use IsOperAdmin() instead of IsAdmin() when sending admin-only messages,
+  that way hidden admins get them too.
+- Add m_error to core_module_table, somehow it was missing.
+- Correct a format string bug that occurs when a read error is
+  received.
+- Add some logging in places where we drop servers and only notify
+  server operators.
+- Track hostmask limits based on a client's original host, if
+  available.
+- Move HIDE_SPOOF_IPS into the general {} block in ircd.conf
+
+-- charybdis-1.0.3
+
+- Fix /invite UID leak. (Found by logiclrd@EFnet.)
+- Incorporate ratbox bugfixes for the MONITOR system.
+- Made show_ip() less braindead.
+- Show real errno if we fail to connect to a server.
+- Don't disclose server IP's when a connection fails.
+- Do not show the channels a service is sitting in.
+- Reverted the aline code from hybrid-7.2
+- Make sure TS6 services are recognized properly if connected remotely.
+- Tweak something in services support for cyrix boxes.
+
+-- charybdis-1.0.2
+
+- Fix propagation of an empty SJOIN (permanant channels).
+- Fix an exploit involving a malformed /trace request.
+- Don't display a blank RPL_WHOISCHANNELS in a remote whois request.
+- Allow modules to provide new usermodes.
+- On a nickname collision, change the collided nick to their unique ID,
+  if general::collision_fnc is enabled in the config.
+- Don't allow UID lookups in /monitor + and /monitor s
+- Fix a garbage issue with channel mode +j.
+- Apply proper capability flags to the proper server in me_gcap().
+- Use find_named_person() instead of find_person() in a nick collision.
+- Prevent UID disclosure in cmode setting.
+- Prevent UID disclosure to remote clients in /kick.
+- Do not allow users to query via /whois <server> <UID>.
+- Don't allow local users to use UID's in local usermode changes.
+- Propagate +q lists on netjunction.
+- Clear +q lists on a lowerTS SJOIN.
+- Ported a generic k/d/x-line parser from hybrid-7.2 which resulted in
+  duplicate code reduction.
+- Fix linebuf raw code to not truncate lines longer than 512 bytes;
+  improves ziplink reliability on net junction.
+- Use find_named_person() vs find_person() in services alias code.
+- Fix issue where channel forwarding token can be lost on net junction.
+- Fix empty channel desync issues involving +P.
+- Remove unused non-ENCAP CHGHOST support.
+- Use TS6 form for SQUIT wallops.
+- Propagate nickname changes for remote clients in TS6 form if possible,
+  even if sent in TS5 format.
+- Only clear oper_only_umodes for local clients on deoper.
+
+-- charybdis-1.0.1
+
+- Display logged in status on non-local clients too.
+- Documentation updates
+- Fix a bug with forward target authorization.
+- Fix a bug with mode propagation (+Q/+F).
+- Change ERR_NOSUCHNICK to ERR_SERVICESOFFLINE in services aliases.
+- Add remote rehashing.
+- Document service { } blocks (u:lines on ircu).
+- Document identify_service and identify_command in reference.conf.
+
+-- charybdis-1.0
+- Implement channel mode +L for channel list limit exemptions.
+- Implement channel mode +P primarily as a status mode, permanant 
+  channel -- this is usually enforced via services registrations.
+- Change behaviour of /stats p: now displays all staff members instead
+  of local ones only.
+- Make oper_list global, add local_oper_list for local traffic.
+- Strip control codes from parts and quits.
+- Add channel mode +c which strips control codes from messages sent to
+  the channel.
+- Add channel mode +g which enables free use of the /invite command.
+- Add channel mode +z which sends rejected messages to channel ops.
+  Could be useful for Q&A sessions or other similar events.
+- Add channel quietmasks. These are recommended over the use of channel
+  bans used to remove a user's ability to participate in the channel.
+- Add channel join throttling mode, +j. Used to throttle channel join
+  traffic, i.e. join/part flood attacks. Syntax: +j <joins>:<timeslice>
+- Improvements to channel_modes(), from shadowircd -- allows for
+  better construction of the mode string.
+- Use the undernet throttle notice instead of bancache message when
+  dealing with rejected clients. (stolen from ircu2.10.12)
+- Add channel forwarding, via channel mode +f, behaves similarly to
+  dancer-ircd version.
+- Update example.conf to reflect AthemeNET changes. Original ratbox
+  config is now reference.conf.
+- Services account names are now tracked globally.
+- Add channel mode +Q which disables the effects of channel forwarding
+  on a temporary basis.
+- Add channel mode +F which allows anybody to disable forwarding target
+  authorisation, voluntarily on their channels.
+- Make wallops behave like normal wallops.
+- Add services aliases: /ns, /cs, /os, /nickserv, /chanserv, /operserv.
+- Add simple hack that enables use of server password for automatic
+  identify.
+
+-- ircd-ratbox-2.1.5+datadrain
+- fix a buffer overflow and an unterminated buffer when TS6 forces us
+  to remove bans
+- fix potential junk SJOIN generation when splitting it into multiple
+  lines
+- make servlink check for an uncompressed ERROR
+- change NICKLEN to 15.
+- change TOPICLEN to 390.
+- force services extensions to be enabled always
+- change patchlevel.h to get it's information from 'configure'
+- add m_chghost.c, ghetto rigged hostcloaking module, using elite ENCAP
+  technique
+
+-- ircd-ratbox-2.1.4
+- fix minor time bug which occurs on december 31st
+- dont drop a servers link when we get a malformed WHOIS
+- disallow commas in channel keys
+- fix compile problem with abort_list
+- fix build on darwin
+- fix compilation with gcc4
+- userhost was only allowing 4 targets instead of 5
+- invalidate channel ban cache on nickchange
+- add TARGMAX to 005, detailing maximum targets for messages
+- fix counting of clients on accept list when adding users
+- use ID instead of name when bursting SJOIN to TS6 servers
+- lower id in struct User, which was one byte bigger than it needs to be
+
+-- ircd-ratbox-2.1.3
+- removed sendq_eob as it just doesnt work on efnet
+- dont allow MONITOR from an unregistered client
+- add some uniqueness into the auth process for bopm
+- fix resvs to check whether target server is us properly
+- fix a core in cidr channel ban matching
+- raise max temptime to a year
+- fix cores when we receive extra params to NICK/UID
+- remove no_oper_resvs, add resv_exempt auth flag
+- fix flattened links
+- clean up the accept code, and dont clear a users own list of accepted
+  clients on nickchange
+- non-efnet:
+  - make services {}; blocks be displayed on stats U
+  - make services {}; blocks apply on rehash, you must now have only ONE
+    service {}; block, but you may have multiple name=""; entries within.
+  - only show services logged in info for local clients
+
+-- ircd-ratbox-2.1.2
+- fix missing end comment tag in example confs
+- fix display problem with unauthorised conn notice
+- remove some unused defines from INFO
+- fix tabs for spaces in some helpfiles
+- add in missing links_delay conf option
+- fix cores under amd64
+- disallow bans beginning with ':' over BMASK
+- disallow bans with a space in chm_ban()
+- stop counting hidden opers in stats p count output
+- match() params of remote unresv were inverted, causing it to never match
+- fix possibility of clients setting blank keys
+- fix UID problems with trace
+- raise default topiclen to 160
+- add in forced nick change for ratbox-services, when compiled with
+  --enable-services
+
+-- ircd-ratbox-2.1.1
+- remove an 005 token to hack around the parser bug
+- exempt users messaging themselves from target change
+- disallow messaging towards UIDs
+- add in doc/tgchange.txt
+- move stats L back to RPL_STATSLINKINFO
+- fix some minor auth problems
+- properly store ipv6 ips when we're compiled for v4 only
+- fix propagation of xline/resv
+- sync remote kline reasons with form used for local klines
+
+-- ircd-ratbox-2.1.0
+- no changes
+
+-- ircd-ratbox-2.1.0beta2
+- fix a few compile warnings
+- added multi-prefix clicap, for showing "@+" in NAMES/WHO replies
+- remove split_delay, make split servers now work on how many servers have
+  issued EOB, rather than how many exist.
+- server-side notify lists.  See doc/monitor.txt
+- fix undline core
+- remove an unwanted space from beginning of second 005
+- fix a potential core with the patricia when removing classes
+- when we're handling global NAMES, dont output channels whose users are all
+  invisible
+
+-- ircd-ratbox-2.1.0beta1
+- No release notes, see doc/whats-new-2.1.txt
+
+--------------------------------------------------------------------------------
+
+BUGS: Major bugs in this release are listed in BUGS
+
+BUG REPORTS: If you run this code and encounter problems, you must report
+via IRC to irc.atheme.net, #athemenet-dev.
+
+Please include a gdb backtrace and keep the core file, binaries and 
+modules in case the developers need them.
+
+Other files recommended for reading: BUGS, README.FIRST, INSTALL
+
+--------------------------------------------------------------------------------
+$Id: NEWS 2813 2006-12-05 13:24:19Z jilles $
+
diff --git a/README.FIRST b/README.FIRST
new file mode 100644 (file)
index 0000000..6f58113
--- /dev/null
@@ -0,0 +1,102 @@
+If you don't read this first, we won't help you.
+:-)
+
+******************************* IMPORTANT *************************************
+
+  *********** Note for those who dont bother reading docs *****************
+  * - Reading INSTALL is now a must, as the old DPATH is now specified    *
+  *   when configure is run.                                              *
+  *   You now need to ./configure --prefix="/path/to/install/it"          *
+  * - The old config format WILL NOT WORK.  Please see doc/example.conf ! *
+  * - The old kline format WILL NOT WORK.  Please use convertklines which *
+  *   will be installed with your ircd!                                          *
+  *************************************************************************
+
+  ALSO, IF YOU ARE UPGRADING YOUR CURRENT SOURCE TREE, AND YOU TRY TO BUILD
+  IN IT WITHOUT PERFORMING AT LEAST 'make clean', THINGS _WILL_ BREAK.  IT IS
+  RECOMMENDED THAT YOU RUN 'make distclean' AND THEN RERUN './configure'!
+
+******************************* REQUIREMENTS **********************************
+
+Necessary Requirements:
+
+- A supported platform (look below)
+
+- A working dynamic load library, unless
+  compiling as static, without module
+  support.
+
+- A working lex.  Solaris /usr/ccs/bin/lex
+  appears to be broken, on this system flex
+  should be used.
+
+
+Feature Specific Requirements:
+
+- For the SSL Challenge controlled OPER feature and encrypted server links,
+  a working OpenSSL library
+
+- For encrypted oper and (optional) server passwords, a working DES and/or
+  MD5 library
+
+*******************************************************************************
+
+- To report bugs in ircd-ratbox, send the bug report to ircd-ratbox@lists.ratbox.org
+
+- Known bugs are listed in the BUGS file
+
+- See the INSTALL document for info on configuring and compiling
+  ircd-ratbox.
+
+- Please read doc/index.txt to get an overview of the current documentation.
+
+- Old Hybrid 5/6 configuration files are no longer supported.  All conf
+  files will have to be converted to the new format.  A convertconf
+  utility is provided and installed into bin/.
+
+- If you are wondering why config.h is practically empty, its because many 
+  things that were once in config.h are now specified in the 'general'
+  block of ircd.conf.  Look at example.conf for more information about
+  these options.
+
+- The files, /etc/services, /etc/protocols, and /etc/resolv.conf, MUST be
+  readable by the user running the server in order for ircd to start.
+  Errors from adns causing the ircd to refuse to start up are often related
+  to permission problems on these files.
+
+- There is a mailing list for ircd-ratbox.  To subscribe to this list
+  visit http://lists.ratbox.org/cgi-bin/mailman/listinfo/ircd-ratbox
+  Note that this list also gets the commit emails from the CVS server.
+
+- FREEBSD USERS: if you are compiling with ipv6 you may experience
+  problems with ipv4 due to the way the socket code is written.  To
+  fix this you must: "sysctl net.inet6.ip6.v6only=0"
+
+- SOLARIS USERS: this code appears to tickle a bug in older gcc and 
+  egcs ONLY on 64-bit Solaris7.  gcc-2.95 and SunPro C on 64bit should
+  work fine, and any gcc or SunPro compiled on 32bit.
+
+- DARWIN AND MACOS X USERS: You must be using at least the December 2001
+  Development Tools from Apple to build ircd-ratbox with shared modules.
+  Before then you MUST disable shared modules, as we do not have the proper
+  flags for cc(1) prior to that point to produce shared modules.
+
+- SUPPORTED PLATFORMS: this code should compile without any warnings
+  on FreeBSD 3.x/4.x, RedHat 6.2, Debian Potato and Solaris 7/8 sparc.  
+  Please let us know if you find otherwise.  
+  It probably does not compile on AIX, IRIX or libc5 Linux.
+
+- TESTED PLATFORMS:  The code has been tested on the following platforms, and
+  is known to run properly.
+  FreeBSD 3.x/4.x
+  Linux glibc
+  Solaris 2.6/7/8
+  OpenBSD 2.8
+  NetBSD 1.4
+
+- Please read doc/whats-new.txt for information about what is in this release
+
+- Other files recommended for reading: BUGS, INSTALL
+
+--------------------------------------------------------------------------------
+$Id: README.FIRST 1837 2006-08-22 14:05:58Z nenolod $
diff --git a/SVN-Access b/SVN-Access
new file mode 100644 (file)
index 0000000..63a13a9
--- /dev/null
@@ -0,0 +1,5 @@
+The charybdis repository is available for anonymous access:
+       svn co http://svn.atheme.org/charybdis/trunk charybdis-devel
+
+For the latest stable:
+       svn co http://svn.atheme.org/charybdis/branches/stable charybdis-stable
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644 (file)
index 0000000..cc5d05d
--- /dev/null
@@ -0,0 +1,50 @@
+# $Id: aclocal.m4 918 2006-02-23 18:17:21Z nenolod $ - aclocal.m4 - Autoconf fun...
+AC_DEFUN([AC_DEFINE_DIR], [
+  test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+  test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+  ac_define_dir=`eval echo [$]$2`
+  ac_define_dir=`eval echo [$]ac_define_dir`
+  $1="$ac_define_dir"
+  AC_SUBST($1)
+  ifelse($3, ,
+    AC_DEFINE_UNQUOTED($1, "$ac_define_dir"),
+    AC_DEFINE_UNQUOTED($1, "$ac_define_dir", $3))
+])
+
+AC_DEFUN([AC_SUBST_DIR], [
+        ifelse($2,,,$1="[$]$2")
+        $1=`(
+            test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+            test "x$exec_prefix" = xNONE && exec_prefix="${prefix}"
+            eval echo \""[$]$1"\"
+        )`
+        AC_SUBST($1)
+])
+
+dnl CHARYBDIS_C_GCC_TRY_FLAGS(<warnings>,<cachevar>)
+AC_DEFUN([CHARYBDIS_C_GCC_TRY_FLAGS],[
+ AC_MSG_CHECKING([GCC flag(s) $1])
+ if test "${GCC-no}" = yes
+ then
+  AC_CACHE_VAL($2,[
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} $1 -Werror"
+   AC_TRY_COMPILE([
+#include <string.h>
+#include <stdio.h>
+int main(void);
+],[
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+], [$2=yes], [$2=no])
+   CFLAGS="${oldcflags}"])
+  if test "x$$2" = xyes; then
+   CWARNS="${CWARNS}$1 "
+   AC_MSG_RESULT(ok)  
+  else
+   $2=''
+   AC_MSG_RESULT(no)
+  fi
+ else
+  AC_MSG_RESULT(no, not using GCC)
+ fi
+])
diff --git a/configure b/configure
new file mode 100755 (executable)
index 0000000..847ad0b
--- /dev/null
+++ b/configure
@@ -0,0 +1,15592 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.59 for charybdis 2.1.2.
+#
+# $Id: configure 2811 2006-12-05 13:18:39Z jilles $
+#
+# Copyright (C) 2003 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 Bourne compatible
+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+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+  set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+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
+  fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; 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'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# 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
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x$as_lineno_3"  = "x$as_lineno_2"  || {
+  # Find who we are.  Look in the path if we contain no path at all
+  # relative or not.
+  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
+
+       ;;
+  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_me: error: cannot find myself; rerun with an absolute path" >&2
+   { (exit 1); exit 1; }; }
+  fi
+  case $CONFIG_SHELL in
+  '')
+    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=.
+  for as_base in sh bash ksh sh5; do
+        case $as_dir in
+        /*)
+          if ("$as_dir/$as_base" -c '
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x$as_lineno_3"  = "x$as_lineno_2" ') 2>/dev/null; then
+            $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+            $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+            CONFIG_SHELL=$as_dir/$as_base
+            export CONFIG_SHELL
+            exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+          fi;;
+        esac
+       done
+done
+;;
+  esac
+
+  # 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 before each line; the second 'sed' does the real
+  # work.  The second script uses 'N' to pair each line-number line
+  # with the numbered line, 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
+  # second 'sed' script.  Blame Lee E. McMahon for sed's syntax.  :-)
+  sed '=' <$as_myself |
+    sed '
+      N
+      s,$,-,
+      : loop
+      s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+      t loop
+      s,-$,,
+      s,^['$as_cr_digits']*\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 sensible to this).
+  . ./$as_me.lineno
+  # Exit status is that of the last command.
+  exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+  *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T='     ' ;;
+  *c*,*  ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+  *)       ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+  # We could just check for DJGPP; but this test a) works b) is more generic
+  # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+  if test -f conf$$.exe; then
+    # Don't use ln at all; we don't have any links
+    as_ln_s='cp -p'
+  else
+    as_ln_s='ln -s'
+  fi
+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$$.file
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# 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'"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS="  $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+
+# 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`
+
+exec 6>&1
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_config_libobj_dir=.
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Maximum number of lines to put in a shell here document.
+# This variable seems obsolete.  It should probably be removed, and
+# only ac_max_sed_lines should be used.
+: ${ac_max_here_lines=38}
+
+# Identity of this package.
+PACKAGE_NAME='charybdis'
+PACKAGE_TARNAME='charybdis'
+PACKAGE_VERSION='2.1.2'
+PACKAGE_STRING='charybdis 2.1.2'
+PACKAGE_BUGREPORT=''
+
+ac_default_prefix=$HOME/ircd
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+#if 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 datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT MKDEP MAKEDEPEND STDOUT CPP EGREP SET_MAKE INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA RM CP MV LN SED AR LD RANLIB TOUCH YACC LEX LEXLIB LEX_OUTPUT_ROOT CRYPT_LIB VICONF ALLOCA ENCSPEED ZLIB_LD ETC_DIR confdir LOG_DIR logdir HELP_DIR helpdir MODULE_DIR moduledir SELECT_TYPE FNVHASH_S MODULES_LIBS MOD_TARGET SSL_SRCS_ENABLE SSL_INCLUDES SSL_LIBS PICFLAGS IRC_CFLAGS SEDOBJ LIBOBJS LTLIBOBJS'
+ac_subst_files=''
+
+# 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.
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+ac_prev=
+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
+
+  ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_option in
+
+  -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 | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir=$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" ;;
+
+  -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'`
+    case $ac_option in
+      *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+      *) ac_optarg=yes ;;
+    esac
+    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 ;;
+
+  -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 ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    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 ;;
+
+  -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'`
+    case $ac_option in
+      *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+      *) ac_optarg=yes ;;
+    esac
+    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; }; }
+    ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+    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 paths.
+for ac_var in exec_prefix prefix
+do
+  eval ac_val=$`echo $ac_var`
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
+    *)  { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+   { (exit 1); exit 1; }; };;
+  esac
+done
+
+# Be sure to have absolute paths.
+for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
+             localstatedir libdir includedir oldincludedir infodir mandir
+do
+  eval ac_val=$`echo $ac_var`
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* ) ;;
+    *)  { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+   { (exit 1); exit 1; }; };;
+  esac
+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
+
+
+# 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 its parent.
+  ac_confdir=`(dirname "$0") 2>/dev/null ||
+$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
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
+   { (exit 1); exit 1; }; }
+  else
+    { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+   { (exit 1); exit 1; }; }
+  fi
+fi
+(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null ||
+  { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2
+   { (exit 1); exit 1; }; }
+srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
+ac_env_build_alias_set=${build_alias+set}
+ac_env_build_alias_value=$build_alias
+ac_cv_env_build_alias_set=${build_alias+set}
+ac_cv_env_build_alias_value=$build_alias
+ac_env_host_alias_set=${host_alias+set}
+ac_env_host_alias_value=$host_alias
+ac_cv_env_host_alias_set=${host_alias+set}
+ac_cv_env_host_alias_value=$host_alias
+ac_env_target_alias_set=${target_alias+set}
+ac_env_target_alias_value=$target_alias
+ac_cv_env_target_alias_set=${target_alias+set}
+ac_cv_env_target_alias_value=$target_alias
+ac_env_CC_set=${CC+set}
+ac_env_CC_value=$CC
+ac_cv_env_CC_set=${CC+set}
+ac_cv_env_CC_value=$CC
+ac_env_CFLAGS_set=${CFLAGS+set}
+ac_env_CFLAGS_value=$CFLAGS
+ac_cv_env_CFLAGS_set=${CFLAGS+set}
+ac_cv_env_CFLAGS_value=$CFLAGS
+ac_env_LDFLAGS_set=${LDFLAGS+set}
+ac_env_LDFLAGS_value=$LDFLAGS
+ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
+ac_cv_env_LDFLAGS_value=$LDFLAGS
+ac_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_env_CPPFLAGS_value=$CPPFLAGS
+ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_cv_env_CPPFLAGS_value=$CPPFLAGS
+ac_env_CPP_set=${CPP+set}
+ac_env_CPP_value=$CPP
+ac_cv_env_CPP_set=${CPP+set}
+ac_cv_env_CPP_value=$CPP
+
+#
+# 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 charybdis 2.1.2 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 \`..']
+
+_ACEOF
+
+  cat <<_ACEOF
+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]
+  --datadir=DIR          read-only architecture-independent data [PREFIX/share]
+  --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]
+  --infodir=DIR          info documentation [PREFIX/info]
+  --mandir=DIR           man documentation [PREFIX/man]
+_ACEOF
+
+  cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+  case $ac_init_help in
+     short | recursive ) echo "Configuration of charybdis 2.1.2:";;
+   esac
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-ipv6           Enable IPv6 support
+  --enable-openssl=DIR  Enable OpenSSL support (DIR optional).
+  --disable-openssl       Disable OpenSSL support.
+  --disable-zlib          Disable ziplinks support
+  --enable-poll           Force poll() usage.
+  --enable-select         Force select() usage.
+  --enable-kqueue         Force kqueue() usage.
+  --enable-devpoll        Force usage of /dev/poll.
+  --enable-epoll          Force sys_epoll usage (Linux only).
+  --enable-assert         Enable assert(). Choose between soft(warnings) and
+                          hard(aborts the daemon)
+  --enable-iodebug        Enable IO Debugging hooks
+  --enable-profile        Enable profiling
+  --disable-balloc        Disable the block allocator.
+  --enable-ricer-hashing  Enable assembly-based hashing routines.
+  --enable-small-net      Enable small network support.
+  --disable-shared-modules
+                          Disable shared modules.
+  --enable-warnings       Enable all sorts of warnings for debugging.
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-zlib-path=DIR    Path to libz.so for ziplinks support.
+  --with-confdir=DIR      Directory to install config files.
+  --with-logdir=DIR       Directory where to write logfiles.
+  --with-helpdir=DIR      Directory to install help files.
+  --with-moduledir=DIR    Directory to install modules.
+  --with-nicklen=LENGTH   Set the nick length to LENGTH (default 15, max 50)
+  --with-topiclen=NUMBER  Set the max topic length to NUMBER (default 390, max
+                          390)
+  --with-maxclients=NUMBER
+                          Maximum number of connections the ircd can handle
+
+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>
+  CPPFLAGS    C/C++ preprocessor flags, e.g. -I<include dir> if you have
+              headers in a nonstandard directory <include dir>
+  CPP         C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+_ACEOF
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  ac_popdir=`pwd`
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d $ac_dir || continue
+    ac_builddir=.
+
+if test "$ac_dir" != .; then
+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+  # A "../" for each directory in $ac_dir_suffix.
+  ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+  ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+  .)  # No --srcdir option.  We are building in place.
+    ac_srcdir=.
+    if test -z "$ac_top_builddir"; then
+       ac_top_srcdir=.
+    else
+       ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+    fi ;;
+  [\\/]* | ?:[\\/]* )  # Absolute path.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir ;;
+  *) # Relative path.
+    ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+  case "$ac_dir" in
+  .) ac_abs_builddir=`pwd`;;
+  [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+  *) ac_abs_builddir=`pwd`/"$ac_dir";;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+  case ${ac_top_builddir}. in
+  .) ac_abs_top_builddir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+  *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+  case $ac_srcdir in
+  .) ac_abs_srcdir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+  *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+  case $ac_top_srcdir in
+  .) ac_abs_top_srcdir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+  *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+  esac;;
+esac
+
+    cd $ac_dir
+    # Check for guested configure; otherwise get Cygnus style 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
+    elif test -f $ac_srcdir/configure.ac ||
+          test -f $ac_srcdir/configure.in; then
+      echo
+      $ac_configure --help
+    else
+      echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi
+    cd $ac_popdir
+  done
+fi
+
+test -n "$ac_init_help" && exit 0
+if $ac_init_version; then
+  cat <<\_ACEOF
+charybdis configure 2.1.2
+generated by GNU Autoconf 2.59
+
+Copyright (C) 2003 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+
+$Id: configure 2811 2006-12-05 13:18:39Z jilles $
+_ACEOF
+  exit 0
+fi
+exec 5>config.log
+cat >&5 <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by charybdis $as_me 2.1.2, which was
+generated by GNU Autoconf 2.59.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+{
+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`
+hostinfo               = `(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
+
+} >&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_sep=
+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_sep'$ac_arg'"
+      # Get rid of the leading space.
+      ac_sep=" "
+      ;;
+    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: Be sure not to use single quotes in there, as some shells,
+# such as our DU 5.0 friend, will then `close' the trap.
+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,
+{
+  (set) 2>&1 |
+    case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in
+    *ac_space=\ *)
+      sed -n \
+       "s/'"'"'/'"'"'\\\\'"'"''"'"'/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
+      ;;
+    *)
+      sed -n \
+       "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+      ;;
+    esac;
+}
+    echo
+
+    cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=$`echo $ac_var`
+      echo "$ac_var='"'"'$ac_val'"'"'"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      cat <<\_ASBOX
+## ------------- ##
+## Output files. ##
+## ------------- ##
+_ASBOX
+      echo
+      for ac_var in $ac_subst_files
+      do
+       eval ac_val=$`echo $ac_var`
+       echo "$ac_var='"'"'$ac_val'"'"'"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+      echo
+      sed "/^$/d" confdefs.h | sort
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      echo "$as_me: caught signal $ac_signal"
+    echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core &&
+  rm -rf 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 -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo >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 -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; 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 `(set) 2>&1 |
+              sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; 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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+          ac_config_headers="$ac_config_headers include/setup.h"
+
+
+
+
+
+cat >>confdefs.h <<\_ACEOF
+#define _GNU_SOURCE 1
+_ACEOF
+
+
+
+OLD_CFLAGS="$CFLAGS"
+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 $as_executable_p "$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
+
+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 $as_executable_p "$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
+
+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
+
+  CC=$ac_ct_CC
+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 $as_executable_p "$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
+
+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 "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_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 $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+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
+
+  CC=$ac_ct_CC
+else
+  CC="$ac_cv_prog_CC"
+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 $as_executable_p "$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
+
+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
+  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 $as_executable_p "$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
+
+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
+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 $as_executable_p "$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
+
+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
+
+  CC=$ac_ct_CC
+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`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+  (eval $ac_compiler --version </dev/null >&5) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+  (eval $ac_compiler -v </dev/null >&5) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+  (eval $ac_compiler -V </dev/null >&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[^ ]*//'`
+if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5
+  (eval $ac_link_default) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # Find the output, starting from the most likely.  This scheme is
+# not robust to junk in `.', hence go to wildcards (a.*) only as a last
+# resort.
+
+# Be careful to initialize this variable, since it used to be cached.
+# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile.
+ac_cv_exeext=
+# b.out is created by i960 compilers.
+for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj )
+       ;;
+    conftest.$ac_ext )
+       # This is the source file.
+       ;;
+    [ab].out )
+       # We found the default executable, but exeext='' is most
+       # certainly right.
+       break;;
+    *.* )
+       ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+       # FIXME: I believe we export ac_cv_exeext for Libtool,
+       # but it would be cool to find out if it's true.  Does anybody
+       # maintain Libtool? --akim.
+       export ac_cv_exeext
+       break;;
+    * )
+       break;;
+  esac
+done
+else
+  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
+echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6
+
+# Check 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'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&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 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 { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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 | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+         export ac_cv_exeext
+         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 { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;;
+    *) 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 { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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
+CFLAGS="-g"
+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
+  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 { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_cc_g=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+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 ANSI C" >&5
+echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_stdc+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_prog_cc_stdc=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 -std1 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 -std1.  */
+int osf4_cc_array ['\x00' == 0 ? 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
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX                  -qlanglvl=ansi
+# Ultrix and OSF/1     -std1
+# HP-UX 10.20 and later        -Ae
+# HP-UX older versions -Aa -D_HPUX_SOURCE
+# SVR4                 -Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_prog_cc_stdc=$ac_arg
+break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext
+done
+rm -f conftest.$ac_ext conftest.$ac_objext
+CC=$ac_save_CC
+
+fi
+
+case "x$ac_cv_prog_cc_stdc" in
+  x|xno)
+    echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6 ;;
+  *)
+    echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
+    CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+# Some people use a C++ compiler to compile C.  Since we use `exit',
+# in C++ we need to declare it.  In case someone uses the same compiler
+# for both compiling C and C++ we need to have the C++ compiler decide
+# the declaration of exit, since it's the most demanding environment.
+cat >conftest.$ac_ext <<_ACEOF
+#ifndef __cplusplus
+  choke me
+#endif
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  for ac_declaration in \
+   '' \
+   'extern "C" void std::exit (int) throw (); using std::exit;' \
+   'extern "C" void std::exit (int); using std::exit;' \
+   'extern "C" void exit (int) throw ();' \
+   'extern "C" void exit (int);' \
+   'void exit (int);'
+do
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_declaration
+#include <stdlib.h>
+int
+main ()
+{
+exit (42);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+continue
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_declaration
+int
+main ()
+{
+exit (42);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+  echo '#ifdef __cplusplus' >>confdefs.h
+  echo $ac_declaration      >>confdefs.h
+  echo '#endif'             >>confdefs.h
+fi
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+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
+
+
+CFLAGS="$OLD_CFLAGS"
+
+
+if test "$ac_cv_c_compiler_gnu" != yes; then
+
+SGS=no
+echo "$as_me:$LINENO: checking $CC -version for TenDRA or MIPSpro" >&5
+echo $ECHO_N "checking $CC -version for TenDRA or MIPSpro... $ECHO_C" >&6
+case `$CC -version 2>&1` in
+*TenDRA*)
+       echo "$as_me:$LINENO: result: yes, TenDRA" >&5
+echo "${ECHO_T}yes, TenDRA" >&6
+       IRC_CFLAGS=""
+       CPPFLAGS="$CPPFLAGS -Ylonglong -Yansi -I/usr/include"
+       SGS=yes
+       TenDRA=yes
+;;
+*MIPSpro*)
+       echo "$as_me:$LINENO: result: yes, MIPSpro" >&5
+echo "${ECHO_T}yes, MIPSpro" >&6
+       MIPSpro=yes
+       SGS=yes
+;;
+*)
+       echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+       TenDRA=no
+       MIPSpro=no
+;;
+esac
+
+echo "$as_me:$LINENO: checking $CC -V for Sun Workshop, Forte, HPUX or Tru64 cc" >&5
+echo $ECHO_N "checking $CC -V for Sun Workshop, Forte, HPUX or Tru64 cc... $ECHO_C" >&6
+case `$CC -V 2>&1` in
+*Sun*WorkShop* | *Forte*Developer*)
+       echo "$as_me:$LINENO: result: Sun Workshop/Forte" >&5
+echo "${ECHO_T}Sun Workshop/Forte" >&6
+       IRC_CFLAGS="-fast -xinline=dlinkAdd,dlinkAddBefore,dlinkAddTail,dlinkDelete,dlink_list_length,dlink_node,dlinkMoveList,_MyMalloc,_MyRealloc,_MyFree,_DupString"
+       SunWorkShop=yes
+       SGS=yes
+;;
+*Tru64*)
+       echo "$as_me:$LINENO: result: Tru64 cc" >&5
+echo "${ECHO_T}Tru64 cc" >&6
+       IRC_CFLAGS="-O2"
+       CPPFLAGS="-I/usr/local/include"
+       Tru=yes
+;;
+*HP*ANSI*)
+       echo "$as_me:$LINENO: result: HPUX cc" >&5
+echo "${ECHO_T}HPUX cc" >&6
+       HPUX=yes
+       IRC_CFLAGS="+e"
+;;
+*)
+       echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+;;
+esac
+
+fi
+
+echo "$as_me:$LINENO: checking uname -s for Cygwin, Solaris, AIX or HPUX" >&5
+echo $ECHO_N "checking uname -s for Cygwin, Solaris, AIX or HPUX... $ECHO_C" >&6
+OSNAME=`uname -s`
+case "$OSNAME" in
+        HP-UX*)
+
+               if test "$HPUX" != yes -a "$ac_cv_c_compiler_gnu" = no; then
+                       echo "$as_me:$LINENO: result: assuming old HPUX with its own cc" >&5
+echo "${ECHO_T}assuming old HPUX with its own cc" >&6
+                       IRC_CFLAGS="$IRC_CFLAGS +e"
+                       HPUX=yes
+               else
+                       echo "$as_me:$LINENO: result: already using newer HPUX" >&5
+echo "${ECHO_T}already using newer HPUX" >&6
+               fi
+       ;;
+       CYGWIN*)
+               echo "$as_me:$LINENO: result: Cygwin" >&5
+echo "${ECHO_T}Cygwin" >&6
+               CYGWIN=yes
+       ;;
+       SunOS*)
+               echo "$as_me:$LINENO: result: SunOS or Solaris" >&5
+echo "${ECHO_T}SunOS or Solaris" >&6
+
+cat >>confdefs.h <<\_ACEOF
+#define __EXTENSIONS__ 1
+_ACEOF
+
+               SUN=yes
+       ;;
+       AIX*)
+               echo "$as_me:$LINENO: result: AIX - Sorry you poor bastard..really we are" >&5
+echo "${ECHO_T}AIX - Sorry you poor bastard..really we are" >&6
+               IRC_CFLAGS="$IRC_CFLAGS -Wl,-brtl -Wl,-G"
+       ;;
+       *)
+               echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+       ;;
+esac
+
+if test "$ac_cv_c_compiler_gnu" = yes; then
+       echo "$as_me:$LINENO: checking if $CC is Apple GCC" >&5
+echo $ECHO_N "checking if $CC is Apple GCC... $ECHO_C" >&6
+
+       case `$CC -v 2>&1 | tail -n 1` in
+       *Apple*)
+               echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+               AppleGCC=yes
+       ;;
+       *)
+               echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+               AppleGCC=no
+       ;;
+       esac
+
+       IRC_CFLAGS="$IRC_CFLAGS -O0 -Wall"
+fi
+
+if test "$ac_cv_prog_cc_g" = yes; then
+               if test "$Tru" = yes; then
+               IRC_CFLAGS="$IRC_CFLAGS -g3"
+       else
+               IRC_CFLAGS="$IRC_CFLAGS -g"
+       fi
+fi
+
+echo "$as_me:$LINENO: checking if $CC supports the SVR4 SGS interfaces" >&5
+echo $ECHO_N "checking if $CC supports the SVR4 SGS interfaces... $ECHO_C" >&6
+if test "$SGS" = "yes"; then
+       echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+       echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+# Extract the first word of "mkdep", so it can be a program name with args.
+set dummy mkdep; 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_MKDEP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $MKDEP in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_MKDEP="$MKDEP" # 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 $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_MKDEP="$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
+
+  ;;
+esac
+fi
+MKDEP=$ac_cv_path_MKDEP
+
+if test -n "$MKDEP"; then
+  echo "$as_me:$LINENO: result: $MKDEP" >&5
+echo "${ECHO_T}$MKDEP" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+# Extract the first word of "makedepend", so it can be a program name with args.
+set dummy makedepend; 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_MAKEDEPEND+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $MAKEDEPEND in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_MAKEDEPEND="$MAKEDEPEND" # 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 $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_MAKEDEPEND="$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
+
+  ;;
+esac
+fi
+MAKEDEPEND=$ac_cv_path_MAKEDEPEND
+
+if test -n "$MAKEDEPEND"; then
+  echo "$as_me:$LINENO: result: $MAKEDEPEND" >&5
+echo "${ECHO_T}$MAKEDEPEND" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+
+echo "$as_me:$LINENO: checking how to generate dependency info" >&5
+echo $ECHO_N "checking how to generate dependency info... $ECHO_C" >&6
+
+STDOUT="> .depend"
+
+if test "$ac_cv_c_compiler_gnu" = yes; then
+       echo "$as_me:$LINENO: result: gcc -MM" >&5
+echo "${ECHO_T}gcc -MM" >&6
+       MKDEP="$CC -MM"
+elif test ! -z "$MKDEP"; then
+       echo "$as_me:$LINENO: result: mkdep" >&5
+echo "${ECHO_T}mkdep" >&6
+
+               if test -z "$Tru"; then
+               STDOUT=""
+       else
+               STDOUT=" 2> /dev/null"
+       fi
+elif test "$SunWorkShop" = yes; then
+       echo "$as_me:$LINENO: result: $CC -xM" >&5
+echo "${ECHO_T}$CC -xM" >&6
+       MKDEP="$CC -xM"
+       STDOUT="> .depend 2> /dev/null"
+elif test ! -z "$MAKEDEPEND"; then
+       echo "$as_me:$LINENO: result: makedepend" >&5
+echo "${ECHO_T}makedepend" >&6
+       MKDEP="$MAKEDEPEND -f-"
+else
+       echo "$as_me:$LINENO: result: nothing suitable.. forget it!" >&5
+echo "${ECHO_T}nothing suitable.. forget it!" >&6
+       MKDEP=":"
+fi
+
+
+
+
+echo "$as_me:$LINENO: checking for /dev/null" >&5
+echo $ECHO_N "checking for /dev/null... $ECHO_C" >&6
+if test -c /dev/null ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define PATH_DEVNULL "/dev/null"
+_ACEOF
+
+       echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+
+cat >>confdefs.h <<\_ACEOF
+#define PATH_DEVNULL "devnull.log"
+_ACEOF
+
+       echo "$as_me:$LINENO: result: no - using devnull.log" >&5
+echo "${ECHO_T}no - using devnull.log" >&6
+fi
+
+if test ! -z "$CFLAGS"; then
+       IRC_CFLAGS="$IRC_CFLAGS $CFLAGS"
+fi
+
+
+echo "$as_me:$LINENO: checking for library containing strerror" >&5
+echo $ECHO_N "checking for library containing strerror... $ECHO_C" >&6
+if test "${ac_cv_search_strerror+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+ac_cv_search_strerror=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char strerror ();
+int
+main ()
+{
+strerror ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_strerror="none required"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_strerror" = no; then
+  for ac_lib in cposix; do
+    LIBS="-l$ac_lib  $ac_func_search_save_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 gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char strerror ();
+int
+main ()
+{
+strerror ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_strerror="-l$ac_lib"
+break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+  done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_strerror" >&5
+echo "${ECHO_T}$ac_cv_search_strerror" >&6
+if test "$ac_cv_search_strerror" != no; then
+  test "$ac_cv_search_strerror" = "none required" || LIBS="$ac_cv_search_strerror $LIBS"
+
+fi
+
+echo "$as_me:$LINENO: checking for inline" >&5
+echo $ECHO_N "checking for inline... $ECHO_C" >&6
+if test "${ac_cv_c_inline+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_c_inline=$ac_kw; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5
+echo "${ECHO_T}$ac_cv_c_inline" >&6
+
+
+case $ac_cv_c_inline in
+  inline | yes) ;;
+  *)
+    case $ac_cv_c_inline in
+      no) ac_val=;;
+      *) ac_val=$ac_cv_c_inline;;
+    esac
+    cat >>confdefs.h <<_ACEOF
+#ifndef __cplusplus
+#define inline $ac_val
+#endif
+_ACEOF
+    ;;
+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
+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 { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&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; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_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 non-existent 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 { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&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; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_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 { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&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; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_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 non-existent 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 { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&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; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_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 egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6
+if test "${ac_cv_prog_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_prog_egrep='grep -E'
+    else ac_cv_prog_egrep='egrep'
+    fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5
+echo "${ECHO_T}$ac_cv_prog_egrep" >&6
+ EGREP=$ac_cv_prog_egrep
+
+
+if test $ac_cv_c_compiler_gnu = yes; then
+    echo "$as_me:$LINENO: checking whether $CC needs -traditional" >&5
+echo $ECHO_N "checking whether $CC needs -traditional... $ECHO_C" >&6
+if test "${ac_cv_prog_gcc_traditional+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+    ac_pattern="Autoconf.*'x'"
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sgtty.h>
+Autoconf TIOCGETP
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "$ac_pattern" >/dev/null 2>&1; then
+  ac_cv_prog_gcc_traditional=yes
+else
+  ac_cv_prog_gcc_traditional=no
+fi
+rm -f conftest*
+
+
+  if test $ac_cv_prog_gcc_traditional = no; then
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <termio.h>
+Autoconf TCGETA
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "$ac_pattern" >/dev/null 2>&1; then
+  ac_cv_prog_gcc_traditional=yes
+fi
+rm -f conftest*
+
+  fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_gcc_traditional" >&5
+echo "${ECHO_T}$ac_cv_prog_gcc_traditional" >&6
+  if test $ac_cv_prog_gcc_traditional = yes; then
+    CC="$CC -traditional"
+  fi
+fi
+
+echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'`
+if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.make <<\_ACEOF
+all:
+       @echo 'ac_maketemp="$(MAKE)"'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftest.make
+fi
+if eval "test \"`echo '$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
+
+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
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"
+ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure.
+
+# 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 $as_executable_p "$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
+
+
+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.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    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'
+
+# Extract the first word of "rm", so it can be a program name with args.
+set dummy rm; 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_RM+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $RM in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_RM="$RM" # 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 $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_RM="$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
+
+  ;;
+esac
+fi
+RM=$ac_cv_path_RM
+
+if test -n "$RM"; then
+  echo "$as_me:$LINENO: result: $RM" >&5
+echo "${ECHO_T}$RM" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+# Extract the first word of "cp", so it can be a program name with args.
+set dummy cp; 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_CP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $CP in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_CP="$CP" # 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 $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_CP="$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
+
+  ;;
+esac
+fi
+CP=$ac_cv_path_CP
+
+if test -n "$CP"; then
+  echo "$as_me:$LINENO: result: $CP" >&5
+echo "${ECHO_T}$CP" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+# Extract the first word of "mv", so it can be a program name with args.
+set dummy mv; 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_MV+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $MV in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_MV="$MV" # 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 $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_MV="$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
+
+  ;;
+esac
+fi
+MV=$ac_cv_path_MV
+
+if test -n "$MV"; then
+  echo "$as_me:$LINENO: result: $MV" >&5
+echo "${ECHO_T}$MV" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+# Extract the first word of "ln", so it can be a program name with args.
+set dummy ln; 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_LN+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $LN in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_LN="$LN" # 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 $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_LN="$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
+
+  ;;
+esac
+fi
+LN=$ac_cv_path_LN
+
+if test -n "$LN"; then
+  echo "$as_me:$LINENO: result: $LN" >&5
+echo "${ECHO_T}$LN" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+# Extract the first word of "sed", so it can be a program name with args.
+set dummy sed; 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_SED+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $SED in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_SED="$SED" # 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 $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_SED="$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
+
+  ;;
+esac
+fi
+SED=$ac_cv_path_SED
+
+if test -n "$SED"; then
+  echo "$as_me:$LINENO: result: $SED" >&5
+echo "${ECHO_T}$SED" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+# Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; 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_AR+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $AR in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_AR="$AR" # 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 $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_AR="$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
+
+  ;;
+esac
+fi
+AR=$ac_cv_path_AR
+
+if test -n "$AR"; then
+  echo "$as_me:$LINENO: result: $AR" >&5
+echo "${ECHO_T}$AR" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+# Extract the first word of "ld", so it can be a program name with args.
+set dummy ld; 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_LD+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $LD in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_LD="$LD" # 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 $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_LD="$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
+
+  ;;
+esac
+fi
+LD=$ac_cv_path_LD
+
+if test -n "$LD"; then
+  echo "$as_me:$LINENO: result: $LD" >&5
+echo "${ECHO_T}$LD" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; 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_RANLIB+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $RANLIB in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_RANLIB="$RANLIB" # 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 $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_RANLIB="$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
+
+  ;;
+esac
+fi
+RANLIB=$ac_cv_path_RANLIB
+
+if test -n "$RANLIB"; then
+  echo "$as_me:$LINENO: result: $RANLIB" >&5
+echo "${ECHO_T}$RANLIB" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+# Extract the first word of "touch", so it can be a program name with args.
+set dummy touch; 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_TOUCH+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $TOUCH in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_TOUCH="$TOUCH" # 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 $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_TOUCH="$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
+
+  ;;
+esac
+fi
+TOUCH=$ac_cv_path_TOUCH
+
+if test -n "$TOUCH"; then
+  echo "$as_me:$LINENO: result: $TOUCH" >&5
+echo "${ECHO_T}$TOUCH" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+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 $as_executable_p "$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
+
+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" = "yacc" -a -z "`which $YACC 2>/dev/null`"; then
+       { { echo "$as_me:$LINENO: error: could not locate a suitable parser generator; install bison, yacc, or byacc" >&5
+echo "$as_me: error: could not locate a suitable parser generator; install bison, yacc, or byacc" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+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 $as_executable_p "$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
+
+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 -z "$LEXLIB"
+then
+  echo "$as_me:$LINENO: checking for yywrap in -lfl" >&5
+echo $ECHO_N "checking for yywrap in -lfl... $ECHO_C" >&6
+if test "${ac_cv_lib_fl_yywrap+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lfl  $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 gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char yywrap ();
+int
+main ()
+{
+yywrap ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_fl_yywrap=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_fl_yywrap=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_fl_yywrap" >&5
+echo "${ECHO_T}$ac_cv_lib_fl_yywrap" >&6
+if test $ac_cv_lib_fl_yywrap = yes; then
+  LEXLIB="-lfl"
+else
+  echo "$as_me:$LINENO: checking for yywrap in -ll" >&5
+echo $ECHO_N "checking for yywrap in -ll... $ECHO_C" >&6
+if test "${ac_cv_lib_l_yywrap+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ll  $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 gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char yywrap ();
+int
+main ()
+{
+yywrap ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_l_yywrap=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_l_yywrap=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_l_yywrap" >&5
+echo "${ECHO_T}$ac_cv_lib_l_yywrap" >&6
+if test $ac_cv_lib_l_yywrap = yes; then
+  LEXLIB="-ll"
+fi
+
+fi
+
+fi
+
+if test "x$LEX" != "x:"; then
+  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
+  # The minimal lex program is just a single line: %%.  But some broken lexes
+# (Solaris, I think it was) want two %% lines, so accommodate them.
+cat >conftest.l <<_ACEOF
+%%
+%%
+_ACEOF
+{ (eval echo "$as_me:$LINENO: \"$LEX conftest.l\"") >&5
+  (eval $LEX conftest.l) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+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
+rm -f conftest.l
+LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root
+
+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
+echo 'extern char *yytext;' >>$LEX_OUTPUT_ROOT.c
+ac_save_LIBS=$LIBS
+LIBS="$LIBS $LEXLIB"
+cat >conftest.$ac_ext <<_ACEOF
+`cat $LEX_OUTPUT_ROOT.c`
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_save_LIBS
+rm -f "${LEX_OUTPUT_ROOT}.c"
+
+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
+
+fi
+
+if test "$LEX" = ":"; then
+       { { echo "$as_me:$LINENO: error: could not locate a suitable lexical generator, install flex or lex." >&5
+echo "$as_me: error: could not locate a suitable lexical generator, install flex or lex." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+if test "$libexecdir" = '${exec_prefix}/libexec' &&
+   test "$localstatedir" = '${prefix}/var'; then
+       libexecdir='${bindir}'
+       localstatedir='${prefix}'
+fi
+
+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 { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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>
+#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))
+      exit(2);
+  exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&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 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 eval "test \"\${$as_ac_Header+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 { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&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 sys/resource.h sys/param.h errno.h sys/syslog.h stddef.h sys/wait.h wait.h sys/epoll.h sys/uio.h machine/endian.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&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 { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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 { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&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; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_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;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the charybdis lists.  ##
+## ------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&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 for an ANSI C-conforming const" >&5
+echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6
+if test "${ac_cv_c_const+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 ()
+{
+/* FIXME: Include the comments suggested by Paul. */
+#ifndef __cplusplus
+  /* Ultrix mips cc rejects this.  */
+  typedef int charset[2];
+  const charset x;
+  /* SunOS 4.1.1 cc rejects this.  */
+  char const *const *ccp;
+  char **p;
+  /* NEC SVR4.0.2 mips cc rejects this.  */
+  struct point {int x, y;};
+  static struct point const zero = {0,0};
+  /* AIX XL C 1.02.0.0 rejects this.
+     It does not let you subtract one const X* pointer from another in
+     an arm of an if-expression whose if-part is not a constant
+     expression */
+  const char *g = "string";
+  ccp = &g + (g ? g-g : 0);
+  /* HPUX 7.0 cc rejects these. */
+  ++ccp;
+  p = (char**) ccp;
+  ccp = (char const *const *) p;
+  { /* SCO 3.2v4 cc rejects this.  */
+    char *t;
+    char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+    *t++ = 0;
+  }
+  { /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+    int x[] = {25, 17};
+    const int *foo = &x[0];
+    ++foo;
+  }
+  { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+    typedef const int *iptr;
+    iptr p = 0;
+    ++p;
+  }
+  { /* AIX XL C 1.02.0.0 rejects this saying
+       "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+    struct s { int j; const int *ap[3]; };
+    struct s *b; b->j = 5;
+  }
+  { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+    const int foo = 10;
+  }
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_c_const=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_const=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5
+echo "${ECHO_T}$ac_cv_c_const" >&6
+if test $ac_cv_c_const = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define const
+_ACEOF
+
+fi
+
+if test "$ac_cv_header_machine_endian_h" = "no" ; then
+    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 !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
+ bogus endian macros
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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 ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+short ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; }
+short ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+short 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 { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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.  */
+int
+main ()
+{
+  /* Are we little or big endian?  From Harbison&Steele.  */
+  union
+  {
+    long l;
+    char c[sizeof (long)];
+  } u;
+  u.l = 1;
+  exit (u.c[sizeof (long) - 1] == 1);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&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 gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f 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
+
+fi
+echo "$as_me:$LINENO: checking for pid_t" >&5
+echo $ECHO_N "checking for pid_t... $ECHO_C" >&6
+if test "${ac_cv_type_pid_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
+int
+main ()
+{
+if ((pid_t *) 0)
+  return 0;
+if (sizeof (pid_t))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_type_pid_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_pid_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_pid_t" >&5
+echo "${ECHO_T}$ac_cv_type_pid_t" >&6
+if test $ac_cv_type_pid_t = yes; then
+  :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define pid_t int
+_ACEOF
+
+fi
+
+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
+int
+main ()
+{
+if ((size_t *) 0)
+  return 0;
+if (sizeof (size_t))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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
+_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
+int
+main ()
+{
+if ((short *) 0)
+  return 0;
+if (sizeof (short))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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
+
+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 "$ac_cv_type_short" = yes; then
+  # The cast to unsigned long 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.
+  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
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (short))) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (short))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (short))) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (short))) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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 conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f 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
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (short))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_short=$ac_lo;;
+'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (short), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (short), 77
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; } ;;
+esac
+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.  */
+$ac_includes_default
+long longval () { return (long) (sizeof (short)); }
+unsigned long ulongval () { return (long) (sizeof (short)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    exit (1);
+  if (((long) (sizeof (short))) < 0)
+    {
+      long i = longval ();
+      if (i != ((long) (sizeof (short))))
+       exit (1);
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long i = ulongval ();
+      if (i != ((long) (sizeof (short))))
+       exit (1);
+      fprintf (f, "%lu\n", i);
+    }
+  exit (ferror (f) || fclose (f) != 0);
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&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 )
+{ { echo "$as_me:$LINENO: error: cannot compute sizeof (short), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (short), 77
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+else
+  ac_cv_sizeof_short=0
+fi
+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
+int
+main ()
+{
+if ((int *) 0)
+  return 0;
+if (sizeof (int))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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
+
+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 "$ac_cv_type_int" = yes; then
+  # The cast to unsigned long 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.
+  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
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (int))) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (int))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (int))) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (int))) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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 conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f 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
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (int))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_int=$ac_lo;;
+'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (int), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (int), 77
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; } ;;
+esac
+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.  */
+$ac_includes_default
+long longval () { return (long) (sizeof (int)); }
+unsigned long ulongval () { return (long) (sizeof (int)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    exit (1);
+  if (((long) (sizeof (int))) < 0)
+    {
+      long i = longval ();
+      if (i != ((long) (sizeof (int))))
+       exit (1);
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long i = ulongval ();
+      if (i != ((long) (sizeof (int))))
+       exit (1);
+      fprintf (f, "%lu\n", i);
+    }
+  exit (ferror (f) || fclose (f) != 0);
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&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 )
+{ { echo "$as_me:$LINENO: error: cannot compute sizeof (int), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (int), 77
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+else
+  ac_cv_sizeof_int=0
+fi
+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
+int
+main ()
+{
+if ((long *) 0)
+  return 0;
+if (sizeof (long))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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
+
+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 "$ac_cv_type_long" = yes; then
+  # The cast to unsigned long 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.
+  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
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long))) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long))) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long))) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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 conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f 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
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_long=$ac_lo;;
+'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (long), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long), 77
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; } ;;
+esac
+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.  */
+$ac_includes_default
+long longval () { return (long) (sizeof (long)); }
+unsigned long ulongval () { return (long) (sizeof (long)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    exit (1);
+  if (((long) (sizeof (long))) < 0)
+    {
+      long i = longval ();
+      if (i != ((long) (sizeof (long))))
+       exit (1);
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long i = ulongval ();
+      if (i != ((long) (sizeof (long))))
+       exit (1);
+      fprintf (f, "%lu\n", i);
+    }
+  exit (ferror (f) || fclose (f) != 0);
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&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 )
+{ { echo "$as_me:$LINENO: error: cannot compute sizeof (long), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long), 77
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+else
+  ac_cv_sizeof_long=0
+fi
+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 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
+int
+main ()
+{
+if ((long long *) 0)
+  return 0;
+if (sizeof (long long))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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
+
+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 "$ac_cv_type_long_long" = yes; then
+  # The cast to unsigned long 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.
+  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
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long long))) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long long))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long long))) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long long))) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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 conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f 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
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long long))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_long_long=$ac_lo;;
+'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (long long), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long long), 77
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; } ;;
+esac
+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.  */
+$ac_includes_default
+long longval () { return (long) (sizeof (long long)); }
+unsigned long ulongval () { return (long) (sizeof (long long)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    exit (1);
+  if (((long) (sizeof (long long))) < 0)
+    {
+      long i = longval ();
+      if (i != ((long) (sizeof (long long))))
+       exit (1);
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long i = ulongval ();
+      if (i != ((long) (sizeof (long long))))
+       exit (1);
+      fprintf (f, "%lu\n", i);
+    }
+  exit (ferror (f) || fclose (f) != 0);
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&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 )
+{ { echo "$as_me:$LINENO: error: cannot compute sizeof (long long), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long long), 77
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+else
+  ac_cv_sizeof_long_long=0
+fi
+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
+
+
+
+
+echo "$as_me:$LINENO: checking the system's memory page size" >&5
+echo $ECHO_N "checking the system's memory page size... $ECHO_C" >&6
+pagesize="no"
+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 <stdio.h>
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+int main(void) {
+    FILE *fp = fopen("conftest.malloc", "w");
+
+    if (fp != NULL) {
+        fprintf(fp, "%d\n", getpagesize());
+        fclose(fp);
+    } else
+        exit(1);
+    exit(0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+if test -f "conftest.malloc" ; then
+    pagesize=`cat conftest.malloc`
+fi
+
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+if test "$pagesize" != "no" ; then
+    echo "$as_me:$LINENO: result: $pagesize" >&5
+echo "${ECHO_T}$pagesize" >&6
+else
+    if test "$ac_cv_sizeof_int" = "4" ; then
+        pagesize=4096
+    else
+        pagesize=8192
+    fi
+    echo "$as_me:$LINENO: result: $pagesize (guessing)" >&5
+echo "${ECHO_T}$pagesize (guessing)" >&6
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define MALLOC_PAGESIZE $pagesize
+_ACEOF
+
+
+
+echo "$as_me:$LINENO: checking for library containing socket" >&5
+echo $ECHO_N "checking for library containing socket... $ECHO_C" >&6
+if test "${ac_cv_search_socket+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+ac_cv_search_socket=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char socket ();
+int
+main ()
+{
+socket ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_socket="none required"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_socket" = no; then
+  for ac_lib in socket; do
+    LIBS="-l$ac_lib  $ac_func_search_save_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 gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char socket ();
+int
+main ()
+{
+socket ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_socket="-l$ac_lib"
+break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+  done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_socket" >&5
+echo "${ECHO_T}$ac_cv_search_socket" >&6
+if test "$ac_cv_search_socket" != no; then
+  test "$ac_cv_search_socket" = "none required" || LIBS="$ac_cv_search_socket $LIBS"
+
+else
+  { { echo "$as_me:$LINENO: error: You have no socket()! Aborting." >&5
+echo "$as_me: error: You have no socket()! Aborting." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+
+if test x"$SUN" = xyes; then
+       echo "$as_me:$LINENO: checking for library containing inet_ntoa" >&5
+echo $ECHO_N "checking for library containing inet_ntoa... $ECHO_C" >&6
+if test "${ac_cv_search_inet_ntoa+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+ac_cv_search_inet_ntoa=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char inet_ntoa ();
+int
+main ()
+{
+inet_ntoa ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_inet_ntoa="none required"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_inet_ntoa" = no; then
+  for ac_lib in nsl; do
+    LIBS="-l$ac_lib  $ac_func_search_save_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 gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char inet_ntoa ();
+int
+main ()
+{
+inet_ntoa ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_inet_ntoa="-l$ac_lib"
+break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+  done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_inet_ntoa" >&5
+echo "${ECHO_T}$ac_cv_search_inet_ntoa" >&6
+if test "$ac_cv_search_inet_ntoa" != no; then
+  test "$ac_cv_search_inet_ntoa" = "none required" || LIBS="$ac_cv_search_inet_ntoa $LIBS"
+
+else
+  { { echo "$as_me:$LINENO: error: libnsl not found! Aborting." >&5
+echo "$as_me: error: libnsl not found! Aborting." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+fi
+
+echo "$as_me:$LINENO: checking for struct sockaddr.sa_len" >&5
+echo $ECHO_N "checking for struct sockaddr.sa_len... $ECHO_C" >&6
+if test "${ac_cv_member_struct_sockaddr_sa_len+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>
+
+
+int
+main ()
+{
+static struct sockaddr ac_aggr;
+if (ac_aggr.sa_len)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_member_struct_sockaddr_sa_len=yes
+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.  */
+#include <sys/types.h>
+#include <sys/socket.h>
+
+
+int
+main ()
+{
+static struct sockaddr ac_aggr;
+if (sizeof ac_aggr.sa_len)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_member_struct_sockaddr_sa_len=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_member_struct_sockaddr_sa_len=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_member_struct_sockaddr_sa_len" >&5
+echo "${ECHO_T}$ac_cv_member_struct_sockaddr_sa_len" >&6
+if test $ac_cv_member_struct_sockaddr_sa_len = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define SOCKADDR_IN_HAS_LEN 1
+_ACEOF
+
+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>
+
+int
+main ()
+{
+if ((socklen_t *) 0)
+  return 0;
+if (sizeof (socklen_t))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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
+
+cat >>confdefs.h <<\_ACEOF
+#define socklen_t unsigned int
+_ACEOF
+
+fi
+
+
+# Check whether --enable-ipv6 or --disable-ipv6 was given.
+if test "${enable_ipv6+set}" = set; then
+  enableval="$enable_ipv6"
+  ipv6=$enableval
+else
+  ipv6=no
+fi;
+
+if test $ipv6 != yes; then
+       have_v6="no"
+else
+echo "$as_me:$LINENO: checking for core IPv6 support" >&5
+echo $ECHO_N "checking for core IPv6 support... $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.  */
+#define IN_AUTOCONF
+       #include <sys/types.h>
+       #include <sys/socket.h>
+       #include <netinet/in.h>
+int
+main ()
+{
+struct sockaddr_in6 s;
+         s.sin6_family = 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+       if test "$CYGWIN" = "yes"; then
+               echo "$as_me:$LINENO: result: no, Cygwin's IPv6 is incomplete" >&5
+echo "${ECHO_T}no, Cygwin's IPv6 is incomplete" >&6
+               have_v6=no
+       else
+               have_v6=yes
+
+cat >>confdefs.h <<\_ACEOF
+#define IPV6 1
+_ACEOF
+
+               echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+               echo "$as_me:$LINENO: checking for struct in6addr_any" >&5
+echo $ECHO_N "checking for struct in6addr_any... $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.  */
+#define IN_AUTOCONF
+                               #include <sys/types.h>
+                               #include <sys/socket.h>
+                               #include <netinet/in.h>
+int
+main ()
+{
+struct in6_addr a = in6addr_any;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 NO_IN6ADDR_ANY 1
+_ACEOF
+
+                               inet_misc=1
+
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+       fi
+
+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
+have_v6="no"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+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
+ac_cv_search_crypt=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char crypt ();
+int
+main ()
+{
+crypt ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_crypt="none required"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_crypt" = no; then
+  for ac_lib in crypt descrypt; do
+    LIBS="-l$ac_lib  $ac_func_search_save_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 gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char crypt ();
+int
+main ()
+{
+crypt ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_crypt="-l$ac_lib"
+break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+  done
+fi
+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
+if test "$ac_cv_search_crypt" != no; then
+  test "$ac_cv_search_crypt" = "none required" || LIBS="$ac_cv_search_crypt $LIBS"
+
+fi
+
+
+CRYPT_LIB=$ac_cv_search_crypt
+
+if test "$CRYPT_LIB" = "none required"; then
+       unset CRYPT_LIB
+elif test "$CRYPT_LIB" = no; then
+       unset CRYPT_LIB
+fi
+
+
+
+if test "$ac_cv_header_sys_wait_h" = yes -o "$ac_cv_header_wait_h" = yes; then
+       VICONF=viconf
+                       else
+       VICONF=""
+fi
+
+
+
+echo "$as_me:$LINENO: checking whether string.h and strings.h may both be included" >&5
+echo $ECHO_N "checking whether string.h and strings.h may both be included... $ECHO_C" >&6
+if test "${gcc_cv_header_string+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+#include <string.h>
+       #include <strings.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  gcc_cv_header_string=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gcc_cv_header_string=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+echo "$as_me:$LINENO: result: $gcc_cv_header_string" >&5
+echo "${ECHO_T}$gcc_cv_header_string" >&6
+
+if test "$gcc_cv_header_string" = "yes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STRING_WITH_STRINGS 1
+_ACEOF
+
+fi
+
+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 !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
+ bogus endian macros
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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 ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+short ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; }
+short ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+short 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 { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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.  */
+int
+main ()
+{
+  /* Are we little or big endian?  From Harbison&Steele.  */
+  union
+  {
+    long l;
+    char c[sizeof (long)];
+  } u;
+  u.l = 1;
+  exit (u.c[sizeof (long) - 1] == 1);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&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 gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f 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
+
+
+if test "${ac_cv_header_stdarg_h+set}" = set; then
+  echo "$as_me:$LINENO: checking for stdarg.h" >&5
+echo $ECHO_N "checking for stdarg.h... $ECHO_C" >&6
+if test "${ac_cv_header_stdarg_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdarg_h" >&5
+echo "${ECHO_T}$ac_cv_header_stdarg_h" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking stdarg.h usability" >&5
+echo $ECHO_N "checking stdarg.h 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 <stdarg.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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 stdarg.h presence" >&5
+echo $ECHO_N "checking stdarg.h 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 <stdarg.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&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; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_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: stdarg.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: stdarg.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: stdarg.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: stdarg.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: stdarg.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: stdarg.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: stdarg.h:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: stdarg.h:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: stdarg.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: stdarg.h: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: stdarg.h:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: stdarg.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: stdarg.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: stdarg.h: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: stdarg.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: stdarg.h: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the charybdis lists.  ##
+## ------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for stdarg.h" >&5
+echo $ECHO_N "checking for stdarg.h... $ECHO_C" >&6
+if test "${ac_cv_header_stdarg_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_header_stdarg_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdarg_h" >&5
+echo "${ECHO_T}$ac_cv_header_stdarg_h" >&6
+
+fi
+if test $ac_cv_header_stdarg_h = yes; then
+  :
+else
+  { { echo "$as_me:$LINENO: error: ** stdarg.h could not be found - ircd-ratbox will not compile without it **" >&5
+echo "$as_me: error: ** stdarg.h could not be found - ircd-ratbox will not compile without it **" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+
+
+
+if test "$ac_cv_c_compiler_gnu" = yes; then
+
+echo "$as_me:$LINENO: checking for strlcpy" >&5
+echo $ECHO_N "checking for strlcpy... $ECHO_C" >&6
+save_CFLAGS=$CFLAGS
+CFLAGS="$CFLAGS -Wimplicit -Werror"
+
+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>
+               #include <stdlib.h>
+int
+main ()
+{
+char *a = malloc(6);
+               strlcpy(a, "hello", 6);
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_STRLCPY 1
+_ACEOF
+
+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
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+
+echo "$as_me:$LINENO: checking for strlcat" >&5
+echo $ECHO_N "checking for strlcat... $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 <string.h>
+               #include <stdlib.h>
+int
+main ()
+{
+char *a = malloc(6);
+               a[0] = '\0';
+               strlcat(a, "hello", 6);
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_STRLCAT 1
+_ACEOF
+
+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
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+
+CFLAGS=$save_CFLAGS
+
+else
+
+
+
+
+for ac_func in strlcat strlcpy
+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 eval "test \"\${$as_ac_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 gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+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
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&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
+
+
+fi
+
+echo "$as_me:$LINENO: checking for u_int32_t" >&5
+echo $ECHO_N "checking for u_int32_t... $ECHO_C" >&6
+if test "${ac_cv_type_u_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
+int
+main ()
+{
+if ((u_int32_t *) 0)
+  return 0;
+if (sizeof (u_int32_t))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_type_u_int32_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_u_int32_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_u_int32_t" >&5
+echo "${ECHO_T}$ac_cv_type_u_int32_t" >&6
+if test $ac_cv_type_u_int32_t = yes; then
+  :
+else
+
+       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
+int
+main ()
+{
+if ((uint32_t *) 0)
+  return 0;
+if (sizeof (uint32_t))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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
+
+
+cat >>confdefs.h <<\_ACEOF
+#define u_int32_t uint32_t
+_ACEOF
+
+
+else
+
+               { echo "$as_me:$LINENO: WARNING: system has no u_int32_t or uint32_t, default to unsigned long int" >&5
+echo "$as_me: WARNING: system has no u_int32_t or uint32_t, default to unsigned long int" >&2;}
+
+cat >>confdefs.h <<\_ACEOF
+#define u_int32_t unsigned long int
+_ACEOF
+
+
+fi
+
+
+fi
+
+
+echo "$as_me:$LINENO: checking for u_int16_t" >&5
+echo $ECHO_N "checking for u_int16_t... $ECHO_C" >&6
+if test "${ac_cv_type_u_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
+int
+main ()
+{
+if ((u_int16_t *) 0)
+  return 0;
+if (sizeof (u_int16_t))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_type_u_int16_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_u_int16_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_u_int16_t" >&5
+echo "${ECHO_T}$ac_cv_type_u_int16_t" >&6
+if test $ac_cv_type_u_int16_t = yes; then
+  :
+else
+
+       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
+int
+main ()
+{
+if ((uint16_t *) 0)
+  return 0;
+if (sizeof (uint16_t))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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
+
+
+cat >>confdefs.h <<\_ACEOF
+#define u_int16_t uint16_t
+_ACEOF
+
+
+else
+
+               { echo "$as_me:$LINENO: WARNING: system has no u_int16_t or uint16_t, default to unsigned short int" >&5
+echo "$as_me: WARNING: system has no u_int16_t or uint16_t, default to unsigned short int" >&2;}
+
+cat >>confdefs.h <<\_ACEOF
+#define u_int16_t unsigned short int
+_ACEOF
+
+
+fi
+
+
+fi
+
+
+echo "$as_me:$LINENO: checking for in_port_t" >&5
+echo $ECHO_N "checking for in_port_t... $ECHO_C" >&6
+if test "${ac_cv_type_in_port_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 <netinet/in.h>
+
+int
+main ()
+{
+if ((in_port_t *) 0)
+  return 0;
+if (sizeof (in_port_t))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_type_in_port_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_in_port_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_in_port_t" >&5
+echo "${ECHO_T}$ac_cv_type_in_port_t" >&6
+if test $ac_cv_type_in_port_t = yes; then
+  :
+else
+
+cat >>confdefs.h <<\_ACEOF
+#define in_port_t u_int16_t
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking for sa_family_t" >&5
+echo $ECHO_N "checking for sa_family_t... $ECHO_C" >&6
+if test "${ac_cv_type_sa_family_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>
+
+int
+main ()
+{
+if ((sa_family_t *) 0)
+  return 0;
+if (sizeof (sa_family_t))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_type_sa_family_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_sa_family_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_sa_family_t" >&5
+echo "${ECHO_T}$ac_cv_type_sa_family_t" >&6
+if test $ac_cv_type_sa_family_t = yes; then
+  :
+else
+
+cat >>confdefs.h <<\_ACEOF
+#define sa_family_t u_int16_t
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking for uintptr_t" >&5
+echo $ECHO_N "checking for uintptr_t... $ECHO_C" >&6
+if test "${ac_cv_type_uintptr_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
+int
+main ()
+{
+if ((uintptr_t *) 0)
+  return 0;
+if (sizeof (uintptr_t))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_type_uintptr_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_uintptr_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_uintptr_t" >&5
+echo "${ECHO_T}$ac_cv_type_uintptr_t" >&6
+if test $ac_cv_type_uintptr_t = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_UINTPTR_T 1
+_ACEOF
+
+
+fi
+
+
+
+
+
+
+
+
+for ac_func in socketpair vsnprintf mmap gettimeofday strdup strndup
+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 eval "test \"\${$as_ac_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 gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+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
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&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
+
+
+# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
+# for constant arguments.  Useless!
+echo "$as_me:$LINENO: checking for working alloca.h" >&5
+echo $ECHO_N "checking for working alloca.h... $ECHO_C" >&6
+if test "${ac_cv_working_alloca_h+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 <alloca.h>
+int
+main ()
+{
+char *p = (char *) alloca (2 * sizeof (int));
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_working_alloca_h=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_working_alloca_h=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_working_alloca_h" >&5
+echo "${ECHO_T}$ac_cv_working_alloca_h" >&6
+if test $ac_cv_working_alloca_h = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ALLOCA_H 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for alloca" >&5
+echo $ECHO_N "checking for alloca... $ECHO_C" >&6
+if test "${ac_cv_func_alloca_works+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.  */
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#else
+# ifdef _MSC_VER
+#  include <malloc.h>
+#  define alloca _alloca
+# else
+#  if HAVE_ALLOCA_H
+#   include <alloca.h>
+#  else
+#   ifdef _AIX
+ #pragma alloca
+#   else
+#    ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+#    endif
+#   endif
+#  endif
+# endif
+#endif
+
+int
+main ()
+{
+char *p = (char *) alloca (1);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_func_alloca_works=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_alloca_works=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_alloca_works" >&5
+echo "${ECHO_T}$ac_cv_func_alloca_works" >&6
+
+if test $ac_cv_func_alloca_works = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ALLOCA 1
+_ACEOF
+
+else
+  # The SVR3 libPW and SVR4 libucb both contain incompatible functions
+# that cause trouble.  Some versions do not even contain alloca or
+# contain a buggy version.  If you still want to use their alloca,
+# use ar to extract alloca.o from them instead of compiling alloca.c.
+
+ALLOCA=alloca.$ac_objext
+
+cat >>confdefs.h <<\_ACEOF
+#define C_ALLOCA 1
+_ACEOF
+
+
+echo "$as_me:$LINENO: checking whether \`alloca.c' needs Cray hooks" >&5
+echo $ECHO_N "checking whether \`alloca.c' needs Cray hooks... $ECHO_C" >&6
+if test "${ac_cv_os_cray+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.  */
+#if defined(CRAY) && ! defined(CRAY2)
+webecray
+#else
+wenotbecray
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "webecray" >/dev/null 2>&1; then
+  ac_cv_os_cray=yes
+else
+  ac_cv_os_cray=no
+fi
+rm -f conftest*
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_os_cray" >&5
+echo "${ECHO_T}$ac_cv_os_cray" >&6
+if test $ac_cv_os_cray = yes; then
+  for ac_func in _getb67 GETB67 getb67; 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 eval "test \"\${$as_ac_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 gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+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
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define CRAY_STACKSEG_END $ac_func
+_ACEOF
+
+    break
+fi
+
+  done
+fi
+
+echo "$as_me:$LINENO: checking stack direction for C alloca" >&5
+echo $ECHO_N "checking stack direction for C alloca... $ECHO_C" >&6
+if test "${ac_cv_c_stack_direction+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_c_stack_direction=0
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+int
+find_stack_direction ()
+{
+  static char *addr = 0;
+  auto char dummy;
+  if (addr == 0)
+    {
+      addr = &dummy;
+      return find_stack_direction ();
+    }
+  else
+    return (&dummy > addr) ? 1 : -1;
+}
+
+int
+main ()
+{
+  exit (find_stack_direction () < 0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_c_stack_direction=1
+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_stack_direction=-1
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_stack_direction" >&5
+echo "${ECHO_T}$ac_cv_c_stack_direction" >&6
+
+cat >>confdefs.h <<_ACEOF
+#define STACK_DIRECTION $ac_cv_c_stack_direction
+_ACEOF
+
+
+fi
+
+
+
+echo "$as_me:$LINENO: checking for nanosleep" >&5
+echo $ECHO_N "checking for nanosleep... $ECHO_C" >&6
+if test "${ac_cv_func_nanosleep+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 nanosleep to an innocuous variant, in case <limits.h> declares nanosleep.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define nanosleep innocuous_nanosleep
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char nanosleep (); 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 nanosleep
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char nanosleep ();
+/* 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_nanosleep) || defined (__stub___nanosleep)
+choke me
+#else
+char (*f) () = nanosleep;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != nanosleep;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_func_nanosleep=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_nanosleep=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_nanosleep" >&5
+echo "${ECHO_T}$ac_cv_func_nanosleep" >&6
+if test $ac_cv_func_nanosleep = yes; then
+  :
+else
+  echo "$as_me:$LINENO: checking for nanosleep in -lrt" >&5
+echo $ECHO_N "checking for nanosleep in -lrt... $ECHO_C" >&6
+if test "${ac_cv_lib_rt_nanosleep+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lrt  $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 gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char nanosleep ();
+int
+main ()
+{
+nanosleep ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_rt_nanosleep=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_rt_nanosleep=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_rt_nanosleep" >&5
+echo "${ECHO_T}$ac_cv_lib_rt_nanosleep" >&6
+if test $ac_cv_lib_rt_nanosleep = yes; then
+  LIBS="${LIBS} -lrt"
+else
+  echo "$as_me:$LINENO: checking for nanosleep in -lposix4" >&5
+echo $ECHO_N "checking for nanosleep in -lposix4... $ECHO_C" >&6
+if test "${ac_cv_lib_posix4_nanosleep+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lposix4  $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 gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char nanosleep ();
+int
+main ()
+{
+nanosleep ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_posix4_nanosleep=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_posix4_nanosleep=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_posix4_nanosleep" >&5
+echo "${ECHO_T}$ac_cv_lib_posix4_nanosleep" >&6
+if test $ac_cv_lib_posix4_nanosleep = yes; then
+  LIBS="${LIBS} -lposix4"
+
+fi
+
+fi
+
+fi
+
+if test x$ac_cv_func_nanosleep = xno && test x$ac_cv_lib_posix4_nanosleep = xno  && test x$ac_cv_lib_rt_nanosleep = xno
+then
+         echo "$as_me:$LINENO: result: \"nanosleep not found..using select for delay\"" >&5
+echo "${ECHO_T}\"nanosleep not found..using select for delay\"" >&6
+else
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_NANOSLEEP 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for OpenSSL" >&5
+echo $ECHO_N "checking for OpenSSL... $ECHO_C" >&6
+# Check whether --enable-openssl or --disable-openssl was given.
+if test "${enable_openssl+set}" = set; then
+  enableval="$enable_openssl"
+  cf_enable_openssl=$enableval
+else
+  cf_enable_openssl="auto"
+fi;
+
+if test "$cf_enable_openssl" != "no" ; then
+       cf_openssl_basedir=""
+       if test "$cf_enable_openssl" != "auto" &&
+       test "$cf_enable_openssl" != "yes" ; then
+                               cf_openssl_basedir="`echo ${cf_enable_openssl} | sed 's/\/$//'`"
+       else
+                       for dirs in /usr/local/ssl /usr/pkg /usr/local \
+               /usr/local/openssl ; do
+                       if test -f "${dirs}/include/openssl/opensslv.h" ; then
+                               cf_openssl_basedir="${dirs}"
+                       break
+                       fi
+               done
+               unset dirs
+       fi
+               if test ! -z "$cf_openssl_basedir"; then
+               if test -f "${cf_openssl_basedir}/include/openssl/opensslv.h" ; then
+                       SSL_INCLUDES="-I${cf_openssl_basedir}/include"
+                       SSL_LIBS="-L${cf_openssl_basedir}/lib"
+               else
+                                               cf_openssl_basedir=""
+               fi
+       else
+                                                               if test -f "/usr/include/openssl/opensslv.h" ; then
+                       cf_openssl_basedir="/usr"
+               fi
+       fi
+
+                       if test ! -z "$cf_openssl_basedir"; then
+               echo "$as_me:$LINENO: result: $cf_openssl_basedir" >&5
+echo "${ECHO_T}$cf_openssl_basedir" >&6
+               cf_enable_openssl="yes"
+       else
+               echo "$as_me:$LINENO: result: not found. Specify a correct path?" >&5
+echo "${ECHO_T}not found. Specify a correct path?" >&6
+               cf_enable_openssl="no"
+       fi
+       unset cf_openssl_basedir
+else
+               echo "$as_me:$LINENO: result: disabled" >&5
+echo "${ECHO_T}disabled" >&6
+fi
+
+save_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS $SSL_INCLUDES"
+save_LIBS="$LIBS"
+LIBS="$LIBS $SSL_LIBS"
+if test "$cf_enable_openssl" != no; then
+               echo "$as_me:$LINENO: checking for OpenSSL 0.9.6 or above" >&5
+echo $ECHO_N "checking for OpenSSL 0.9.6 or above... $ECHO_C" >&6
+       if test "$cross_compiling" = yes; then
+  cf_openssl_version_ok=no
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <openssl/opensslv.h>
+               #include <stdlib.h>
+int
+main ()
+{
+if ( OPENSSL_VERSION_NUMBER >= 0x00906000)
+               exit(0); else exit(1);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  cf_openssl_version_ok=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 )
+cf_openssl_version_ok=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+       if test "$cf_openssl_version_ok" = yes; then
+               echo "$as_me:$LINENO: result: found" >&5
+echo "${ECHO_T}found" >&6
+
+                               ENCSPEED=encspeed
+
+
+                               CPPFLAGS="$CPPFLAGS $SSL_LIBS"
+
+echo "$as_me:$LINENO: checking for RSA_free in -lcrypto" >&5
+echo $ECHO_N "checking for RSA_free in -lcrypto... $ECHO_C" >&6
+if test "${ac_cv_lib_crypto_RSA_free+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 gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char RSA_free ();
+int
+main ()
+{
+RSA_free ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_crypto_RSA_free=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_crypto_RSA_free=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_crypto_RSA_free" >&5
+echo "${ECHO_T}$ac_cv_lib_crypto_RSA_free" >&6
+if test $ac_cv_lib_crypto_RSA_free = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBCRYPTO 1
+_ACEOF
+
+  LIBS="-lcrypto $LIBS"
+
+fi
+
+               SSL_LIBS="$SSL_LIBS -lcrypto"
+               SSL_SRCS_ENABLE='$(SSL_SRCS)'
+       else
+               echo "$as_me:$LINENO: result: no - OpenSSL support disabled" >&5
+echo "${ECHO_T}no - OpenSSL support disabled" >&6
+       fi
+fi
+
+CPPFLAGS="$save_CPPFLAGS"
+LIBS="$save_LIBS"
+
+
+
+
+
+# Check whether --with-zlib-path or --without-zlib-path was given.
+if test "${with_zlib_path+set}" = set; then
+  withval="$with_zlib_path"
+  LIBS="$LIBS -L$withval"
+fi;
+
+# Check whether --enable-zlib or --disable-zlib was given.
+if test "${enable_zlib+set}" = set; then
+  enableval="$enable_zlib"
+  zlib=$enableval
+else
+  zlib=yes
+fi;
+
+if test "$zlib" = yes; then
+
+if test "${ac_cv_header_zlib_h+set}" = set; then
+  echo "$as_me:$LINENO: checking for zlib.h" >&5
+echo $ECHO_N "checking for zlib.h... $ECHO_C" >&6
+if test "${ac_cv_header_zlib_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_zlib_h" >&5
+echo "${ECHO_T}$ac_cv_header_zlib_h" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking zlib.h usability" >&5
+echo $ECHO_N "checking zlib.h 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 <zlib.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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 zlib.h presence" >&5
+echo $ECHO_N "checking zlib.h 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 <zlib.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&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; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_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: zlib.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: zlib.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: zlib.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: zlib.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: zlib.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: zlib.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: zlib.h:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: zlib.h:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: zlib.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: zlib.h: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: zlib.h:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: zlib.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: zlib.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: zlib.h: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: zlib.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: zlib.h: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the charybdis lists.  ##
+## ------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for zlib.h" >&5
+echo $ECHO_N "checking for zlib.h... $ECHO_C" >&6
+if test "${ac_cv_header_zlib_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_header_zlib_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_zlib_h" >&5
+echo "${ECHO_T}$ac_cv_header_zlib_h" >&6
+
+fi
+if test $ac_cv_header_zlib_h = yes; then
+
+       echo "$as_me:$LINENO: checking for zlibVersion in -lz" >&5
+echo $ECHO_N "checking for zlibVersion in -lz... $ECHO_C" >&6
+if test "${ac_cv_lib_z_zlibVersion+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lz  $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 gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char zlibVersion ();
+int
+main ()
+{
+zlibVersion ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_z_zlibVersion=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_z_zlibVersion=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_z_zlibVersion" >&5
+echo "${ECHO_T}$ac_cv_lib_z_zlibVersion" >&6
+if test $ac_cv_lib_z_zlibVersion = yes; then
+
+               ZLIB_LD=-lz
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_LIBZ 1
+_ACEOF
+
+
+else
+  zlib=no
+fi
+
+
+else
+  zlib=no
+fi
+
+
+
+fi
+
+
+# Check whether --enable-poll or --disable-poll was given.
+if test "${enable_poll+set}" = set; then
+  enableval="$enable_poll"
+   if test $enableval = yes; then
+       SELECT_TYPE_EXPLICIT="poll"
+  else
+       use_poll=no
+  fi
+
+fi;
+
+# Check whether --enable-select or --disable-select was given.
+if test "${enable_select+set}" = set; then
+  enableval="$enable_select"
+   if test $enableval = yes; then
+       SELECT_TYPE_EXPLICIT="select"
+  else
+       use_select=no
+  fi
+
+fi;
+
+# Check whether --enable-kqueue or --disable-kqueue was given.
+if test "${enable_kqueue+set}" = set; then
+  enableval="$enable_kqueue"
+   if test $enableval = yes; then
+       SELECT_TYPE_EXPLICIT="kqueue"
+  else
+       use_kqueue=no
+  fi
+
+fi;
+
+# Check whether --enable-devpoll or --disable-devpoll was given.
+if test "${enable_devpoll+set}" = set; then
+  enableval="$enable_devpoll"
+   if test $enableval = yes; then
+       SELECT_TYPE_EXPLICIT="devpoll"
+
+
+for ac_header in sys/devpoll.h devpoll.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&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 { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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 { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&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; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_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;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the charybdis lists.  ##
+## ------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&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
+
+  else
+       use_devpoll=no;
+  fi
+
+fi;
+
+# Check whether --enable-epoll or --disable-epoll was given.
+if test "${enable_epoll+set}" = set; then
+  enableval="$enable_epoll"
+   if test $enableval = yes; then
+       SELECT_TYPE_EXPLICIT="epoll"
+  else
+       use_epoll=no
+  fi
+
+fi;
+
+
+echo "$as_me:$LINENO: checking whether to modify confdir" >&5
+echo $ECHO_N "checking whether to modify confdir... $ECHO_C" >&6
+
+# Check whether --with-confdir or --without-confdir was given.
+if test "${with_confdir+set}" = set; then
+  withval="$with_confdir"
+   confdir=`echo $withval | sed 's/\/$//'`
+                echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+  test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+  test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+  ac_define_dir=`eval echo $confdir`
+  ac_define_dir=`eval echo $ac_define_dir`
+  ETC_DIR="$ac_define_dir"
+
+
+cat >>confdefs.h <<_ACEOF
+#define ETC_DIR "$ac_define_dir"
+_ACEOF
+
+
+
+
+        confdir=`(
+            test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+            test "x$exec_prefix" = xNONE && exec_prefix="${prefix}"
+            eval echo \""$confdir"\"
+        )`
+
+
+else
+   confdir='${prefix}/etc'
+                echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+
+  test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+  test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+  ac_define_dir=`eval echo $confdir`
+  ac_define_dir=`eval echo $ac_define_dir`
+  ETC_DIR="$ac_define_dir"
+
+
+cat >>confdefs.h <<_ACEOF
+#define ETC_DIR "$ac_define_dir"
+_ACEOF
+
+
+
+
+        confdir=`(
+            test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+            test "x$exec_prefix" = xNONE && exec_prefix="${prefix}"
+            eval echo \""$confdir"\"
+        )`
+
+
+
+fi;
+
+
+echo "$as_me:$LINENO: checking whether to modify logdir" >&5
+echo $ECHO_N "checking whether to modify logdir... $ECHO_C" >&6
+
+# Check whether --with-logdir or --without-logdir was given.
+if test "${with_logdir+set}" = set; then
+  withval="$with_logdir"
+   logdir=`echo $withval | sed 's/\/$//'`
+                echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+  test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+  test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+  ac_define_dir=`eval echo $logdir`
+  ac_define_dir=`eval echo $ac_define_dir`
+  LOG_DIR="$ac_define_dir"
+
+
+cat >>confdefs.h <<_ACEOF
+#define LOG_DIR "$ac_define_dir"
+_ACEOF
+
+
+
+
+        logdir=`(
+            test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+            test "x$exec_prefix" = xNONE && exec_prefix="${prefix}"
+            eval echo \""$logdir"\"
+        )`
+
+
+else
+   logdir='${prefix}/logs'
+                echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+
+  test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+  test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+  ac_define_dir=`eval echo $logdir`
+  ac_define_dir=`eval echo $ac_define_dir`
+  LOG_DIR="$ac_define_dir"
+
+
+cat >>confdefs.h <<_ACEOF
+#define LOG_DIR "$ac_define_dir"
+_ACEOF
+
+
+
+
+        logdir=`(
+            test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+            test "x$exec_prefix" = xNONE && exec_prefix="${prefix}"
+            eval echo \""$logdir"\"
+        )`
+
+
+
+fi;
+
+
+echo "$as_me:$LINENO: checking whether to modify helpdir" >&5
+echo $ECHO_N "checking whether to modify helpdir... $ECHO_C" >&6
+
+# Check whether --with-helpdir or --without-helpdir was given.
+if test "${with_helpdir+set}" = set; then
+  withval="$with_helpdir"
+   helpdir=`echo $withval | sed 's/\/$//'`
+                echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+  test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+  test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+  ac_define_dir=`eval echo $helpdir`
+  ac_define_dir=`eval echo $ac_define_dir`
+  HELP_DIR="$ac_define_dir"
+
+
+cat >>confdefs.h <<_ACEOF
+#define HELP_DIR "$ac_define_dir"
+_ACEOF
+
+
+
+
+        helpdir=`(
+            test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+            test "x$exec_prefix" = xNONE && exec_prefix="${prefix}"
+            eval echo \""$helpdir"\"
+        )`
+
+
+else
+   helpdir='${prefix}/help'
+                echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+
+  test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+  test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+  ac_define_dir=`eval echo $helpdir`
+  ac_define_dir=`eval echo $ac_define_dir`
+  HELP_DIR="$ac_define_dir"
+
+
+cat >>confdefs.h <<_ACEOF
+#define HELP_DIR "$ac_define_dir"
+_ACEOF
+
+
+
+
+        helpdir=`(
+            test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+            test "x$exec_prefix" = xNONE && exec_prefix="${prefix}"
+            eval echo \""$helpdir"\"
+        )`
+
+
+
+fi;
+
+
+echo "$as_me:$LINENO: checking whether to modify moduledir" >&5
+echo $ECHO_N "checking whether to modify moduledir... $ECHO_C" >&6
+
+# Check whether --with-moduledir or --without-moduledir was given.
+if test "${with_moduledir+set}" = set; then
+  withval="$with_moduledir"
+   moduledir=`echo $withval | sed 's/\/$//'`
+                echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+  test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+  test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+  ac_define_dir=`eval echo $moduledir`
+  ac_define_dir=`eval echo $ac_define_dir`
+  MODULE_DIR="$ac_define_dir"
+
+
+cat >>confdefs.h <<_ACEOF
+#define MODULE_DIR "$ac_define_dir"
+_ACEOF
+
+
+
+
+        moduledir=`(
+            test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+            test "x$exec_prefix" = xNONE && exec_prefix="${prefix}"
+            eval echo \""$moduledir"\"
+        )`
+
+
+else
+   moduledir='${prefix}/modules'
+                echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+
+  test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+  test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+  ac_define_dir=`eval echo $moduledir`
+  ac_define_dir=`eval echo $ac_define_dir`
+  MODULE_DIR="$ac_define_dir"
+
+
+cat >>confdefs.h <<_ACEOF
+#define MODULE_DIR "$ac_define_dir"
+_ACEOF
+
+
+
+
+        moduledir=`(
+            test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+            test "x$exec_prefix" = xNONE && exec_prefix="${prefix}"
+            eval echo \""$moduledir"\"
+        )`
+
+
+
+fi;
+
+if test ! -z "$SELECT_TYPE_EXPLICIT"; then
+       SELECT_TYPE="$SELECT_TYPE_EXPLICIT";
+       echo "Forcing $SELECT_TYPE to be enabled"
+else
+
+if test ! "x$use_select" = "xno"; then
+
+for ac_func in select
+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 eval "test \"\${$as_ac_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 gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+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
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+ haveselect=yes
+else
+  haveselect=no
+fi
+done
+
+       if test "x$haveselect" = "xyes" ; then
+               SELECT_TYPE="select"
+       fi
+fi
+
+if test ! "x$use_poll" = "xno"; then
+
+for ac_func in poll
+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 eval "test \"\${$as_ac_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 gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+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
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+ havepoll=yes
+else
+  havepoll=no
+fi
+done
+
+       if test "x$havepoll" = "xyes" ; then
+               SELECT_TYPE="poll"
+       fi
+fi
+
+if test ! "x$use_devpoll" = "xno"; then
+       echo "$as_me:$LINENO: checking for /dev/poll" >&5
+echo $ECHO_N "checking for /dev/poll... $ECHO_C" >&6
+       if test -c "/dev/poll"; then
+               echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+
+for ac_header in devpoll.h sys/devpoll.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&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 { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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 { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&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; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_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;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the charybdis lists.  ##
+## ------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&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
+
+               SELECT_TYPE="devpoll"
+       else
+               echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+       fi
+fi
+
+if test ! "x$use_kqueue" = "xno"; then
+
+for ac_func in kevent
+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 eval "test \"\${$as_ac_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 gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+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
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+ havekqueue=yes
+else
+  havekqueue=no
+fi
+done
+
+       if test "x$havekqueue" = "xyes" ; then
+               SELECT_TYPE="kqueue"
+       fi
+fi
+
+if test ! "x$use_epoll" = "xno"; then
+
+for ac_func in epoll_ctl
+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 eval "test \"\${$as_ac_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 gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+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
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+ haveepoll=yes
+else
+  haveepoll=no
+fi
+done
+
+       if test "x$ac_cv_header_sys_epoll_h" = "xyes"; then
+               if test "x$haveepoll" = "xyes" ; then
+                       echo "$as_me:$LINENO: checking for epoll support in kernel" >&5
+echo $ECHO_N "checking for epoll support in kernel... $ECHO_C" >&6
+                       if test "$cross_compiling" = yes; then
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&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 <stdint.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/epoll.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+int
+main(int argc, char **argv)
+{
+        int epfd;
+
+        epfd = epoll_create(256);
+        exit (epfd == -1 ? 1 : 0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_EPOLL 1
+_ACEOF
+
+           SELECT_TYPE="epoll"
+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 )
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+               fi
+       fi
+
+haveepollsyscall=no
+
+if test "x$ac_cv_header_sys_epoll_h" = "xyes"; then
+       if test "x$haveepoll" = "xno" ; then
+                echo "$as_me:$LINENO: checking for epoll system call" >&5
+echo $ECHO_N "checking for epoll system call... $ECHO_C" >&6
+                if test "$cross_compiling" = yes; then
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&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 <stdint.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/epoll.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+int
+epoll_create(int size)
+{
+        return (syscall(__NR_epoll_create, size));
+}
+
+int
+main(int argc, char **argv)
+{
+        int epfd;
+
+        epfd = epoll_create(256);
+        exit (epfd == -1 ? 1 : 0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_EPOLL 1
+_ACEOF
+
+    SELECT_TYPE="epoll"
+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 )
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+       fi
+fi
+
+fi
+
+fi
+
+if test -z "$SELECT_TYPE"; then
+       { { echo "$as_me:$LINENO: error: Unable to find a usable IO interface" >&5
+echo "$as_me: error: Unable to find a usable IO interface" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+echo "Using $SELECT_TYPE for select loop."
+
+
+cat >>confdefs.h <<_ACEOF
+#define SELECT_TYPE "$SELECT_TYPE"
+_ACEOF
+
+
+
+
+
+# Check whether --enable-assert or --disable-assert was given.
+if test "${enable_assert+set}" = set; then
+  enableval="$enable_assert"
+  assert=$enableval
+else
+  assert=no
+fi;
+
+if test "$assert" = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define NDEBUG 1
+_ACEOF
+
+elif test "$assert" = soft; then
+
+cat >>confdefs.h <<\_ACEOF
+#define SOFT_ASSERT 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define NDEBUG 1
+_ACEOF
+
+elif test "$assert" = yes; then
+       assert = "hard";
+fi
+
+echo "$as_me:$LINENO: checking if you want IO Debugging hooks" >&5
+echo $ECHO_N "checking if you want IO Debugging hooks... $ECHO_C" >&6
+# Check whether --enable-iodebug or --disable-iodebug was given.
+if test "${enable_iodebug+set}" = set; then
+  enableval="$enable_iodebug"
+  iodebug=$enableval
+else
+  iodebug=no
+fi;
+
+if test "$iodebug" = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_IODEBUG_HOOKS 1
+_ACEOF
+
+       echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+       echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+
+echo "$as_me:$LINENO: checking if you want to do a profile build" >&5
+echo $ECHO_N "checking if you want to do a profile build... $ECHO_C" >&6
+# Check whether --enable-profile or --disable-profile was given.
+if test "${enable_profile+set}" = set; then
+  enableval="$enable_profile"
+  profile=$enableval
+else
+  profile=no
+fi;
+
+if test "$profile" = yes; then
+       if test "$ac_cv_c_compiler_gnu" = yes; then
+               IRC_CFLAGS="$IRC_CFLAGS -pg"
+               echo "$as_me:$LINENO: result: yes, adding -pg" >&5
+echo "${ECHO_T}yes, adding -pg" >&6
+
+cat >>confdefs.h <<\_ACEOF
+#define CHARYBDIS_PROFILE 1
+_ACEOF
+
+       else
+               echo "$as_me:$LINENO: result: no, profile builds only work with gcc" >&5
+echo "${ECHO_T}no, profile builds only work with gcc" >&6
+       fi
+else
+       echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+# Check whether --enable-balloc or --disable-balloc was given.
+if test "${enable_balloc+set}" = set; then
+  enableval="$enable_balloc"
+  balloc=$enableval
+else
+  balloc=yes
+fi;
+
+if test "$balloc" = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define NOBALLOC 1
+_ACEOF
+
+fi
+
+# Check whether --enable-ricer-hashing or --disable-ricer-hashing was given.
+if test "${enable_ricer_hashing+set}" = set; then
+  enableval="$enable_ricer_hashing"
+  ricer_hashing=$enableval
+else
+  ricer_hashing=no
+fi;
+
+FNVHASH_S=""
+
+if test "$ricer_hashing" = "yes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define RICER_HASHING 1
+_ACEOF
+
+       FNVHASH_S="fnvhash.s"
+fi
+
+
+
+# Check whether --enable-small-net or --disable-small-net was given.
+if test "${enable_small_net+set}" = set; then
+  enableval="$enable_small_net"
+  small_net=$enableval
+else
+  small_net=no
+fi;
+
+if test "$small_net" = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define NICKNAMEHISTORYLENGTH 1500
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define CHANNEL_HEAP_SIZE 256
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define BAN_HEAP_SIZE 128
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define CLIENT_HEAP_SIZE 256
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define LCLIENT_HEAP_SIZE 128
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define PCLIENT_HEAP_SIZE 32
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define USER_HEAP_SIZE 128
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define DNODE_HEAP_SIZE 256
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define TOPIC_HEAP_SIZE 256
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define LINEBUF_HEAP_SIZE 128
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define MEMBER_HEAP_SIZE 256
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define ND_HEAP_SIZE 128
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define CONFITEM_HEAP_SIZE 128
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define MONITOR_HEAP_SIZE 128
+_ACEOF
+
+else
+
+cat >>confdefs.h <<\_ACEOF
+#define NICKNAMEHISTORYLENGTH 15000
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define CHANNEL_HEAP_SIZE 8192
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define BAN_HEAP_SIZE 4096
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define CLIENT_HEAP_SIZE 8192
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define LCLIENT_HEAP_SIZE 1024
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define PCLIENT_HEAP_SIZE 256
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define USER_HEAP_SIZE 8192
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define DNODE_HEAP_SIZE 8192
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define TOPIC_HEAP_SIZE 4096
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define LINEBUF_HEAP_SIZE 2048
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define MEMBER_HEAP_SIZE 32768
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define ND_HEAP_SIZE 512
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define CONFITEM_HEAP_SIZE 256
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define MONITOR_HEAP_SIZE 1024
+_ACEOF
+
+fi
+
+
+# Check whether --with-nicklen or --without-nicklen was given.
+if test "${with_nicklen+set}" = set; then
+  withval="$with_nicklen"
+
+  if test $withval -ge 50; then
+       NICKLEN=50
+       { echo "$as_me:$LINENO: WARNING: NICKLEN has a hard limit of 50. Setting NICKLEN=50" >&5
+echo "$as_me: WARNING: NICKLEN has a hard limit of 50. Setting NICKLEN=50" >&2;}
+  else
+       NICKLEN="$withval"
+  fi
+
+else
+  NICKLEN=15
+fi;
+
+
+# Check whether --with-topiclen or --without-topiclen was given.
+if test "${with_topiclen+set}" = set; then
+  withval="$with_topiclen"
+
+ if test $withval -ge 390; then
+       TOPICLEN=390
+       { echo "$as_me:$LINENO: WARNING: TOPICLEN has a hard limit of 390. Setting TOPICLEN=390" >&5
+echo "$as_me: WARNING: TOPICLEN has a hard limit of 390. Setting TOPICLEN=390" >&2;}
+ else
+       TOPICLEN=$withval
+ fi
+
+else
+  TOPICLEN=390
+fi;
+
+
+# Check whether --with-maxclients or --without-maxclients was given.
+if test "${with_maxclients+set}" = set; then
+  withval="$with_maxclients"
+  MAX_CLIENTS="$withval"
+else
+  MAX_CLIENTS=3000
+fi;
+
+
+if test "$MAX_CLIENTS" = yes; then
+       MAX_CLIENTS=3000
+fi
+
+if test $MAX_CLIENTS -gt 65536; then
+       MAX_CLIENTS=65536
+       { echo "$as_me:$LINENO: WARNING: Max connections cannot be larger than 65536!" >&5
+echo "$as_me: WARNING: Max connections cannot be larger than 65536!" >&2;}
+fi
+
+
+cat >>confdefs.h <<_ACEOF
+#define TOPICLEN ${TOPICLEN}
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define NICKLEN (${NICKLEN}+1)
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define MAX_CLIENTS ${MAX_CLIENTS}
+_ACEOF
+
+
+# Check whether --enable-shared-modules or --disable-shared-modules was given.
+if test "${enable_shared_modules+set}" = set; then
+  enableval="$enable_shared_modules"
+  shared_modules=$enableval
+else
+  shared_modules="yes"
+fi;
+
+if test "$shared_modules" = yes; then
+
+       if test "$CYGWIN" = yes; then
+               { echo "$as_me:$LINENO: WARNING: disabling shared modules; Cygwin is at present unable to build them." >&5
+echo "$as_me: WARNING: disabling shared modules; Cygwin is at present unable to build them." >&2;}
+               shared_modules="no"
+       fi
+
+               if test "$CC" = tcc -a "$TenDRA" = "no"; then
+               { echo "$as_me:$LINENO: WARNING: disabling shared modules: Tiny C Compiler can't create PIC" >&5
+echo "$as_me: WARNING: disabling shared modules: Tiny C Compiler can't create PIC" >&2;}
+               shared_modules="no"
+       fi
+fi
+
+if test "$shared_modules" = yes; then
+       DYNLINK_C=dynlink.c
+
+for ac_header in dlfcn.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&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 { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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 { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&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; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_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;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the charybdis lists.  ##
+## ------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&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 for library containing shl_load" >&5
+echo $ECHO_N "checking for library containing shl_load... $ECHO_C" >&6
+if test "${ac_cv_search_shl_load+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+ac_cv_search_shl_load=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char shl_load ();
+int
+main ()
+{
+shl_load ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_shl_load="none required"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_shl_load" = no; then
+  for ac_lib in dld; do
+    LIBS="-l$ac_lib  $ac_func_search_save_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 gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char shl_load ();
+int
+main ()
+{
+shl_load ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_shl_load="-l$ac_lib"
+break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+  done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_shl_load" >&5
+echo "${ECHO_T}$ac_cv_search_shl_load" >&6
+if test "$ac_cv_search_shl_load" != no; then
+  test "$ac_cv_search_shl_load" = "none required" || LIBS="$ac_cv_search_shl_load $LIBS"
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SHL_LOAD 1
+_ACEOF
+
+         SUFFIX=".sl"
+         MOD_TARGET=hpux_shared
+         SEDOBJ="s/\.o/.sl/g"
+
+else
+
+                    echo "$as_me:$LINENO: checking for library containing dlopen" >&5
+echo $ECHO_N "checking for library containing dlopen... $ECHO_C" >&6
+if test "${ac_cv_search_dlopen+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+ac_cv_search_dlopen=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_dlopen="none required"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_dlopen" = no; then
+  for ac_lib in dl c_r; do
+    LIBS="-l$ac_lib  $ac_func_search_save_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 gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_dlopen="-l$ac_lib"
+break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+  done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_dlopen" >&5
+echo "${ECHO_T}$ac_cv_search_dlopen" >&6
+if test "$ac_cv_search_dlopen" != no; then
+  test "$ac_cv_search_dlopen" = "none required" || LIBS="$ac_cv_search_dlopen $LIBS"
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_DLOPEN 1
+_ACEOF
+
+           SUFFIX=".so"
+           MOD_TARGET=shared_modules
+           SEDOBJ="s/\.o/.so/g"
+           if test "$AppleGCC" = yes; then
+
+for ac_header in mach-o/dyld.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&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 { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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 { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&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; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_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;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the charybdis lists.  ##
+## ------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&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
+
+            fi
+           echo "$as_me:$LINENO: checking for dlsym" >&5
+echo $ECHO_N "checking for dlsym... $ECHO_C" >&6
+if test "${ac_cv_func_dlsym+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 dlsym to an innocuous variant, in case <limits.h> declares dlsym.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define dlsym innocuous_dlsym
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char dlsym (); 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 dlsym
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char dlsym ();
+/* 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_dlsym) || defined (__stub___dlsym)
+choke me
+#else
+char (*f) () = dlsym;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != dlsym;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_func_dlsym=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_dlsym=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_dlsym" >&5
+echo "${ECHO_T}$ac_cv_func_dlsym" >&6
+if test $ac_cv_func_dlsym = yes; then
+  :
+else
+
+             { echo "$as_me:$LINENO: WARNING: dlsym is not available, shared modules disabled" >&5
+echo "$as_me: WARNING: dlsym is not available, shared modules disabled" >&2;}
+             shared_modules=no
+
+fi
+
+
+for ac_func in dlfunc
+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 eval "test \"\${$as_ac_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 gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+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
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&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
+
+
+else
+
+           shared_modules=no
+
+fi
+
+
+fi
+
+fi
+
+
+cat >>confdefs.h <<_ACEOF
+#define SHARED_SUFFIX "$SUFFIX"
+_ACEOF
+
+
+if test "$shared_modules" = yes; then
+       # The GNU linker requires the -export-dynamic option to make
+       # all symbols visible in the dynamic symbol table.
+       hold_ldflags=$LDFLAGS
+       echo "$as_me:$LINENO: checking for the ld -export-dynamic flag" >&5
+echo $ECHO_N "checking for the ld -export-dynamic flag... $ECHO_C" >&6
+       LDFLAGS="${LDFLAGS} -Wl,-export-dynamic -Werror"
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+int i;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  found=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+found=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+       LDFLAGS=$hold_ldflags
+
+       if expr "`uname -s`" : ^IRIX >/dev/null 2>&1; then
+               found="no, IRIX ld uses -B,dynamic"
+               LDFLAGS="${LDFLAGS} -Wl,-B,dynamic"
+       fi
+
+       if expr "`uname -s`" : ^AIX >/dev/null 2>&1; then
+               found="no, AIX ld uses -G -brtl"
+               LDFLAGS="${LDFLAGS} -Wl,-G,-brtl"
+       fi
+
+       echo "$as_me:$LINENO: result: $found" >&5
+echo "${ECHO_T}$found" >&6
+
+       if test "$found" = yes; then
+               LDFLAGS="${LDFLAGS} -Wl,-export-dynamic"
+       fi
+
+       echo "$as_me:$LINENO: checking for compiler option to produce PIC" >&5
+echo $ECHO_N "checking for compiler option to produce PIC... $ECHO_C" >&6
+                               if test "$SGS" = "yes"; then
+               echo "$as_me:$LINENO: result: SVR4 SGS interfaces: -KPIC -DPIC -G" >&5
+echo "${ECHO_T}SVR4 SGS interfaces: -KPIC -DPIC -G" >&6
+               PICFLAGS="-KPIC -DPIC -G"
+       fi
+
+       if test "$AppleGCC" = "yes"; then
+               echo "$as_me:$LINENO: result: Darwin Mach-O bundles: -fno-common -bundle -flat_namespace -undefined suppress" >&5
+echo "${ECHO_T}Darwin Mach-O bundles: -fno-common -bundle -flat_namespace -undefined suppress" >&6
+               PICFLAGS="-fno-common -bundle -flat_namespace -undefined suppress"
+       fi
+                                                               if test "$HPUX" = "yes" -a "$CC" != gcc; then
+               echo "$as_me:$LINENO: result: HP-UX cc: +z -r -q -n" >&5
+echo "${ECHO_T}HP-UX cc: +z -r -q -n" >&6
+               PICFLAGS="+z -r -q -n -c"
+               echo "$as_me:$LINENO: checking if +ESfic is required on this platform" >&5
+echo $ECHO_N "checking if +ESfic is required on this platform... $ECHO_C" >&6
+
+               if expr "`$CC +ESfic 2>&1`" : ".*neither supported.*" >/dev/null; then
+                       echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+               else
+                       echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+                       PICFLAGS="$PICFLAGS +ESfic"
+               fi
+
+               LDFLAGS="${LDFLAGS} -Wl,-E"
+       fi
+       if test "$Tru" = yes -a "$CC" != gcc; then
+               echo "$as_me:$LINENO: result: Tru64: -shared -expect_unresolved '*'" >&5
+echo "${ECHO_T}Tru64: -shared -expect_unresolved '*'" >&6
+               PICFLAGS="-shared -expect_unresolved '*' "
+               LDFLAGS="-call_shared"
+       fi
+       if test -z "$PICFLAGS"; then
+               if test "$ac_cv_c_compiler_gnu" = "yes"; then
+                       echo "$as_me:$LINENO: result: gcc: -fPIC -DPIC -shared" >&5
+echo "${ECHO_T}gcc: -fPIC -DPIC -shared" >&6
+                       PICFLAGS="-fPIC -DPIC -shared"
+               else
+                       echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+                       shared_modules=no
+               fi
+       fi
+fi
+
+# This must be down here, or it will mess up checks like the ones
+# for -Wl,-export-dynamic
+# -- jilles
+# Check whether --enable-warnings or --disable-warnings was given.
+if test "${enable_warnings+set}" = set; then
+  enableval="$enable_warnings"
+
+IRC_CFLAGS="$IRC_CFLAGS -O0"
+CFLAGS="$IRC_CFLAGS"
+
+
+ echo "$as_me:$LINENO: checking GCC flag(s) -Wall" >&5
+echo $ECHO_N "checking GCC flag(s) -Wall... $ECHO_C" >&6
+ if test "${GCC-no}" = yes
+ then
+  if test "${charybdis_cv_c_gcc_w_all+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} -Wall -Werror"
+   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>
+#include <stdio.h>
+int main(void);
+
+int
+main ()
+{
+
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  charybdis_cv_c_gcc_w_all=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+charybdis_cv_c_gcc_w_all=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+   CFLAGS="${oldcflags}"
+fi
+
+  if test "x$charybdis_cv_c_gcc_w_all" = xyes; then
+   CWARNS="${CWARNS}-Wall "
+   echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+  else
+   charybdis_cv_c_gcc_w_all=''
+   echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+  fi
+ else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ fi
+
+
+ echo "$as_me:$LINENO: checking GCC flag(s) -Wpointer-arith" >&5
+echo $ECHO_N "checking GCC flag(s) -Wpointer-arith... $ECHO_C" >&6
+ if test "${GCC-no}" = yes
+ then
+  if test "${charybdis_cv_c_gcc_w_pointer_arith+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} -Wpointer-arith -Werror"
+   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>
+#include <stdio.h>
+int main(void);
+
+int
+main ()
+{
+
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  charybdis_cv_c_gcc_w_pointer_arith=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+charybdis_cv_c_gcc_w_pointer_arith=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+   CFLAGS="${oldcflags}"
+fi
+
+  if test "x$charybdis_cv_c_gcc_w_pointer_arith" = xyes; then
+   CWARNS="${CWARNS}-Wpointer-arith "
+   echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+  else
+   charybdis_cv_c_gcc_w_pointer_arith=''
+   echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+  fi
+ else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ fi
+
+
+ echo "$as_me:$LINENO: checking GCC flag(s) -Wimplicit -Wnested-externs" >&5
+echo $ECHO_N "checking GCC flag(s) -Wimplicit -Wnested-externs... $ECHO_C" >&6
+ if test "${GCC-no}" = yes
+ then
+  if test "${charybdis_cv_c_gcc_w_implicit+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} -Wimplicit -Wnested-externs -Werror"
+   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>
+#include <stdio.h>
+int main(void);
+
+int
+main ()
+{
+
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  charybdis_cv_c_gcc_w_implicit=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+charybdis_cv_c_gcc_w_implicit=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+   CFLAGS="${oldcflags}"
+fi
+
+  if test "x$charybdis_cv_c_gcc_w_implicit" = xyes; then
+   CWARNS="${CWARNS}-Wimplicit -Wnested-externs "
+   echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+  else
+   charybdis_cv_c_gcc_w_implicit=''
+   echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+  fi
+ else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ fi
+
+
+ echo "$as_me:$LINENO: checking GCC flag(s) -Wcast-align" >&5
+echo $ECHO_N "checking GCC flag(s) -Wcast-align... $ECHO_C" >&6
+ if test "${GCC-no}" = yes
+ then
+  if test "${charybdis_cv_c_gcc_w_cast_align+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} -Wcast-align -Werror"
+   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>
+#include <stdio.h>
+int main(void);
+
+int
+main ()
+{
+
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  charybdis_cv_c_gcc_w_cast_align=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+charybdis_cv_c_gcc_w_cast_align=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+   CFLAGS="${oldcflags}"
+fi
+
+  if test "x$charybdis_cv_c_gcc_w_cast_align" = xyes; then
+   CWARNS="${CWARNS}-Wcast-align "
+   echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+  else
+   charybdis_cv_c_gcc_w_cast_align=''
+   echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+  fi
+ else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ fi
+
+
+ echo "$as_me:$LINENO: checking GCC flag(s) -Wcast-qual" >&5
+echo $ECHO_N "checking GCC flag(s) -Wcast-qual... $ECHO_C" >&6
+ if test "${GCC-no}" = yes
+ then
+  if test "${charybdis_cv_c_gcc_w_cast_qual+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} -Wcast-qual -Werror"
+   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>
+#include <stdio.h>
+int main(void);
+
+int
+main ()
+{
+
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  charybdis_cv_c_gcc_w_cast_qual=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+charybdis_cv_c_gcc_w_cast_qual=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+   CFLAGS="${oldcflags}"
+fi
+
+  if test "x$charybdis_cv_c_gcc_w_cast_qual" = xyes; then
+   CWARNS="${CWARNS}-Wcast-qual "
+   echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+  else
+   charybdis_cv_c_gcc_w_cast_qual=''
+   echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+  fi
+ else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ fi
+
+
+ echo "$as_me:$LINENO: checking GCC flag(s) -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations" >&5
+echo $ECHO_N "checking GCC flag(s) -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations... $ECHO_C" >&6
+ if test "${GCC-no}" = yes
+ then
+  if test "${charybdis_cv_c_gcc_prototypes+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Werror"
+   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>
+#include <stdio.h>
+int main(void);
+
+int
+main ()
+{
+
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  charybdis_cv_c_gcc_prototypes=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+charybdis_cv_c_gcc_prototypes=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+   CFLAGS="${oldcflags}"
+fi
+
+  if test "x$charybdis_cv_c_gcc_prototypes" = xyes; then
+   CWARNS="${CWARNS}-Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations "
+   echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+  else
+   charybdis_cv_c_gcc_prototypes=''
+   echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+  fi
+ else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ fi
+
+
+ echo "$as_me:$LINENO: checking GCC flag(s) -Wparenthesis" >&5
+echo $ECHO_N "checking GCC flag(s) -Wparenthesis... $ECHO_C" >&6
+ if test "${GCC-no}" = yes
+ then
+  if test "${charybdis_cv_c_gcc_parenthesis+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} -Wparenthesis -Werror"
+   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>
+#include <stdio.h>
+int main(void);
+
+int
+main ()
+{
+
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  charybdis_cv_c_gcc_parenthesis=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+charybdis_cv_c_gcc_parenthesis=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+   CFLAGS="${oldcflags}"
+fi
+
+  if test "x$charybdis_cv_c_gcc_parenthesis" = xyes; then
+   CWARNS="${CWARNS}-Wparenthesis "
+   echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+  else
+   charybdis_cv_c_gcc_parenthesis=''
+   echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+  fi
+ else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ fi
+
+
+ echo "$as_me:$LINENO: checking GCC flag(s) -W -Wno-unused" >&5
+echo $ECHO_N "checking GCC flag(s) -W -Wno-unused... $ECHO_C" >&6
+ if test "${GCC-no}" = yes
+ then
+  if test "${charybdis_cv_c_gcc_w+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} -W -Wno-unused -Werror"
+   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>
+#include <stdio.h>
+int main(void);
+
+int
+main ()
+{
+
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  charybdis_cv_c_gcc_w=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+charybdis_cv_c_gcc_w=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+   CFLAGS="${oldcflags}"
+fi
+
+  if test "x$charybdis_cv_c_gcc_w" = xyes; then
+   CWARNS="${CWARNS}-W -Wno-unused "
+   echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+  else
+   charybdis_cv_c_gcc_w=''
+   echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+  fi
+ else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ fi
+
+
+ echo "$as_me:$LINENO: checking GCC flag(s) -Wextra" >&5
+echo $ECHO_N "checking GCC flag(s) -Wextra... $ECHO_C" >&6
+ if test "${GCC-no}" = yes
+ then
+  if test "${charybdis_cv_c_gcc_w_extra+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} -Wextra -Werror"
+   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>
+#include <stdio.h>
+int main(void);
+
+int
+main ()
+{
+
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  charybdis_cv_c_gcc_w_extra=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+charybdis_cv_c_gcc_w_extra=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+   CFLAGS="${oldcflags}"
+fi
+
+  if test "x$charybdis_cv_c_gcc_w_extra" = xyes; then
+   CWARNS="${CWARNS}-Wextra "
+   echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+  else
+   charybdis_cv_c_gcc_w_extra=''
+   echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+  fi
+ else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ fi
+
+
+ echo "$as_me:$LINENO: checking GCC flag(s) -Wshadow" >&5
+echo $ECHO_N "checking GCC flag(s) -Wshadow... $ECHO_C" >&6
+ if test "${GCC-no}" = yes
+ then
+  if test "${charybdis_cv_c_gcc_w_shadow+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} -Wshadow -Werror"
+   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>
+#include <stdio.h>
+int main(void);
+
+int
+main ()
+{
+
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  charybdis_cv_c_gcc_w_shadow=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+charybdis_cv_c_gcc_w_shadow=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+   CFLAGS="${oldcflags}"
+fi
+
+  if test "x$charybdis_cv_c_gcc_w_shadow" = xyes; then
+   CWARNS="${CWARNS}-Wshadow "
+   echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+  else
+   charybdis_cv_c_gcc_w_shadow=''
+   echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+  fi
+ else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ fi
+
+
+ echo "$as_me:$LINENO: checking GCC flag(s) -Wmissing-noreturn" >&5
+echo $ECHO_N "checking GCC flag(s) -Wmissing-noreturn... $ECHO_C" >&6
+ if test "${GCC-no}" = yes
+ then
+  if test "${charybdis_cv_c_gcc_w_missing_noreturn+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} -Wmissing-noreturn -Werror"
+   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>
+#include <stdio.h>
+int main(void);
+
+int
+main ()
+{
+
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  charybdis_cv_c_gcc_w_missing_noreturn=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+charybdis_cv_c_gcc_w_missing_noreturn=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+   CFLAGS="${oldcflags}"
+fi
+
+  if test "x$charybdis_cv_c_gcc_w_missing_noreturn" = xyes; then
+   CWARNS="${CWARNS}-Wmissing-noreturn "
+   echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+  else
+   charybdis_cv_c_gcc_w_missing_noreturn=''
+   echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+  fi
+ else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ fi
+
+
+ echo "$as_me:$LINENO: checking GCC flag(s) -Wundef" >&5
+echo $ECHO_N "checking GCC flag(s) -Wundef... $ECHO_C" >&6
+ if test "${GCC-no}" = yes
+ then
+  if test "${charybdis_cv_c_gcc_w_undef+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} -Wundef -Werror"
+   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>
+#include <stdio.h>
+int main(void);
+
+int
+main ()
+{
+
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  charybdis_cv_c_gcc_w_undef=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+charybdis_cv_c_gcc_w_undef=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+   CFLAGS="${oldcflags}"
+fi
+
+  if test "x$charybdis_cv_c_gcc_w_undef" = xyes; then
+   CWARNS="${CWARNS}-Wundef "
+   echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+  else
+   charybdis_cv_c_gcc_w_undef=''
+   echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+  fi
+ else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ fi
+
+
+ echo "$as_me:$LINENO: checking GCC flag(s) -Wpacked" >&5
+echo $ECHO_N "checking GCC flag(s) -Wpacked... $ECHO_C" >&6
+ if test "${GCC-no}" = yes
+ then
+  if test "${charybdis_cv_c_gcc_w_packed+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} -Wpacked -Werror"
+   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>
+#include <stdio.h>
+int main(void);
+
+int
+main ()
+{
+
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  charybdis_cv_c_gcc_w_packed=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+charybdis_cv_c_gcc_w_packed=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+   CFLAGS="${oldcflags}"
+fi
+
+  if test "x$charybdis_cv_c_gcc_w_packed" = xyes; then
+   CWARNS="${CWARNS}-Wpacked "
+   echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+  else
+   charybdis_cv_c_gcc_w_packed=''
+   echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+  fi
+ else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ fi
+
+
+ echo "$as_me:$LINENO: checking GCC flag(s) -Wnested-externs" >&5
+echo $ECHO_N "checking GCC flag(s) -Wnested-externs... $ECHO_C" >&6
+ if test "${GCC-no}" = yes
+ then
+  if test "${charybdis_cv_c_gcc_w_nested_externs+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} -Wnested-externs -Werror"
+   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>
+#include <stdio.h>
+int main(void);
+
+int
+main ()
+{
+
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  charybdis_cv_c_gcc_w_nested_externs=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+charybdis_cv_c_gcc_w_nested_externs=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+   CFLAGS="${oldcflags}"
+fi
+
+  if test "x$charybdis_cv_c_gcc_w_nested_externs" = xyes; then
+   CWARNS="${CWARNS}-Wnested-externs "
+   echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+  else
+   charybdis_cv_c_gcc_w_nested_externs=''
+   echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+  fi
+ else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ fi
+
+
+ echo "$as_me:$LINENO: checking GCC flag(s) -Wbad-function-cast" >&5
+echo $ECHO_N "checking GCC flag(s) -Wbad-function-cast... $ECHO_C" >&6
+ if test "${GCC-no}" = yes
+ then
+  if test "${charybdis_cv_c_gcc_w_bad_function_cast+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} -Wbad-function-cast -Werror"
+   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>
+#include <stdio.h>
+int main(void);
+
+int
+main ()
+{
+
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  charybdis_cv_c_gcc_w_bad_function_cast=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+charybdis_cv_c_gcc_w_bad_function_cast=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+   CFLAGS="${oldcflags}"
+fi
+
+  if test "x$charybdis_cv_c_gcc_w_bad_function_cast" = xyes; then
+   CWARNS="${CWARNS}-Wbad-function-cast "
+   echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+  else
+   charybdis_cv_c_gcc_w_bad_function_cast=''
+   echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+  fi
+ else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ fi
+
+
+ echo "$as_me:$LINENO: checking GCC flag(s) -Wunused-function -Wunused-label -Wunused-value -Wunused-variable" >&5
+echo $ECHO_N "checking GCC flag(s) -Wunused-function -Wunused-label -Wunused-value -Wunused-variable... $ECHO_C" >&6
+ if test "${GCC-no}" = yes
+ then
+  if test "${charybdis_cv_c_gcc_w_unused+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} -Wunused-function -Wunused-label -Wunused-value -Wunused-variable -Werror"
+   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>
+#include <stdio.h>
+int main(void);
+
+int
+main ()
+{
+
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  charybdis_cv_c_gcc_w_unused=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+charybdis_cv_c_gcc_w_unused=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+   CFLAGS="${oldcflags}"
+fi
+
+  if test "x$charybdis_cv_c_gcc_w_unused" = xyes; then
+   CWARNS="${CWARNS}-Wunused-function -Wunused-label -Wunused-value -Wunused-variable "
+   echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+  else
+   charybdis_cv_c_gcc_w_unused=''
+   echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+  fi
+ else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ fi
+
+
+ echo "$as_me:$LINENO: checking GCC flag(s) -Wredundant-decls" >&5
+echo $ECHO_N "checking GCC flag(s) -Wredundant-decls... $ECHO_C" >&6
+ if test "${GCC-no}" = yes
+ then
+  if test "${charybdis_cv_c_gcc_w_redundant_decls+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} -Wredundant-decls -Werror"
+   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>
+#include <stdio.h>
+int main(void);
+
+int
+main ()
+{
+
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  charybdis_cv_c_gcc_w_redundant_decls=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+charybdis_cv_c_gcc_w_redundant_decls=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+   CFLAGS="${oldcflags}"
+fi
+
+  if test "x$charybdis_cv_c_gcc_w_redundant_decls" = xyes; then
+   CWARNS="${CWARNS}-Wredundant-decls "
+   echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+  else
+   charybdis_cv_c_gcc_w_redundant_decls=''
+   echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+  fi
+ else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ fi
+
+
+ echo "$as_me:$LINENO: checking GCC flag(s) -Wfloat-equal" >&5
+echo $ECHO_N "checking GCC flag(s) -Wfloat-equal... $ECHO_C" >&6
+ if test "${GCC-no}" = yes
+ then
+  if test "${charybdis_cv_c_gcc_w_float_equal+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} -Wfloat-equal -Werror"
+   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>
+#include <stdio.h>
+int main(void);
+
+int
+main ()
+{
+
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  charybdis_cv_c_gcc_w_float_equal=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+charybdis_cv_c_gcc_w_float_equal=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+   CFLAGS="${oldcflags}"
+fi
+
+  if test "x$charybdis_cv_c_gcc_w_float_equal" = xyes; then
+   CWARNS="${CWARNS}-Wfloat-equal "
+   echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+  else
+   charybdis_cv_c_gcc_w_float_equal=''
+   echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+  fi
+ else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ fi
+
+
+ echo "$as_me:$LINENO: checking GCC flag(s) -Wformat=2" >&5
+echo $ECHO_N "checking GCC flag(s) -Wformat=2... $ECHO_C" >&6
+ if test "${GCC-no}" = yes
+ then
+  if test "${charybdis_cv_c_gcc_w_format+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} -Wformat=2 -Werror"
+   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>
+#include <stdio.h>
+int main(void);
+
+int
+main ()
+{
+
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  charybdis_cv_c_gcc_w_format=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+charybdis_cv_c_gcc_w_format=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+   CFLAGS="${oldcflags}"
+fi
+
+  if test "x$charybdis_cv_c_gcc_w_format" = xyes; then
+   CWARNS="${CWARNS}-Wformat=2 "
+   echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+  else
+   charybdis_cv_c_gcc_w_format=''
+   echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+  fi
+ else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ fi
+
+
+ echo "$as_me:$LINENO: checking GCC flag(s) -pedantic" >&5
+echo $ECHO_N "checking GCC flag(s) -pedantic... $ECHO_C" >&6
+ if test "${GCC-no}" = yes
+ then
+  if test "${charybdis_cv_c_gcc_pedantic+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} -pedantic -Werror"
+   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>
+#include <stdio.h>
+int main(void);
+
+int
+main ()
+{
+
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  charybdis_cv_c_gcc_pedantic=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+charybdis_cv_c_gcc_pedantic=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+   CFLAGS="${oldcflags}"
+fi
+
+  if test "x$charybdis_cv_c_gcc_pedantic" = xyes; then
+   CWARNS="${CWARNS}-pedantic "
+   echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+  else
+   charybdis_cv_c_gcc_pedantic=''
+   echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+  fi
+ else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ fi
+
+
+IRC_CFLAGS="$CFLAGS"
+
+fi;
+
+if test "$shared_modules" = no; then
+       DYNLINK_C=""
+       MOD_TARGET="libmodules.a"
+       MODULES_LIBS="../modules/libmodules.a"
+       SEDOBJ=""
+
+cat >>confdefs.h <<\_ACEOF
+#define STATIC_MODULES 1
+_ACEOF
+
+       { echo "$as_me:$LINENO: WARNING: shared module support has been disabled!" >&5
+echo "$as_me: WARNING: shared module support has been disabled!" >&2;}
+fi
+
+if test "$shared_modules" = yes; then
+
+       echo "$as_me:$LINENO: checking for nlist" >&5
+echo $ECHO_N "checking for nlist... $ECHO_C" >&6
+if test "${ac_cv_func_nlist+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 nlist to an innocuous variant, in case <limits.h> declares nlist.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define nlist innocuous_nlist
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char nlist (); 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 nlist
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char nlist ();
+/* 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_nlist) || defined (__stub___nlist)
+choke me
+#else
+char (*f) () = nlist;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != nlist;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_func_nlist=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_nlist=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_nlist" >&5
+echo "${ECHO_T}$ac_cv_func_nlist" >&6
+if test $ac_cv_func_nlist = yes; then
+  :
+else
+  echo "$as_me:$LINENO: checking for nlist in -ldl" >&5
+echo $ECHO_N "checking for nlist in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_nlist+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $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 gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char nlist ();
+int
+main ()
+{
+nlist ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_dl_nlist=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_nlist=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_nlist" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_nlist" >&6
+if test $ac_cv_lib_dl_nlist = yes; then
+  nlist_lib="-ldl"
+else
+  echo "$as_me:$LINENO: checking for nlist in -lelf" >&5
+echo $ECHO_N "checking for nlist in -lelf... $ECHO_C" >&6
+if test "${ac_cv_lib_elf_nlist+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lelf  $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 gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char nlist ();
+int
+main ()
+{
+nlist ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_elf_nlist=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_elf_nlist=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_elf_nlist" >&5
+echo "${ECHO_T}$ac_cv_lib_elf_nlist" >&6
+if test $ac_cv_lib_elf_nlist = yes; then
+  nlist_lib="-lelf"
+fi
+
+
+fi
+
+
+fi
+
+
+                               if test "${ac_cv_header_libelf_nlist_h+set}" = set; then
+  echo "$as_me:$LINENO: checking for libelf/nlist.h" >&5
+echo $ECHO_N "checking for libelf/nlist.h... $ECHO_C" >&6
+if test "${ac_cv_header_libelf_nlist_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_libelf_nlist_h" >&5
+echo "${ECHO_T}$ac_cv_header_libelf_nlist_h" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking libelf/nlist.h usability" >&5
+echo $ECHO_N "checking libelf/nlist.h 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 <libelf/nlist.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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 libelf/nlist.h presence" >&5
+echo $ECHO_N "checking libelf/nlist.h 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 <libelf/nlist.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&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; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_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: libelf/nlist.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: libelf/nlist.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: libelf/nlist.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: libelf/nlist.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: libelf/nlist.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: libelf/nlist.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: libelf/nlist.h:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: libelf/nlist.h:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: libelf/nlist.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: libelf/nlist.h: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: libelf/nlist.h:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: libelf/nlist.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: libelf/nlist.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: libelf/nlist.h: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: libelf/nlist.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: libelf/nlist.h: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the charybdis lists.  ##
+## ------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for libelf/nlist.h" >&5
+echo $ECHO_N "checking for libelf/nlist.h... $ECHO_C" >&6
+if test "${ac_cv_header_libelf_nlist_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_header_libelf_nlist_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_libelf_nlist_h" >&5
+echo "${ECHO_T}$ac_cv_header_libelf_nlist_h" >&6
+
+fi
+if test $ac_cv_header_libelf_nlist_h = yes; then
+   nlist_h="libelf/nlist.h"
+fi
+
+
+       if test "${ac_cv_header_elf_nlist_h+set}" = set; then
+  echo "$as_me:$LINENO: checking for elf/nlist.h" >&5
+echo $ECHO_N "checking for elf/nlist.h... $ECHO_C" >&6
+if test "${ac_cv_header_elf_nlist_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_elf_nlist_h" >&5
+echo "${ECHO_T}$ac_cv_header_elf_nlist_h" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking elf/nlist.h usability" >&5
+echo $ECHO_N "checking elf/nlist.h 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 <elf/nlist.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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 elf/nlist.h presence" >&5
+echo $ECHO_N "checking elf/nlist.h 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 <elf/nlist.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&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; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_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: elf/nlist.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: elf/nlist.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: elf/nlist.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: elf/nlist.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: elf/nlist.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: elf/nlist.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: elf/nlist.h:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: elf/nlist.h:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: elf/nlist.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: elf/nlist.h: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: elf/nlist.h:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: elf/nlist.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: elf/nlist.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: elf/nlist.h: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: elf/nlist.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: elf/nlist.h: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the charybdis lists.  ##
+## ------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for elf/nlist.h" >&5
+echo $ECHO_N "checking for elf/nlist.h... $ECHO_C" >&6
+if test "${ac_cv_header_elf_nlist_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_header_elf_nlist_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_elf_nlist_h" >&5
+echo "${ECHO_T}$ac_cv_header_elf_nlist_h" >&6
+
+fi
+if test $ac_cv_header_elf_nlist_h = yes; then
+   nlist_h="elf/nlist.h"
+fi
+
+
+       if test "${ac_cv_header_nlist_h+set}" = set; then
+  echo "$as_me:$LINENO: checking for nlist.h" >&5
+echo $ECHO_N "checking for nlist.h... $ECHO_C" >&6
+if test "${ac_cv_header_nlist_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_nlist_h" >&5
+echo "${ECHO_T}$ac_cv_header_nlist_h" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking nlist.h usability" >&5
+echo $ECHO_N "checking nlist.h 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 <nlist.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&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); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; 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 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 nlist.h presence" >&5
+echo $ECHO_N "checking nlist.h 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 <nlist.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&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; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_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: nlist.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: nlist.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: nlist.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: nlist.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: nlist.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: nlist.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: nlist.h:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: nlist.h:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: nlist.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: nlist.h: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: nlist.h:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: nlist.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: nlist.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: nlist.h: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: nlist.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: nlist.h: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the charybdis lists.  ##
+## ------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for nlist.h" >&5
+echo $ECHO_N "checking for nlist.h... $ECHO_C" >&6
+if test "${ac_cv_header_nlist_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_header_nlist_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_nlist_h" >&5
+echo "${ECHO_T}$ac_cv_header_nlist_h" >&6
+
+fi
+if test $ac_cv_header_nlist_h = yes; then
+   nlist_h="nlist.h"
+fi
+
+
+       if test x"$nlist_h" = "x"; then
+
+cat >>confdefs.h <<_ACEOF
+#define SYMBOL_PREFIX ""
+_ACEOF
+
+       else
+               echo "$as_me:$LINENO: checking for extra underscores prepended to symbol names" >&5
+echo $ECHO_N "checking for extra underscores prepended to symbol names... $ECHO_C" >&6
+               if test "${symbol_underscores+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+cat << EOF > conftest.c
+#include <$nlist_h>
+#include <stdio.h>
+#include <stdlib.h>
+void _modinit(void);
+int main(int argc, char *argv[]) {
+       int i;
+       struct nlist nl[5];
+
+       /* fill the names in this way, so it'll work almost everywhere */
+       nl[0].n_name = "_modinit";
+       nl[1].n_name = "__modinit";
+       nl[2].n_name = "___modinit";
+       nl[3].n_name = "____modinit";
+       nl[0].n_value = nl[1].n_value = nl[2].n_value = nl[3].n_value = nl[4].n_name = NULL;
+
+       if(argc < 2 || (nlist(argv[1], nl)) == -1) exit(-1);
+       for(i = 0; i < 4; i++) {
+               if(nl[i].n_value != NULL)
+               {
+                       int j;
+                       for(j = 0; j < i; j++)
+                               printf("_");
+                       exit(i);
+               }
+       }
+       exit(-1);
+}
+void _modinit(void) { return; }
+EOF
+               $CC $CPPFLAGS $IRC_CFLAGS -o conftest conftest.c $nlist_lib >/dev/null 2>&1
+               symbol_underscores=`./conftest conftest`
+               echo "$as_me:$LINENO: result: $symbol_underscores" >&5
+echo "${ECHO_T}$symbol_underscores" >&6
+               $RM -f conftest conftest.c
+
+fi
+
+
+cat >>confdefs.h <<_ACEOF
+#define SYMBOL_PREFIX "${symbol_underscores}"
+_ACEOF
+
+       fi
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test "$prefix" = "NONE"; then
+
+cat >>confdefs.h <<_ACEOF
+#define IRCD_PREFIX "$ac_default_prefix"
+_ACEOF
+
+
+else
+
+
+       prefix=`echo $prefix | sed 's/\/$//'`
+
+cat >>confdefs.h <<_ACEOF
+#define IRCD_PREFIX "$prefix"
+_ACEOF
+
+
+fi
+
+                                                                                                    ac_config_files="$ac_config_files Makefile libcharybdis/Makefile servlink/Makefile extensions/Makefile unsupported/Makefile src/Makefile modules/Makefile tools/Makefile doc/Makefile help/Makefile"
+
+
+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, don't put newlines in cache variables' values.
+# 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.
+{
+  (set) 2>&1 |
+    case `(ac_space=' '; set | grep ac_space) 2>&1` in
+    *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 \
+       "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+      ;;
+    esac;
+} |
+  sed '
+     t clear
+     : clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     /^ac_cv_env/!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 "updating cache $cache_file"
+    cat confcache >$cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  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}'
+
+# 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
+
+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_i=`echo "$ac_i" |
+        sed 's/\$U\././;s/\.o$//;s/\.obj$//'`
+  # 2. Add them.
+  ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext"
+  ac_ltlibobjs="$ac_ltlibobjs $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 Bourne compatible
+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+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+  set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+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
+  fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; 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'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# 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
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x$as_lineno_3"  = "x$as_lineno_2"  || {
+  # Find who we are.  Look in the path if we contain no path at all
+  # relative or not.
+  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
+
+       ;;
+  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_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5
+echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;}
+   { (exit 1); exit 1; }; }
+  fi
+  case $CONFIG_SHELL in
+  '')
+    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=.
+  for as_base in sh bash ksh sh5; do
+        case $as_dir in
+        /*)
+          if ("$as_dir/$as_base" -c '
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x$as_lineno_3"  = "x$as_lineno_2" ') 2>/dev/null; then
+            $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+            $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+            CONFIG_SHELL=$as_dir/$as_base
+            export CONFIG_SHELL
+            exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+          fi;;
+        esac
+       done
+done
+;;
+  esac
+
+  # 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 before each line; the second 'sed' does the real
+  # work.  The second script uses 'N' to pair each line-number line
+  # with the numbered line, 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
+  # second 'sed' script.  Blame Lee E. McMahon for sed's syntax.  :-)
+  sed '=' <$as_myself |
+    sed '
+      N
+      s,$,-,
+      : loop
+      s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+      t loop
+      s,-$,,
+      s,^['$as_cr_digits']*\n,,
+    ' >$as_me.lineno &&
+  chmod +x $as_me.lineno ||
+    { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5
+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 sensible to this).
+  . ./$as_me.lineno
+  # Exit status is that of the last command.
+  exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+  *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T='     ' ;;
+  *c*,*  ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+  *)       ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+  # We could just check for DJGPP; but this test a) works b) is more generic
+  # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+  if test -f conf$$.exe; then
+    # Don't use ln at all; we don't have any links
+    as_ln_s='cp -p'
+  else
+    as_ln_s='ln -s'
+  fi
+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$$.file
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# 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'"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS="  $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+exec 6>&1
+
+# Open the log real soon, to keep \$[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.  Logging --version etc. is OK.
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+} >&5
+cat >&5 <<_CSEOF
+
+This file was extended by charybdis $as_me 2.1.2, which was
+generated by GNU Autoconf 2.59.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+_CSEOF
+echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5
+echo >&5
+_ACEOF
+
+# Files that config.status was made for.
+if test -n "$ac_config_files"; then
+  echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_headers"; then
+  echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_links"; then
+  echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_commands"; then
+  echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS
+fi
+
+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, 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
+
+Report bugs to <bug-autoconf@gnu.org>."
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+charybdis config.status 2.1.2
+configured by $0, generated by GNU Autoconf 2.59,
+  with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2003 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+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
+    ;;
+  *) # This is not an option, so the user has probably given explicit
+     # arguments.
+     ac_option=$1
+     ac_need_defaults=false;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --vers* | -V )
+    echo "$ac_cs_version"; exit 0 ;;
+  --he | --h)
+    # Conflict between --help and --header
+    { { echo "$as_me:$LINENO: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&5
+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 0 ;;
+  --debug | --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;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&5
+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" ;;
+
+  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 $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+  exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+
+
+
+
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_config_target in $ac_config_targets
+do
+  case "$ac_config_target" in
+  # Handling of arguments.
+  "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+  "libcharybdis/Makefile" ) CONFIG_FILES="$CONFIG_FILES libcharybdis/Makefile" ;;
+  "servlink/Makefile" ) CONFIG_FILES="$CONFIG_FILES servlink/Makefile" ;;
+  "extensions/Makefile" ) CONFIG_FILES="$CONFIG_FILES extensions/Makefile" ;;
+  "unsupported/Makefile" ) CONFIG_FILES="$CONFIG_FILES unsupported/Makefile" ;;
+  "src/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
+  "modules/Makefile" ) CONFIG_FILES="$CONFIG_FILES modules/Makefile" ;;
+  "tools/Makefile" ) CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;;
+  "doc/Makefile" ) CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
+  "help/Makefile" ) CONFIG_FILES="$CONFIG_FILES help/Makefile" ;;
+  "include/setup.h" ) CONFIG_HEADERS="$CONFIG_HEADERS include/setup.h" ;;
+  *) { { 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
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason to put it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Create a temporary directory, and hook for its removal unless debugging.
+$debug ||
+{
+  trap 'exit_status=$?; rm -rf $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 -q "./confstatXXXXXX") 2>/dev/null` &&
+  test -n "$tmp" && test -d "$tmp"
+}  ||
+{
+  tmp=./confstat$$-$RANDOM
+  (umask 077 && mkdir $tmp)
+} ||
+{
+   echo "$me: cannot create a temporary directory in ." >&2
+   { (exit 1); exit 1; }
+}
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+
+#
+# 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
+  # Protect against being on the right side of a sed subst in config.status.
+  sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g;
+   s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF
+s,@SHELL@,$SHELL,;t t
+s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t
+s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t
+s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t
+s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t
+s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t
+s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t
+s,@exec_prefix@,$exec_prefix,;t t
+s,@prefix@,$prefix,;t t
+s,@program_transform_name@,$program_transform_name,;t t
+s,@bindir@,$bindir,;t t
+s,@sbindir@,$sbindir,;t t
+s,@libexecdir@,$libexecdir,;t t
+s,@datadir@,$datadir,;t t
+s,@sysconfdir@,$sysconfdir,;t t
+s,@sharedstatedir@,$sharedstatedir,;t t
+s,@localstatedir@,$localstatedir,;t t
+s,@libdir@,$libdir,;t t
+s,@includedir@,$includedir,;t t
+s,@oldincludedir@,$oldincludedir,;t t
+s,@infodir@,$infodir,;t t
+s,@mandir@,$mandir,;t t
+s,@build_alias@,$build_alias,;t t
+s,@host_alias@,$host_alias,;t t
+s,@target_alias@,$target_alias,;t t
+s,@DEFS@,$DEFS,;t t
+s,@ECHO_C@,$ECHO_C,;t t
+s,@ECHO_N@,$ECHO_N,;t t
+s,@ECHO_T@,$ECHO_T,;t t
+s,@LIBS@,$LIBS,;t t
+s,@CC@,$CC,;t t
+s,@CFLAGS@,$CFLAGS,;t t
+s,@LDFLAGS@,$LDFLAGS,;t t
+s,@CPPFLAGS@,$CPPFLAGS,;t t
+s,@ac_ct_CC@,$ac_ct_CC,;t t
+s,@EXEEXT@,$EXEEXT,;t t
+s,@OBJEXT@,$OBJEXT,;t t
+s,@MKDEP@,$MKDEP,;t t
+s,@MAKEDEPEND@,$MAKEDEPEND,;t t
+s,@STDOUT@,$STDOUT,;t t
+s,@CPP@,$CPP,;t t
+s,@EGREP@,$EGREP,;t t
+s,@SET_MAKE@,$SET_MAKE,;t t
+s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t
+s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t
+s,@INSTALL_DATA@,$INSTALL_DATA,;t t
+s,@RM@,$RM,;t t
+s,@CP@,$CP,;t t
+s,@MV@,$MV,;t t
+s,@LN@,$LN,;t t
+s,@SED@,$SED,;t t
+s,@AR@,$AR,;t t
+s,@LD@,$LD,;t t
+s,@RANLIB@,$RANLIB,;t t
+s,@TOUCH@,$TOUCH,;t t
+s,@YACC@,$YACC,;t t
+s,@LEX@,$LEX,;t t
+s,@LEXLIB@,$LEXLIB,;t t
+s,@LEX_OUTPUT_ROOT@,$LEX_OUTPUT_ROOT,;t t
+s,@CRYPT_LIB@,$CRYPT_LIB,;t t
+s,@VICONF@,$VICONF,;t t
+s,@ALLOCA@,$ALLOCA,;t t
+s,@ENCSPEED@,$ENCSPEED,;t t
+s,@ZLIB_LD@,$ZLIB_LD,;t t
+s,@ETC_DIR@,$ETC_DIR,;t t
+s,@confdir@,$confdir,;t t
+s,@LOG_DIR@,$LOG_DIR,;t t
+s,@logdir@,$logdir,;t t
+s,@HELP_DIR@,$HELP_DIR,;t t
+s,@helpdir@,$helpdir,;t t
+s,@MODULE_DIR@,$MODULE_DIR,;t t
+s,@moduledir@,$moduledir,;t t
+s,@SELECT_TYPE@,$SELECT_TYPE,;t t
+s,@FNVHASH_S@,$FNVHASH_S,;t t
+s,@MODULES_LIBS@,$MODULES_LIBS,;t t
+s,@MOD_TARGET@,$MOD_TARGET,;t t
+s,@SSL_SRCS_ENABLE@,$SSL_SRCS_ENABLE,;t t
+s,@SSL_INCLUDES@,$SSL_INCLUDES,;t t
+s,@SSL_LIBS@,$SSL_LIBS,;t t
+s,@PICFLAGS@,$PICFLAGS,;t t
+s,@IRC_CFLAGS@,$IRC_CFLAGS,;t t
+s,@SEDOBJ@,$SEDOBJ,;t t
+s,@LIBOBJS@,$LIBOBJS,;t t
+s,@LTLIBOBJS@,$LTLIBOBJS,;t t
+CEOF
+
+_ACEOF
+
+  cat >>$CONFIG_STATUS <<\_ACEOF
+  # Split the substitutions into bite-sized pieces for seds with
+  # small command number limits, like on Digital OSF/1 and HP-UX.
+  ac_max_sed_lines=48
+  ac_sed_frag=1 # Number of current file.
+  ac_beg=1 # First line for current file.
+  ac_end=$ac_max_sed_lines # Line after last line for current file.
+  ac_more_lines=:
+  ac_sed_cmds=
+  while $ac_more_lines; do
+    if test $ac_beg -gt 1; then
+      sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+    else
+      sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+    fi
+    if test ! -s $tmp/subs.frag; then
+      ac_more_lines=false
+    else
+      # The purpose of the label and of the branching condition is to
+      # speed up the sed processing (if there are no `@' at all, there
+      # is no need to browse any of the substitutions).
+      # These are the two extra sed commands mentioned above.
+      (echo ':t
+  /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
+      if test -z "$ac_sed_cmds"; then
+       ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
+      else
+       ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
+      fi
+      ac_sed_frag=`expr $ac_sed_frag + 1`
+      ac_beg=$ac_end
+      ac_end=`expr $ac_end + $ac_max_sed_lines`
+    fi
+  done
+  if test -z "$ac_sed_cmds"; then
+    ac_sed_cmds=cat
+  fi
+fi # test -n "$CONFIG_FILES"
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case $ac_file in
+  - | *:- | *:-:* ) # input from stdin
+       cat >$tmp/stdin
+       ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+       ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+  *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+       ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+  * )   ac_file_in=$ac_file.in ;;
+  esac
+
+  # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
+  ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$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'`
+  { if $as_mkdir_p; then
+    mkdir -p "$ac_dir"
+  else
+    as_dir="$ac_dir"
+    as_dirs=
+    while test ! -d "$as_dir"; do
+      as_dirs="$as_dir $as_dirs"
+      as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$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'`
+    done
+    test ! -n "$as_dirs" || mkdir $as_dirs
+  fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+   { (exit 1); exit 1; }; }; }
+
+  ac_builddir=.
+
+if test "$ac_dir" != .; then
+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+  # A "../" for each directory in $ac_dir_suffix.
+  ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+  ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+  .)  # No --srcdir option.  We are building in place.
+    ac_srcdir=.
+    if test -z "$ac_top_builddir"; then
+       ac_top_srcdir=.
+    else
+       ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+    fi ;;
+  [\\/]* | ?:[\\/]* )  # Absolute path.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir ;;
+  *) # Relative path.
+    ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+  case "$ac_dir" in
+  .) ac_abs_builddir=`pwd`;;
+  [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+  *) ac_abs_builddir=`pwd`/"$ac_dir";;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+  case ${ac_top_builddir}. in
+  .) ac_abs_top_builddir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+  *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+  case $ac_srcdir in
+  .) ac_abs_srcdir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+  *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+  case $ac_top_srcdir in
+  .) ac_abs_top_srcdir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+  *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+  esac;;
+esac
+
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_builddir$INSTALL ;;
+  esac
+
+  if test x"$ac_file" != x-; then
+    { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+    rm -f "$ac_file"
+  fi
+  # 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.  */
+  if test x"$ac_file" = x-; then
+    configure_input=
+  else
+    configure_input="$ac_file.  "
+  fi
+  configure_input=$configure_input"Generated from `echo $ac_file_in |
+                                    sed 's,.*/,,'` by configure."
+
+  # First look for the input files in the build tree, otherwise in the
+  # src tree.
+  ac_file_inputs=`IFS=:
+    for f in $ac_file_in; do
+      case $f in
+      -) echo $tmp/stdin ;;
+      [\\/$]*)
+        # Absolute (can't be DOS-style, as IFS=:)
+        test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+   { (exit 1); exit 1; }; }
+        echo "$f";;
+      *) # Relative
+        if test -f "$f"; then
+          # Build tree
+          echo "$f"
+        elif test -f "$srcdir/$f"; then
+          # Source tree
+          echo "$srcdir/$f"
+        else
+          # /dev/null tree
+          { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+   { (exit 1); exit 1; }; }
+        fi;;
+      esac
+    done` || { (exit 1); exit 1; }
+_ACEOF
+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,@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,@top_builddir@,$ac_top_builddir,;t t
+s,@abs_top_builddir@,$ac_abs_top_builddir,;t t
+s,@INSTALL@,$ac_INSTALL,;t t
+" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out
+  rm -f $tmp/stdin
+  if test x"$ac_file" != x-; then
+    mv $tmp/out $ac_file
+  else
+    cat $tmp/out
+    rm -f $tmp/out
+  fi
+
+done
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+#
+# CONFIG_HEADER section.
+#
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s,^\([   ]*\)#\([        ]*define[       ][      ]*\)'
+ac_dB='[        ].*$,\1#\2'
+ac_dC=' '
+ac_dD=',;t'
+# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_uA='s,^\([   ]*\)#\([        ]*\)undef\([    ][      ]*\)'
+ac_uB='$,\1#\2define\3'
+ac_uC=' '
+ac_uD=',;t'
+
+for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case $ac_file in
+  - | *:- | *:-:* ) # input from stdin
+       cat >$tmp/stdin
+       ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+       ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+  *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+       ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+  * )   ac_file_in=$ac_file.in ;;
+  esac
+
+  test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+
+  # First look for the input files in the build tree, otherwise in the
+  # src tree.
+  ac_file_inputs=`IFS=:
+    for f in $ac_file_in; do
+      case $f in
+      -) echo $tmp/stdin ;;
+      [\\/$]*)
+        # Absolute (can't be DOS-style, as IFS=:)
+        test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+   { (exit 1); exit 1; }; }
+        # Do quote $f, to prevent DOS paths from being IFS'd.
+        echo "$f";;
+      *) # Relative
+        if test -f "$f"; then
+          # Build tree
+          echo "$f"
+        elif test -f "$srcdir/$f"; then
+          # Source tree
+          echo "$srcdir/$f"
+        else
+          # /dev/null tree
+          { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+   { (exit 1); exit 1; }; }
+        fi;;
+      esac
+    done` || { (exit 1); exit 1; }
+  # Remove the trailing spaces.
+  sed 's/[      ]*$//' $ac_file_inputs >$tmp/in
+
+_ACEOF
+
+# Transform confdefs.h into two sed scripts, `conftest.defines' and
+# `conftest.undefs', that substitutes the proper values into
+# config.h.in to produce config.h.  The first handles `#define'
+# templates, and the second `#undef' templates.
+# And first: Protect against being on the right side of a sed subst in
+# config.status.  Protect against being in an unquoted here document
+# in config.status.
+rm -f conftest.defines conftest.undefs
+# Using a here document instead of a string reduces the quoting nightmare.
+# Putting comments in sed scripts is not portable.
+#
+# `end' is used to avoid that the second main sed command (meant for
+# 0-ary CPP macros) applies to n-ary macro definitions.
+# See the Autoconf documentation for `clear'.
+cat >confdef2sed.sed <<\_ACEOF
+s/[\\&,]/\\&/g
+s,[\\$`],\\&,g
+t clear
+: clear
+s,^[    ]*#[    ]*define[       ][      ]*\([^  (][^    (]*\)\(([^)]*)\)[       ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp
+t end
+s,^[    ]*#[    ]*define[       ][      ]*\([^  ][^     ]*\)[   ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp
+: end
+_ACEOF
+# If some macros were called several times there might be several times
+# the same #defines, which is useless.  Nevertheless, we may not want to
+# sort them, since we want the *last* AC-DEFINE to be honored.
+uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines
+sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs
+rm -f confdef2sed.sed
+
+# This sed command replaces #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.
+cat >>conftest.undefs <<\_ACEOF
+s,^[    ]*#[    ]*undef[        ][      ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */,
+_ACEOF
+
+# Break up conftest.defines because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo '  # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS
+echo '  if grep "^[     ]*#[    ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS
+echo '  # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS
+echo '  :' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.defines >/dev/null
+do
+  # Write a limited-size here document to $tmp/defines.sed.
+  echo '  cat >$tmp/defines.sed <<CEOF' >>$CONFIG_STATUS
+  # Speed up: don't consider the non `#define' lines.
+  echo '/^[     ]*#[    ]*define/!b' >>$CONFIG_STATUS
+  # Work around the forget-to-reset-the-flag bug.
+  echo 't clr' >>$CONFIG_STATUS
+  echo ': clr' >>$CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS
+  echo 'CEOF
+  sed -f $tmp/defines.sed $tmp/in >$tmp/out
+  rm -f $tmp/in
+  mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail
+  rm -f conftest.defines
+  mv conftest.tail conftest.defines
+done
+rm -f conftest.defines
+echo '  fi # grep' >>$CONFIG_STATUS
+echo >>$CONFIG_STATUS
+
+# Break up conftest.undefs because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo '  # Handle all the #undef templates' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.undefs >/dev/null
+do
+  # Write a limited-size here document to $tmp/undefs.sed.
+  echo '  cat >$tmp/undefs.sed <<CEOF' >>$CONFIG_STATUS
+  # Speed up: don't consider the non `#undef'
+  echo '/^[     ]*#[    ]*undef/!b' >>$CONFIG_STATUS
+  # Work around the forget-to-reset-the-flag bug.
+  echo 't clr' >>$CONFIG_STATUS
+  echo ': clr' >>$CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS
+  echo 'CEOF
+  sed -f $tmp/undefs.sed $tmp/in >$tmp/out
+  rm -f $tmp/in
+  mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail
+  rm -f conftest.undefs
+  mv conftest.tail conftest.undefs
+done
+rm -f conftest.undefs
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+  # 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.  */
+  if test x"$ac_file" = x-; then
+    echo "/* Generated by configure.  */" >$tmp/config.h
+  else
+    echo "/* $ac_file.  Generated by configure.  */" >$tmp/config.h
+  fi
+  cat $tmp/in >>$tmp/config.h
+  rm -f $tmp/in
+  if test x"$ac_file" != x-; then
+    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
+      ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$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'`
+      { if $as_mkdir_p; then
+    mkdir -p "$ac_dir"
+  else
+    as_dir="$ac_dir"
+    as_dirs=
+    while test ! -d "$as_dir"; do
+      as_dirs="$as_dir $as_dirs"
+      as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$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'`
+    done
+    test ! -n "$as_dirs" || mkdir $as_dirs
+  fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+   { (exit 1); exit 1; }; }; }
+
+      rm -f $ac_file
+      mv $tmp/config.h $ac_file
+    fi
+  else
+    cat $tmp/config.h
+    rm -f $tmp/config.h
+  fi
+done
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+{ (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
+
+
+if test "$cf_openssl_version_ok" = yes; then
+       openssl="yes"
+else
+       openssl="no"
+fi
+
+if test "$shared_modules" = yes; then
+       modules=shared
+else
+       modules=static
+fi
+
+echo "
+Configuration:
+       Install directory  : $prefix
+
+       Ziplinks           : $zlib
+       OpenSSL            : $openssl
+       Modules            : $modules
+       IPv6 support       : $have_v6
+       Socket Engine      : $SELECT_TYPE
+       Small network      : $small_net
+       Block allocator    : $balloc
+       ASM hashing code   : $ricer_hashing
+
+       Nickname length    : $NICKLEN
+       Topic length       : $TOPICLEN
+
+Use make to compile Charybdis, then make install to install it.
+"
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..9e6cf72
--- /dev/null
@@ -0,0 +1,1312 @@
+dnl $Id: configure.ac 2809 2006-12-05 13:18:19Z jilles $
+dnl Process this file with autoconf to produce a configure script.
+
+dnl TODO: clean up all the OpenSSL and shared module checking stuff;
+dnl the most major changes have already been made and it looks like
+dnl said functions need to be just about as complex as they already are.
+
+AC_PREREQ(2.57)
+
+dnl Sneaky way to get an Id tag into the configure script
+AC_COPYRIGHT([$Id: configure.ac 2809 2006-12-05 13:18:19Z jilles $])
+
+AC_INIT([charybdis],[2.1.2])
+
+AC_CONFIG_HEADER(include/setup.h)
+
+AC_PREFIX_DEFAULT($HOME/ircd)
+
+AC_GNU_SOURCE
+
+OLD_CFLAGS="$CFLAGS"
+dnl Checks for programs.
+AC_PROG_CC
+AC_LANG(C)
+
+dnl Make sure autoconf doesn't interfere with cflags -jmallett
+CFLAGS="$OLD_CFLAGS"
+
+dnl Check for various compilers. -jmallett
+dnl But if $CC turns out to be gcc, sure as hell it's, well, gcc. -joshk
+
+if test "$ac_cv_c_compiler_gnu" != yes; then
+
+SGS=no
+AC_MSG_CHECKING($CC -version for TenDRA or MIPSpro)
+case `$CC -version 2>&1` in
+*TenDRA*)
+       AC_MSG_RESULT([yes, TenDRA])
+       IRC_CFLAGS=""
+       CPPFLAGS="$CPPFLAGS -Ylonglong -Yansi -I/usr/include"
+       SGS=yes
+       TenDRA=yes
+;;
+*MIPSpro*)
+       AC_MSG_RESULT([yes, MIPSpro])
+       MIPSpro=yes
+       SGS=yes
+;;
+*)
+       AC_MSG_RESULT(no)
+       TenDRA=no
+       MIPSpro=no
+;;
+esac
+
+AC_MSG_CHECKING([$CC -V for Sun Workshop, Forte, HPUX or Tru64 cc])
+case `$CC -V 2>&1` in
+*Sun*WorkShop* | *Forte*Developer*)
+       AC_MSG_RESULT(Sun Workshop/Forte)
+       IRC_CFLAGS="-fast -xinline=dlinkAdd,dlinkAddBefore,dlinkAddTail,dlinkDelete,dlink_list_length,dlink_node,dlinkMoveList,_MyMalloc,_MyRealloc,_MyFree,_DupString"
+       SunWorkShop=yes
+       SGS=yes
+;;
+*Tru64*)
+       AC_MSG_RESULT(Tru64 cc)
+       IRC_CFLAGS="-O2"
+       CPPFLAGS="-I/usr/local/include"
+       Tru=yes
+;;
+*HP*ANSI*)
+       AC_MSG_RESULT(HPUX cc)
+       HPUX=yes
+       IRC_CFLAGS="+e"
+;;
+*)
+       AC_MSG_RESULT(no)
+;;
+esac
+
+fi
+
+AC_MSG_CHECKING([uname -s for Cygwin, Solaris, AIX or HPUX])
+OSNAME=`uname -s`
+case "$OSNAME" in
+        HP-UX*)
+       dnl only do this if we haven't already detected the newer one
+       dnl and we're not already using gcc
+       
+               if test "$HPUX" != yes -a "$ac_cv_c_compiler_gnu" = no; then
+                       AC_MSG_RESULT(assuming old HPUX with its own cc)  
+                       IRC_CFLAGS="$IRC_CFLAGS +e"
+                       HPUX=yes
+               else
+                       AC_MSG_RESULT(already using newer HPUX)
+               fi
+       ;;
+       CYGWIN*)
+               AC_MSG_RESULT(Cygwin)
+               CYGWIN=yes
+       ;;
+       SunOS*)
+               AC_MSG_RESULT(SunOS or Solaris)
+               AC_DEFINE(__EXTENSIONS__, 1, [This is needed to use strtok_r on Solaris.])
+               SUN=yes
+       ;;
+       AIX*)
+               AC_MSG_RESULT(AIX - Sorry you poor bastard..really we are)
+               IRC_CFLAGS="$IRC_CFLAGS -Wl,-brtl -Wl,-G"
+       ;;
+       *)
+               AC_MSG_RESULT(no)
+       ;;
+esac
+
+if test "$ac_cv_c_compiler_gnu" = yes; then
+       AC_MSG_CHECKING(if $CC is Apple GCC)
+
+       case `$CC -v 2>&1 | tail -n 1` in
+       *Apple*)
+               AC_MSG_RESULT(yes)
+               AppleGCC=yes
+       ;;
+       *)
+               AC_MSG_RESULT(no)
+               AppleGCC=no
+       ;;
+       esac
+
+       IRC_CFLAGS="$IRC_CFLAGS -O0 -Wall"
+fi
+
+dnl If we support -g, use it!
+if test "$ac_cv_prog_cc_g" = yes; then
+       dnl Tru64 needs -g3 for -O2
+       if test "$Tru" = yes; then
+               IRC_CFLAGS="$IRC_CFLAGS -g3"
+       else
+               IRC_CFLAGS="$IRC_CFLAGS -g"
+       fi
+fi
+
+dnl SVR4 SGS based on what we know about the compiler -jmallett
+AC_MSG_CHECKING(if $CC supports the SVR4 SGS interfaces)
+if test "$SGS" = "yes"; then
+       AC_MSG_RESULT(yes)
+else
+       AC_MSG_RESULT(no)
+fi
+
+dnl We prefer gcc -MM because it's a lot less bloated
+AC_PATH_PROG(MKDEP, mkdep)
+AC_PATH_PROG(MAKEDEPEND, makedepend)
+
+AC_MSG_CHECKING(how to generate dependency info)
+
+STDOUT="> .depend"
+
+if test "$ac_cv_c_compiler_gnu" = yes; then
+       AC_MSG_RESULT(gcc -MM)
+       MKDEP="$CC -MM"
+elif test ! -z "$MKDEP"; then
+       AC_MSG_RESULT(mkdep)
+
+       dnl Tru64's mkdep is very loud
+       if test -z "$Tru"; then
+               STDOUT=""
+       else
+               STDOUT=" 2> /dev/null"
+       fi
+elif test "$SunWorkShop" = yes; then
+       AC_MSG_RESULT($CC -xM)
+       MKDEP="$CC -xM"
+       STDOUT="> .depend 2> /dev/null"
+elif test ! -z "$MAKEDEPEND"; then
+       AC_MSG_RESULT(makedepend)
+       MKDEP="$MAKEDEPEND -f-"
+else
+       AC_MSG_RESULT([nothing suitable.. forget it!])
+       MKDEP=":"
+fi
+
+AC_SUBST(MKDEP)
+AC_SUBST(STDOUT)
+
+dnl check for /dev/null so we can use it to hold evil fd's
+AC_MSG_CHECKING([for /dev/null])
+if test -c /dev/null ; then
+       AC_DEFINE(PATH_DEVNULL, "/dev/null", [Path to /dev/null])
+       AC_MSG_RESULT(yes)
+else
+       AC_DEFINE(PATH_DEVNULL, "devnull.log", [Path to /dev/null])
+       AC_MSG_RESULT(no - using devnull.log)
+fi
+
+dnl jdc -- If CFLAGS is defined, best use it everywhere...
+dnl NOTE: jv says it must be added to the *END*, because things like
+dnl "gcc -O9 -O2" will result in -O2 getting preference.  How stupid.
+if test ! -z "$CFLAGS"; then
+       IRC_CFLAGS="$IRC_CFLAGS $CFLAGS"
+fi
+
+AC_ISC_POSIX
+AC_C_INLINE
+AC_PROG_GCC_TRADITIONAL
+AC_PROG_MAKE_SET
+AC_PROG_INSTALL
+AC_PATH_PROG(RM, rm)
+AC_PATH_PROG(CP, cp)
+AC_PATH_PROG(MV, mv)
+AC_PATH_PROG(LN, ln)
+AC_PATH_PROG(SED, sed)
+AC_PATH_PROG(AR, ar)
+AC_PATH_PROG(LD, ld)
+AC_PATH_PROG(RANLIB, ranlib)
+AC_PATH_PROG(TOUCH, touch)
+
+AC_PROG_YACC
+
+dnl AC_PROG_YACC defaults to yacc unconditionally if nothing can be found
+if test "$YACC" = "yacc" -a -z "`which $YACC 2>/dev/null`"; then
+       AC_MSG_ERROR([could not locate a suitable parser generator; install bison, yacc, or byacc])
+fi
+
+AC_PROG_LEX
+
+if test "$LEX" = ":"; then
+       AC_MSG_ERROR([could not locate a suitable lexical generator, install flex or lex.])
+fi
+
+dnl use directory structure of cached as default (hack)
+if test "$libexecdir" = '${exec_prefix}/libexec' &&
+   test "$localstatedir" = '${prefix}/var'; then
+       libexecdir='${bindir}'
+       localstatedir='${prefix}'
+fi
+
+dnl Checks for header files.
+AC_HEADER_STDC
+
+AC_CHECK_HEADERS([crypt.h sys/resource.h sys/param.h errno.h sys/syslog.h stddef.h sys/wait.h wait.h sys/epoll.h sys/uio.h machine/endian.h])
+
+dnl Stuff that the memory manager (imalloc) depends on
+dnl ==================================================
+
+AC_C_CONST
+if test "$ac_cv_header_machine_endian_h" = "no" ; then
+    AC_C_BIGENDIAN
+fi
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+AC_CHECK_SIZEOF(short)
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(long)
+AC_CHECK_SIZEOF(long long)
+
+dnl Memory manager
+dnl ==============
+
+AC_MSG_CHECKING([the system's memory page size])
+pagesize="no"
+AC_TRY_RUN([
+#include <stdio.h>
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+int main(void) {
+    FILE *fp = fopen("conftest.malloc", "w");
+
+    if (fp != NULL) {
+        fprintf(fp, "%d\n", getpagesize());
+        fclose(fp);
+    } else
+        exit(1);
+    exit(0);
+}],[
+if test -f "conftest.malloc" ; then
+    pagesize=`cat conftest.malloc`
+fi
+])
+if test "$pagesize" != "no" ; then
+    AC_MSG_RESULT($pagesize)
+else
+    if test "$ac_cv_sizeof_int" = "4" ; then
+        pagesize=4096
+    else
+        pagesize=8192
+    fi
+    AC_MSG_RESULT([$pagesize (guessing)])
+fi
+AC_DEFINE_UNQUOTED(MALLOC_PAGESIZE, $pagesize,
+    [the system's memory page size])
+
+dnl Networking Functions
+dnl ====================
+
+AC_SEARCH_LIBS(socket, socket, , [AC_MSG_ERROR([You have no socket()! Aborting.])])
+
+dnl SunOS/Solaris required libnsl for inet_ntoa()
+if test x"$SUN" = xyes; then
+       AC_SEARCH_LIBS(inet_ntoa, nsl,, [AC_MSG_ERROR([libnsl not found! Aborting.])])
+fi
+
+AC_CHECK_MEMBER([struct sockaddr.sa_len], [AC_DEFINE(SOCKADDR_IN_HAS_LEN, 1, [Define to 1 if sockaddr has a 'sa_len'
+member.])],,[[#include <sys/types.h>
+#include <sys/socket.h>
+]])
+
+AC_CHECK_TYPE(socklen_t, ,
+[AC_DEFINE([socklen_t], [unsigned int],
+[If we don't have a real socklen_t, unsigned int is good enough.])],
+[#include <sys/types.h>
+#include <sys/socket.h>])
+
+AC_ARG_ENABLE(ipv6,
+AC_HELP_STRING([--enable-ipv6],[Enable IPv6 support]),[ipv6=$enableval],[ipv6=no])
+
+if test $ipv6 != yes; then
+       have_v6="no"
+else
+AC_MSG_CHECKING([for core IPv6 support])
+
+AC_COMPILE_IFELSE(
+[AC_LANG_PROGRAM(
+       [[#define IN_AUTOCONF
+       #include <sys/types.h>
+       #include <sys/socket.h>
+       #include <netinet/in.h>]],
+       [[struct sockaddr_in6 s; 
+         s.sin6_family = 0;]]
+       )],
+[
+       if test "$CYGWIN" = "yes"; then
+               AC_MSG_RESULT([no, Cygwin's IPv6 is incomplete])
+               have_v6=no
+       else
+               have_v6=yes
+               AC_DEFINE(IPV6, 1, [Define if IPv6 support is present and available.])
+               AC_MSG_RESULT(yes)
+               AC_MSG_CHECKING([for struct in6addr_any])
+               AC_COMPILE_IFELSE(
+                       [AC_LANG_PROGRAM(
+                               [[#define IN_AUTOCONF
+                               #include <sys/types.h>
+                               #include <sys/socket.h>
+                               #include <netinet/in.h>]],
+                               [[struct in6_addr a = in6addr_any;]]
+                       )],
+                       [AC_MSG_RESULT(yes)],
+                       [
+                               AC_MSG_RESULT(no)
+                               AC_DEFINE(NO_IN6ADDR_ANY, 1, [Define to 1 if your system has no in6addr_any.])
+                               inet_misc=1
+                       ]
+               )
+       fi
+],
+[AC_MSG_RESULT(no)
+have_v6="no"])
+fi
+
+AC_SEARCH_LIBS(crypt, [crypt descrypt],,)
+
+CRYPT_LIB=$ac_cv_search_crypt
+
+if test "$CRYPT_LIB" = "none required"; then
+       unset CRYPT_LIB
+elif test "$CRYPT_LIB" = no; then
+       unset CRYPT_LIB
+fi
+
+AC_SUBST(CRYPT_LIB)
+
+if test "$ac_cv_header_sys_wait_h" = yes -o "$ac_cv_header_wait_h" = yes; then
+       VICONF=viconf
+       dnl We need one of the above to build viconf. Just a sanity check,
+       dnl we don't want to stop people from building the rest of ircd
+       dnl just because they can't build viconf.
+else
+       VICONF=""
+fi
+
+AC_SUBST(VICONF)
+
+dnl See whether we can include both string.h and strings.h.
+AC_CACHE_CHECK([whether string.h and strings.h may both be included],
+gcc_cv_header_string,
+[
+       AC_COMPILE_IFELSE(
+       [#include <string.h>
+       #include <strings.h>], 
+       [gcc_cv_header_string=yes],
+       [gcc_cv_header_string=no])
+])
+
+if test "$gcc_cv_header_string" = "yes"; then
+       AC_DEFINE(STRING_WITH_STRINGS, 1, [Define to 1 if string.h may be included along with strings.h])
+fi
+
+AC_C_BIGENDIAN
+
+dnl Check for stdarg.h - if we can't find it, halt configure
+AC_CHECK_HEADER(stdarg.h, , [AC_MSG_ERROR([** stdarg.h could not be found - ircd-ratbox will not compile without it **])])
+
+dnl Checks for the existence of strlcat, strlcpy, basename...
+dnl This more reliable test only works with gcc though.
+
+if test "$ac_cv_c_compiler_gnu" = yes; then
+
+AC_MSG_CHECKING(for strlcpy)
+save_CFLAGS=$CFLAGS
+CFLAGS="$CFLAGS -Wimplicit -Werror"
+
+AC_LINK_IFELSE(
+       [AC_LANG_PROGRAM(
+               [[#include <string.h>
+               #include <stdlib.h>]],
+               [[char *a = malloc(6);
+               strlcpy(a, "hello", 6);]]
+       )],
+       [AC_MSG_RESULT(yes)
+       AC_DEFINE(HAVE_STRLCPY, 1, [Define if strlcpy is available (most BSDs.)])],
+       [AC_MSG_RESULT(no)]
+)
+
+AC_MSG_CHECKING(for strlcat)
+AC_LINK_IFELSE(
+       [AC_LANG_PROGRAM(
+               [[#include <string.h>
+               #include <stdlib.h>]],
+               [[char *a = malloc(6);
+               a[0] = '\0';
+               strlcat(a, "hello", 6);]]
+       )],
+       [AC_MSG_RESULT(yes)
+       AC_DEFINE(HAVE_STRLCAT, 1, [Define if strlcat is available (most BSDs.)])],
+       [AC_MSG_RESULT(no)]
+)
+
+CFLAGS=$save_CFLAGS
+
+else
+
+dnl Better than nothing. The more complicated test above probably fixes powerpc,
+dnl so who cares.
+
+AC_CHECK_FUNCS([strlcat strlcpy])
+
+fi
+
+AC_CHECK_TYPE([u_int32_t], [],
+[
+       AC_CHECK_TYPE([uint32_t],
+       [
+               AC_DEFINE(u_int32_t, [uint32_t], [If system does not define u_int32_t, define a reasonable substitute.])
+       ],
+       [
+               AC_MSG_WARN([system has no u_int32_t or uint32_t, default to unsigned long int])
+               AC_DEFINE(u_int32_t, [unsigned long int], [If system does not define u_int32_t, define to unsigned long int here.])
+       ])
+])
+
+AC_CHECK_TYPE([u_int16_t], [],
+[
+       AC_CHECK_TYPE([uint16_t],
+       [
+               AC_DEFINE(u_int16_t, [uint16_t], [If system does not define u_int16_t, define a usable substitute])
+       ],
+       [
+               AC_MSG_WARN([system has no u_int16_t or uint16_t, default to unsigned short int])
+               AC_DEFINE(u_int16_t, [unsigned short int], [If system does not define u_int16_t, define a usable substitute.])
+       ])
+])
+
+AC_CHECK_TYPE([in_port_t], [],
+[AC_DEFINE(in_port_t, [u_int16_t], [If system does not define in_port_t, define it to what it should be.])],
+[[#include <sys/types.h>
+#include <netinet/in.h>]])
+
+AC_CHECK_TYPE([sa_family_t], [],
+[AC_DEFINE(sa_family_t, [u_int16_t], [If system does not define sa_family_t, define it here.])],
+[[#include <sys/types.h>
+#include <sys/socket.h>]])
+
+AC_CHECK_TYPES([uintptr_t])
+
+dnl check for various functions...
+AC_CHECK_FUNCS([socketpair vsnprintf mmap gettimeofday strdup strndup ])
+
+AC_FUNC_ALLOCA
+
+dnl Specialized functions checks
+dnl ============================
+
+dnl check for nanosleep          
+AC_CHECK_FUNC(nanosleep,,[AC_CHECK_LIB(rt,nanosleep,
+                 LIBS="${LIBS} -lrt",
+                 [AC_CHECK_LIB(posix4,nanosleep, LIBS="${LIBS} -lposix4"
+                 )])])
+if test x$ac_cv_func_nanosleep = xno && test x$ac_cv_lib_posix4_nanosleep = xno  && test x$ac_cv_lib_rt_nanosleep = xno
+then     
+         AC_MSG_RESULT("nanosleep not found..using select for delay")
+else     
+        AC_DEFINE([HAVE_NANOSLEEP], 1, [Define if nanosleep exists])
+fi
+
+dnl OpenSSL support
+AC_MSG_CHECKING(for OpenSSL)
+AC_ARG_ENABLE(openssl,
+[AC_HELP_STRING([--enable-openssl[=DIR]],[Enable OpenSSL support (DIR optional).])
+AC_HELP_STRING([--disable-openssl],[Disable OpenSSL support.])],
+[cf_enable_openssl=$enableval],
+[cf_enable_openssl="auto"])
+
+if test "$cf_enable_openssl" != "no" ; then
+       cf_openssl_basedir=""
+       if test "$cf_enable_openssl" != "auto" &&
+       test "$cf_enable_openssl" != "yes" ; then
+               dnl Support for --enable-openssl=/some/place
+               cf_openssl_basedir="`echo ${cf_enable_openssl} | sed 's/\/$//'`"
+       else
+       dnl Do the auto-probe here.  Check some common directory paths.
+               for dirs in /usr/local/ssl /usr/pkg /usr/local \
+               /usr/local/openssl ; do
+                       if test -f "${dirs}/include/openssl/opensslv.h" ; then
+                               cf_openssl_basedir="${dirs}"
+                       break
+                       fi
+               done
+               unset dirs
+       fi
+       dnl Now check cf_openssl_found to see if we found anything.
+       if test ! -z "$cf_openssl_basedir"; then
+               if test -f "${cf_openssl_basedir}/include/openssl/opensslv.h" ; then
+                       SSL_INCLUDES="-I${cf_openssl_basedir}/include"
+                       SSL_LIBS="-L${cf_openssl_basedir}/lib"
+               else
+               dnl OpenSSL wasn't found in the directory specified.  Naughty
+               dnl administrator...
+               cf_openssl_basedir=""
+               fi
+       else
+       dnl Check for stock FreeBSD 4.x and 5.x systems, since their files
+       dnl are in /usr/include and /usr/lib.  In this case, we don't want to
+       dnl change INCLUDES or LIBS, but still want to enable OpenSSL.
+       dnl We can't do this check above, because some people want two versions
+       dnl of OpenSSL installed (stock FreeBSD 4.x/5.x and /usr/local/ssl)
+       dnl and they want /usr/local/ssl to have preference.
+               if test -f "/usr/include/openssl/opensslv.h" ; then
+                       cf_openssl_basedir="/usr"
+               fi
+       fi
+
+       dnl If we have a basedir defined, then everything is okay.  Otherwise,
+       dnl we have a problem.
+       if test ! -z "$cf_openssl_basedir"; then
+               AC_MSG_RESULT($cf_openssl_basedir)
+               cf_enable_openssl="yes"
+       else
+               AC_MSG_RESULT([not found. Specify a correct path?])
+               cf_enable_openssl="no"
+       fi
+       unset cf_openssl_basedir
+else
+       dnl If --disable-openssl was specified
+       AC_MSG_RESULT(disabled)
+fi
+
+save_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS $SSL_INCLUDES"
+save_LIBS="$LIBS"
+LIBS="$LIBS $SSL_LIBS"
+if test "$cf_enable_openssl" != no; then
+       dnl Check OpenSSL version (must be 0.9.6 or above!)
+       AC_MSG_CHECKING(for OpenSSL 0.9.6 or above)
+       AC_RUN_IFELSE(
+               AC_LANG_PROGRAM(
+               [#include <openssl/opensslv.h>
+               #include <stdlib.h>],
+               [[if ( OPENSSL_VERSION_NUMBER >= 0x00906000)
+               exit(0); else exit(1);]]),
+       cf_openssl_version_ok=yes,
+       cf_openssl_version_ok=no,
+       cf_openssl_version_ok=no)
+
+       if test "$cf_openssl_version_ok" = yes; then
+               AC_MSG_RESULT(found)
+
+               dnl Work around pmake/gmake conditional incompatibilities
+               AC_SUBST(ENCSPEED, encspeed)
+               
+               dnl Do all the HAVE_LIBCRYPTO magic -- and check for ciphers
+               CPPFLAGS="$CPPFLAGS $SSL_LIBS"
+               AC_CHECK_LIB(crypto, RSA_free)
+               SSL_LIBS="$SSL_LIBS -lcrypto"
+               SSL_SRCS_ENABLE='$(SSL_SRCS)'
+       else
+               AC_MSG_RESULT(no - OpenSSL support disabled)
+       fi
+fi
+
+CPPFLAGS="$save_CPPFLAGS"
+LIBS="$save_LIBS"
+
+dnl End OpenSSL detection
+
+
+dnl Specialized functions and libraries
+dnl ===================================
+
+AC_ARG_WITH(zlib-path,
+AC_HELP_STRING([--with-zlib-path=DIR],[Path to libz.so for ziplinks support.]),
+[LIBS="$LIBS -L$withval"],)
+
+AC_ARG_ENABLE(zlib,
+AC_HELP_STRING([--disable-zlib],[Disable ziplinks support]),
+[zlib=$enableval],[zlib=yes])
+
+if test "$zlib" = yes; then
+
+AC_CHECK_HEADER(zlib.h, [
+       AC_CHECK_LIB(z, zlibVersion,
+       [
+               AC_SUBST(ZLIB_LD, -lz)
+               AC_DEFINE(HAVE_LIBZ, 1, [Define to 1 if zlib (-lz) is available.])
+       ], zlib=no)
+], zlib=no)
+
+fi
+
+dnl IO Loop Selection
+dnl =================
+
+AC_ARG_ENABLE(poll, AC_HELP_STRING([--enable-poll],[Force poll() usage.]),
+[ if test $enableval = yes; then 
+       SELECT_TYPE_EXPLICIT="poll"
+  else
+       use_poll=no
+  fi
+],)
+
+AC_ARG_ENABLE(select, AC_HELP_STRING([--enable-select],[Force select() usage.]),
+[ if test $enableval = yes; then 
+       SELECT_TYPE_EXPLICIT="select" 
+  else
+       use_select=no
+  fi
+],)
+
+AC_ARG_ENABLE(kqueue, AC_HELP_STRING([--enable-kqueue],[Force kqueue() usage.]),
+[ if test $enableval = yes; then 
+       SELECT_TYPE_EXPLICIT="kqueue"
+  else
+       use_kqueue=no
+  fi
+],)
+
+AC_ARG_ENABLE(devpoll,AC_HELP_STRING([--enable-devpoll],[Force usage of /dev/poll.]),
+[ if test $enableval = yes; then 
+       SELECT_TYPE_EXPLICIT="devpoll" 
+       dnl These need to be defined or not defined
+       AC_CHECK_HEADERS([sys/devpoll.h devpoll.h])
+  else
+       use_devpoll=no;
+  fi
+],)
+
+AC_ARG_ENABLE(epoll, AC_HELP_STRING([--enable-epoll],[Force sys_epoll usage (Linux only).]),
+[ if test $enableval = yes; then 
+       SELECT_TYPE_EXPLICIT="epoll"
+  else
+       use_epoll=no
+  fi
+],)
+
+dnl **********************************************************************
+dnl Check for --with-confdir
+dnl **********************************************************************
+
+AC_MSG_CHECKING([whether to modify confdir])
+AC_ARG_WITH(confdir, 
+AC_HELP_STRING([--with-confdir=DIR],
+              [Directory to install config files.]),
+              [ confdir=`echo $withval | sed 's/\/$//'`
+                AC_MSG_RESULT(yes)
+                AC_DEFINE_DIR(ETC_DIR, confdir, [Prefix where config files are installed.])
+                AC_SUBST_DIR([confdir]) ],
+              [ confdir='${prefix}/etc'
+                AC_MSG_RESULT(no)
+                AC_DEFINE_DIR(ETC_DIR, confdir, [Prefix where config files are installed.])
+                AC_SUBST_DIR([confdir])]
+)
+
+dnl **********************************************************************
+dnl Check for --with-logdir
+dnl **********************************************************************
+
+AC_MSG_CHECKING([whether to modify logdir])
+AC_ARG_WITH(logdir, 
+AC_HELP_STRING([--with-logdir=DIR],
+              [Directory where to write logfiles.]),
+              [ logdir=`echo $withval | sed 's/\/$//'`
+                AC_MSG_RESULT(yes)
+                AC_DEFINE_DIR(LOG_DIR, logdir, [Prefix where to write logfiles.])
+                AC_SUBST_DIR([logdir]) ],
+              [ logdir='${prefix}/logs'
+                AC_MSG_RESULT(no)
+                AC_DEFINE_DIR(LOG_DIR, logdir, [Prefix where to write logfiles.])
+                AC_SUBST_DIR([logdir])]
+)
+
+dnl **********************************************************************
+dnl Check for --with-helpdir
+dnl **********************************************************************
+
+AC_MSG_CHECKING([whether to modify helpdir])
+AC_ARG_WITH(helpdir, 
+AC_HELP_STRING([--with-helpdir=DIR],
+              [Directory to install help files.]),
+              [ helpdir=`echo $withval | sed 's/\/$//'`
+                AC_MSG_RESULT(yes)
+                AC_DEFINE_DIR(HELP_DIR, helpdir, [Prefix where help files are installed.])
+                AC_SUBST_DIR([helpdir]) ],
+              [ helpdir='${prefix}/help'
+                AC_MSG_RESULT(no)
+                AC_DEFINE_DIR(HELP_DIR, helpdir, [Prefix where help file are installed.])
+                AC_SUBST_DIR([helpdir])]
+)
+
+dnl **********************************************************************
+dnl Check for --with-moduledir
+dnl **********************************************************************
+
+AC_MSG_CHECKING([whether to modify moduledir])
+AC_ARG_WITH(moduledir, 
+AC_HELP_STRING([--with-moduledir=DIR],
+              [Directory to install modules.]),
+              [ moduledir=`echo $withval | sed 's/\/$//'`
+                AC_MSG_RESULT(yes)
+                AC_DEFINE_DIR(MODULE_DIR, moduledir, [Prefix where modules are installed.])
+                AC_SUBST_DIR([moduledir]) ],
+              [ moduledir='${prefix}/modules'
+                AC_MSG_RESULT(no)
+                AC_DEFINE_DIR(MODULE_DIR, moduledir, [Prefix where modules are installed.])
+                AC_SUBST_DIR([moduledir])]
+)
+
+if test ! -z "$SELECT_TYPE_EXPLICIT"; then
+       SELECT_TYPE="$SELECT_TYPE_EXPLICIT";
+       echo "Forcing $SELECT_TYPE to be enabled"
+else
+
+if test ! "x$use_select" = "xno"; then
+       AC_CHECK_FUNCS(select, [haveselect=yes], [haveselect=no])
+       if test "x$haveselect" = "xyes" ; then
+               SELECT_TYPE="select"
+       fi
+fi
+
+if test ! "x$use_poll" = "xno"; then
+       AC_CHECK_FUNCS(poll, [havepoll=yes], [havepoll=no])
+       if test "x$havepoll" = "xyes" ; then
+               SELECT_TYPE="poll"
+       fi
+fi
+
+if test ! "x$use_devpoll" = "xno"; then
+       AC_MSG_CHECKING(for /dev/poll)
+       if test -c "/dev/poll"; then
+               AC_MSG_RESULT(yes)
+               AC_CHECK_HEADERS([devpoll.h sys/devpoll.h])
+               SELECT_TYPE="devpoll"
+       else
+               AC_MSG_RESULT(no)       
+       fi
+fi
+
+if test ! "x$use_kqueue" = "xno"; then
+       AC_CHECK_FUNCS(kevent, [havekqueue=yes], [havekqueue=no])
+       if test "x$havekqueue" = "xyes" ; then
+               SELECT_TYPE="kqueue"
+       fi
+fi
+
+if test ! "x$use_epoll" = "xno"; then
+       AC_CHECK_FUNCS(epoll_ctl, [haveepoll=yes], [haveepoll=no])
+       if test "x$ac_cv_header_sys_epoll_h" = "xyes"; then
+               if test "x$haveepoll" = "xyes" ; then
+                       AC_MSG_CHECKING(for epoll support in kernel)
+                       AC_TRY_RUN(
+#include <stdint.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/epoll.h>
+#include <sys/syscall.h>
+#include <unistd.h>     
+
+int
+main(int argc, char **argv)
+{
+        int epfd;
+
+        epfd = epoll_create(256);
+        exit (epfd == -1 ? 1 : 0);
+}, [AC_MSG_RESULT(yes)
+           AC_DEFINE(HAVE_EPOLL, 1,
+               [Define if your system supports the epoll system calls])
+           SELECT_TYPE="epoll"], 
+           AC_MSG_RESULT(no), AC_MSG_RESULT(no))
+               fi
+       fi
+
+haveepollsyscall=no
+
+if test "x$ac_cv_header_sys_epoll_h" = "xyes"; then
+       if test "x$haveepoll" = "xno" ; then
+                AC_MSG_CHECKING(for epoll system call)
+                AC_TRY_RUN(
+#include <stdint.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/epoll.h>
+#include <sys/syscall.h>
+#include <unistd.h>     
+
+int
+epoll_create(int size)
+{
+        return (syscall(__NR_epoll_create, size));
+}
+int
+main(int argc, char **argv)
+{
+        int epfd;
+
+        epfd = epoll_create(256);
+        exit (epfd == -1 ? 1 : 0);
+}, [AC_MSG_RESULT(yes)
+    AC_DEFINE(HAVE_EPOLL, 1,
+        [Define if your system supports the epoll system calls])
+    SELECT_TYPE="epoll"], 
+    AC_MSG_RESULT(no), AC_MSG_RESULT(no))
+       fi
+fi
+
+fi
+
+fi
+
+if test -z "$SELECT_TYPE"; then
+       AC_MSG_ERROR([Unable to find a usable IO interface],)
+fi
+
+echo "Using $SELECT_TYPE for select loop."
+
+AC_DEFINE_UNQUOTED(SELECT_TYPE, "$SELECT_TYPE", [This is the type of IO loop we are using])
+AC_SUBST(SELECT_TYPE)
+
+
+dnl Debug-related options
+dnl =====================
+
+AC_ARG_ENABLE(assert,
+AC_HELP_STRING([--enable-assert],[Enable assert(). Choose between soft(warnings) and hard(aborts the daemon)]),
+[assert=$enableval], [assert=no])
+
+if test "$assert" = no; then
+       AC_DEFINE(NDEBUG, 1, [Define this to disable debugging support.])
+elif test "$assert" = soft; then
+       AC_DEFINE(SOFT_ASSERT, 1, [Define this to enable soft asserts.])
+       AC_DEFINE(NDEBUG, 1, [Define this to disable debugging support.])
+elif test "$assert" = yes; then
+       assert = "hard";
+fi
+
+AC_MSG_CHECKING(if you want IO Debugging hooks)
+AC_ARG_ENABLE(iodebug,
+AC_HELP_STRING([--enable-iodebug],[Enable IO Debugging hooks]),
+[iodebug=$enableval], [iodebug=no])
+
+if test "$iodebug" = yes; then
+       AC_DEFINE(USE_IODEBUG_HOOKS, 1, [Define this to enable IO Debug hooks.])
+       AC_MSG_RESULT(yes)
+else
+       AC_MSG_RESULT(no)
+fi
+
+
+AC_MSG_CHECKING(if you want to do a profile build)
+AC_ARG_ENABLE(profile,
+AC_HELP_STRING([--enable-profile],[Enable profiling]),
+[profile=$enableval], [profile=no])
+
+if test "$profile" = yes; then
+       if test "$ac_cv_c_compiler_gnu" = yes; then
+               IRC_CFLAGS="$IRC_CFLAGS -pg"
+               AC_MSG_RESULT([yes, adding -pg])
+               AC_DEFINE(CHARYBDIS_PROFILE, 1, [Define this if you are profiling.])
+       else
+               AC_MSG_RESULT([no, profile builds only work with gcc])
+       fi
+else
+       AC_MSG_RESULT(no)
+fi
+
+AC_ARG_ENABLE(balloc,
+AC_HELP_STRING([--disable-balloc],[Disable the block allocator.]),
+[balloc=$enableval], [balloc=yes])
+
+if test "$balloc" = no; then
+       AC_DEFINE([NOBALLOC], 1, [Define to 1 if you wish to disable the block allocator.])
+fi
+
+AC_ARG_ENABLE(ricer-hashing,
+AC_HELP_STRING([--enable-ricer-hashing],[Enable assembly-based hashing routines.]),
+[ricer_hashing=$enableval], [ricer_hashing=no])
+
+FNVHASH_S=""
+
+if test "$ricer_hashing" = "yes"; then
+       AC_DEFINE([RICER_HASHING], 1, [Define to 1 if you are using the assembly-based hashing routines.])
+       FNVHASH_S="fnvhash.s"
+fi
+
+AC_SUBST(FNVHASH_S)
+
+AC_ARG_ENABLE(small-net,
+AC_HELP_STRING([--enable-small-net],[Enable small network support.]),
+[small_net=$enableval], [small_net=no])
+
+if test "$small_net" = yes; then
+dnl    AC_DEFINE([HASHSIZE], 4096, [Max number of buckets in hash tables.])
+       AC_DEFINE([NICKNAMEHISTORYLENGTH], 1500, [Size of the WHOWAS array.])
+       AC_DEFINE([CHANNEL_HEAP_SIZE], 256, [Size of the channel heap.])
+       AC_DEFINE([BAN_HEAP_SIZE], 128, [Size of the ban heap.])
+       AC_DEFINE([CLIENT_HEAP_SIZE], 256, [Size of the client heap.])
+       AC_DEFINE([LCLIENT_HEAP_SIZE], 128, [Size of the local client heap.])
+       AC_DEFINE([PCLIENT_HEAP_SIZE], 32, [Size of the pre-client heap.])
+       AC_DEFINE([USER_HEAP_SIZE], 128, [Size of the user heap.])
+       AC_DEFINE([DNODE_HEAP_SIZE], 256, [Size of the dlink_node heap.])
+       AC_DEFINE([TOPIC_HEAP_SIZE], 256, [Size of the topic heap.])
+       AC_DEFINE([LINEBUF_HEAP_SIZE], 128, [Size of the linebuf heap.])
+       AC_DEFINE([MEMBER_HEAP_SIZE], 256, [Sizeof member heap.])
+       AC_DEFINE([ND_HEAP_SIZE], 128, [Size of the nick delay heap.])
+       AC_DEFINE([CONFITEM_HEAP_SIZE], 128, [Size of the confitem heap.])
+       AC_DEFINE([MONITOR_HEAP_SIZE], 128, [Size of the monitor heap.])
+else
+dnl These settings are for a large network like efnet..they will use lots of memory
+dnl so enable small net unless you really need this much support
+        AC_DEFINE([NICKNAMEHISTORYLENGTH], 15000, [Size of the WHOWAS array.])
+        AC_DEFINE([CHANNEL_HEAP_SIZE], 8192, [Size of the channel heap.])
+        AC_DEFINE([BAN_HEAP_SIZE], 4096, [Size of the ban heap.])
+        AC_DEFINE([CLIENT_HEAP_SIZE], 8192, [Size of the client heap.])
+        AC_DEFINE([LCLIENT_HEAP_SIZE], 1024, [Size of the local client heap.])
+       AC_DEFINE([PCLIENT_HEAP_SIZE], 256, [Size of the pre-client heap.])
+        AC_DEFINE([USER_HEAP_SIZE], 8192, [Size of the user heap.])
+        AC_DEFINE([DNODE_HEAP_SIZE], 8192, [Size of the dlink_node heap.])
+        AC_DEFINE([TOPIC_HEAP_SIZE], 4096, [Size of the topic heap.])
+        AC_DEFINE([LINEBUF_HEAP_SIZE], 2048, [Size of the linebuf heap.])
+        AC_DEFINE([MEMBER_HEAP_SIZE], 32768, [Sizeof member heap.])
+        AC_DEFINE([ND_HEAP_SIZE], 512, [Size of the nick delay heap.])
+        AC_DEFINE([CONFITEM_HEAP_SIZE], 256, [Size of the confitem heap.])
+       AC_DEFINE([MONITOR_HEAP_SIZE], 1024, [Size of the monitor heap.])
+fi
+
+AC_ARG_WITH(nicklen,
+AC_HELP_STRING([--with-nicklen=LENGTH],[Set the nick length to LENGTH (default 15, max 50)]),
+[
+  if test $withval -ge 50; then
+       NICKLEN=50
+       AC_MSG_WARN([NICKLEN has a hard limit of 50. Setting NICKLEN=50])
+  else
+       NICKLEN="$withval"
+  fi
+], [NICKLEN=15])
+
+AC_ARG_WITH(topiclen,           
+AC_HELP_STRING([--with-topiclen=NUMBER],[Set the max topic length to NUMBER (default 390, max 390)]),
+[
+ if test $withval -ge 390; then
+       TOPICLEN=390
+       AC_MSG_WARN([TOPICLEN has a hard limit of 390. Setting TOPICLEN=390])
+ else
+       TOPICLEN=$withval
+ fi
+], [TOPICLEN=390])
+
+AC_ARG_WITH(maxclients,
+AC_HELP_STRING([--with-maxclients=NUMBER],[Maximum number of connections the ircd can handle]),
+        MAX_CLIENTS="$withval", MAX_CLIENTS=3000)
+
+
+if test "$MAX_CLIENTS" = yes; then
+       MAX_CLIENTS=3000
+fi
+
+if test $MAX_CLIENTS -gt 65536; then
+       MAX_CLIENTS=65536
+       AC_MSG_WARN([Max connections cannot be larger than 65536!])
+fi
+
+AC_DEFINE_UNQUOTED(TOPICLEN, ${TOPICLEN}, [Maximum topic length (<=390)])
+AC_DEFINE_UNQUOTED(NICKLEN, (${NICKLEN}+1), [Nickname length])
+AC_DEFINE_UNQUOTED(MAX_CLIENTS, ${MAX_CLIENTS}, [Maximum number of network connections])
+
+AC_ARG_ENABLE(shared-modules,
+AC_HELP_STRING([--disable-shared-modules],[ Disable shared modules.]),
+[shared_modules=$enableval], [shared_modules="yes"])
+
+dnl Some first-stage sanity checks.
+if test "$shared_modules" = yes; then
+       
+       if test "$CYGWIN" = yes; then
+               AC_MSG_WARN([disabling shared modules; Cygwin is at present unable to build them.])
+               shared_modules="no"
+       fi
+
+       dnl TenDRA's cc is called tcc too.
+       if test "$CC" = tcc -a "$TenDRA" = "no"; then
+               AC_MSG_WARN([disabling shared modules: Tiny C Compiler can't create PIC])
+               shared_modules="no"
+       fi
+fi
+
+dnl Second stage: check for functions and headers.
+if test "$shared_modules" = yes; then
+       DYNLINK_C=dynlink.c
+       AC_CHECK_HEADERS(dlfcn.h)
+       AC_SEARCH_LIBS(shl_load, dld, 
+       [
+         AC_DEFINE(HAVE_SHL_LOAD, 1, [Define if the shl_load function is available.])
+         SUFFIX=".sl"
+         MOD_TARGET=hpux_shared
+         SEDOBJ="s/\.o/.sl/g"  
+       ],
+       dnl !shl_load:
+       [
+          dnl standard dlopen
+          AC_SEARCH_LIBS(dlopen, [dl c_r],
+         [
+           AC_DEFINE(HAVE_DLOPEN, 1, [Define if the dlopen function is available.])
+           SUFFIX=".so"
+           MOD_TARGET=shared_modules
+           SEDOBJ="s/\.o/.so/g"
+           if test "$AppleGCC" = yes; then
+              AC_CHECK_HEADERS([mach-o/dyld.h])
+            fi
+           AC_CHECK_FUNC(dlsym, ,
+           [
+             AC_MSG_WARN([dlsym is not available, shared modules disabled])
+             shared_modules=no
+           ])
+           AC_CHECK_FUNCS(dlfunc)
+         ],
+         [
+           shared_modules=no
+         ])
+       ])
+fi
+
+AC_DEFINE_UNQUOTED(SHARED_SUFFIX, "$SUFFIX", [Suffix for shared libraries on this platform.])
+
+dnl Third stage - wrangling the linker.
+if test "$shared_modules" = yes; then
+       # The GNU linker requires the -export-dynamic option to make
+       # all symbols visible in the dynamic symbol table.
+       hold_ldflags=$LDFLAGS
+       AC_MSG_CHECKING(for the ld -export-dynamic flag)
+       LDFLAGS="${LDFLAGS} -Wl,-export-dynamic -Werror"
+       AC_LINK_IFELSE(AC_LANG_PROGRAM([],[int i;]), found=yes, found=no)
+       LDFLAGS=$hold_ldflags
+
+       if expr "`uname -s`" : ^IRIX >/dev/null 2>&1; then
+               found="no, IRIX ld uses -B,dynamic"
+               LDFLAGS="${LDFLAGS} -Wl,-B,dynamic"
+       fi
+       
+       if expr "`uname -s`" : ^AIX >/dev/null 2>&1; then
+               found="no, AIX ld uses -G -brtl"
+               LDFLAGS="${LDFLAGS} -Wl,-G,-brtl"
+       fi
+
+       AC_MSG_RESULT($found)
+
+       if test "$found" = yes; then
+               LDFLAGS="${LDFLAGS} -Wl,-export-dynamic"
+       fi
+
+       AC_MSG_CHECKING(for compiler option to produce PIC)
+       dnl The order should be here to check for groups of compilers,
+       dnl then for odd compilers, then if no PICFLAGS were set up,
+       dnl check for GCC and set defaults, or else error. -jmallett
+       if test "$SGS" = "yes"; then
+               AC_MSG_RESULT([SVR4 SGS interfaces: -KPIC -DPIC -G])
+               PICFLAGS="-KPIC -DPIC -G"
+       fi
+       
+       if test "$AppleGCC" = "yes"; then
+               AC_MSG_RESULT([Darwin Mach-O bundles: -fno-common -bundle -flat_namespace -undefined suppress])
+               PICFLAGS="-fno-common -bundle -flat_namespace -undefined suppress"
+       fi
+       dnl Please note, that on HPUX two different stages of module compilation occurs, since
+       dnl while compiling modules, the compiler does not allow you to give arguments
+       dnl to the linker. (I did not design this) 
+       dnl So we need -c in the first stage of module compilation.
+       dnl In the second stage, we link the modules via ld -b.
+       dnl Additionally, HPUX does not like -export-dynamic, it likes -E instead.
+       dnl -TimeMr14C
+       if test "$HPUX" = "yes" -a "$CC" != gcc; then
+               AC_MSG_RESULT(HP-UX cc: +z -r -q -n)
+               PICFLAGS="+z -r -q -n -c"
+               AC_MSG_CHECKING([if +ESfic is required on this platform])
+               
+               if expr "`$CC +ESfic 2>&1`" : ".*neither supported.*" >/dev/null; then 
+                       AC_MSG_RESULT(no)
+               else
+                       AC_MSG_RESULT(yes)
+                       PICFLAGS="$PICFLAGS +ESfic"
+               fi
+
+               LDFLAGS="${LDFLAGS} -Wl,-E"
+       fi
+       if test "$Tru" = yes -a "$CC" != gcc; then
+               AC_MSG_RESULT([Tru64: -shared -expect_unresolved '*'])
+               PICFLAGS="-shared -expect_unresolved '*' "
+               LDFLAGS="-call_shared"
+       fi
+       if test -z "$PICFLAGS"; then
+               if test "$ac_cv_c_compiler_gnu" = "yes"; then
+                       AC_MSG_RESULT(gcc: -fPIC -DPIC -shared)
+                       PICFLAGS="-fPIC -DPIC -shared"
+               else
+                       AC_MSG_RESULT(no)
+                       shared_modules=no
+               fi
+       fi
+fi
+
+# This must be down here, or it will mess up checks like the ones
+# for -Wl,-export-dynamic
+# -- jilles
+AC_ARG_ENABLE(warnings,
+AC_HELP_STRING([--enable-warnings],[Enable all sorts of warnings for debugging.]),
+[
+IRC_CFLAGS="$IRC_CFLAGS -O0"
+CFLAGS="$IRC_CFLAGS"
+
+CHARYBDIS_C_GCC_TRY_FLAGS([-Wall], charybdis_cv_c_gcc_w_all)
+CHARYBDIS_C_GCC_TRY_FLAGS([-Wpointer-arith], charybdis_cv_c_gcc_w_pointer_arith)
+CHARYBDIS_C_GCC_TRY_FLAGS([-Wimplicit -Wnested-externs], charybdis_cv_c_gcc_w_implicit)
+CHARYBDIS_C_GCC_TRY_FLAGS([-Wcast-align], charybdis_cv_c_gcc_w_cast_align)
+CHARYBDIS_C_GCC_TRY_FLAGS([-Wcast-qual], charybdis_cv_c_gcc_w_cast_qual)
+CHARYBDIS_C_GCC_TRY_FLAGS([-Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations], charybdis_cv_c_gcc_prototypes)
+CHARYBDIS_C_GCC_TRY_FLAGS([-Wparenthesis], charybdis_cv_c_gcc_parenthesis)
+CHARYBDIS_C_GCC_TRY_FLAGS([-W -Wno-unused], charybdis_cv_c_gcc_w)
+CHARYBDIS_C_GCC_TRY_FLAGS([-Wextra], charybdis_cv_c_gcc_w_extra)
+CHARYBDIS_C_GCC_TRY_FLAGS([-Wshadow], charybdis_cv_c_gcc_w_shadow)
+CHARYBDIS_C_GCC_TRY_FLAGS([-Wmissing-noreturn], charybdis_cv_c_gcc_w_missing_noreturn)
+CHARYBDIS_C_GCC_TRY_FLAGS([-Wundef], charybdis_cv_c_gcc_w_undef)
+CHARYBDIS_C_GCC_TRY_FLAGS([-Wpacked], charybdis_cv_c_gcc_w_packed)
+CHARYBDIS_C_GCC_TRY_FLAGS([-Wnested-externs], charybdis_cv_c_gcc_w_nested_externs)
+CHARYBDIS_C_GCC_TRY_FLAGS([-Wbad-function-cast], charybdis_cv_c_gcc_w_bad_function_cast)
+CHARYBDIS_C_GCC_TRY_FLAGS([-Wunused-function -Wunused-label -Wunused-value -Wunused-variable], charybdis_cv_c_gcc_w_unused)
+CHARYBDIS_C_GCC_TRY_FLAGS([-Wredundant-decls], charybdis_cv_c_gcc_w_redundant_decls)
+CHARYBDIS_C_GCC_TRY_FLAGS([-Wfloat-equal], charybdis_cv_c_gcc_w_float_equal)
+CHARYBDIS_C_GCC_TRY_FLAGS([-Wformat=2], charybdis_cv_c_gcc_w_format)
+CHARYBDIS_C_GCC_TRY_FLAGS([-pedantic], charybdis_cv_c_gcc_pedantic)
+
+IRC_CFLAGS="$CFLAGS"
+],[])
+
+if test "$shared_modules" = no; then
+       DYNLINK_C=""
+       MOD_TARGET="libmodules.a"
+       MODULES_LIBS="../modules/libmodules.a"
+       SEDOBJ=""
+       AC_DEFINE(STATIC_MODULES, 1, [Define to 1 if dynamic modules can't be used.])
+       AC_MSG_WARN([shared module support has been disabled!])
+fi
+
+dnl Stage 5 - underscores in front of symbol names.
+if test "$shared_modules" = yes; then
+
+       AC_CHECK_FUNC(nlist,,
+               AC_CHECK_LIB(dl, nlist, nlist_lib="-ldl",
+                       AC_CHECK_LIB(elf, nlist, nlist_lib="-lelf",)
+               )
+       )
+
+        dnl We need to find out whether underscores are appended to symbol
+        dnl names in executable files.  First, though, we need to see
+        dnl where nlist.h is hiding.
+       AC_CHECK_HEADER(libelf/nlist.h, [ nlist_h="libelf/nlist.h" ], )
+       AC_CHECK_HEADER(elf/nlist.h, [ nlist_h="elf/nlist.h" ], )
+       AC_CHECK_HEADER(nlist.h, [ nlist_h="nlist.h" ], )
+       if test x"$nlist_h" = "x"; then
+               AC_DEFINE_UNQUOTED(SYMBOL_PREFIX, "", [String containing extra underscores prepended to symbols loaded from modules.])
+       else
+               AC_MSG_CHECKING(for extra underscores prepended to symbol names)
+               AC_CACHE_VAL(symbol_underscores,
+               [
+cat << EOF > conftest.c
+#include <$nlist_h>
+#include <stdio.h>
+#include <stdlib.h>
+void _modinit(void);
+int main(int argc, char *argv[[]]) {
+       int i;
+       struct nlist nl[[5]];
+
+       /* fill the names in this way, so it'll work almost everywhere */
+       nl[[0]].n_name = "_modinit";
+       nl[[1]].n_name = "__modinit";
+       nl[[2]].n_name = "___modinit";
+       nl[[3]].n_name = "____modinit";
+       nl[[0]].n_value = nl[[1]].n_value = nl[[2]].n_value = nl[[3]].n_value = nl[[4]].n_name = NULL;
+
+       if(argc < 2 || (nlist(argv[[1]], nl)) == -1) exit(-1);
+       for(i = 0; i < 4; i++) {
+               if(nl[[i]].n_value != NULL)
+               {
+                       int j;
+                       for(j = 0; j < i; j++)
+                               printf("_");
+                       exit(i);
+               }
+       }
+       exit(-1);
+}
+void _modinit(void) { return; }
+EOF
+               $CC $CPPFLAGS $IRC_CFLAGS -o conftest conftest.c $nlist_lib >/dev/null 2>&1
+               symbol_underscores=`./conftest conftest`
+               AC_MSG_RESULT($symbol_underscores)
+               $RM -f conftest conftest.c
+               ])
+               AC_DEFINE_UNQUOTED(SYMBOL_PREFIX, "${symbol_underscores}", [String containing extra underscores prepended to symbols loaded from modules.])
+       fi
+fi
+
+AC_SUBST(MODULES_LIBS)
+AC_SUBST(MOD_TARGET)
+
+AC_SUBST(SSL_SRCS_ENABLE)
+AC_SUBST(SSL_INCLUDES)
+AC_SUBST(SSL_LIBS)
+
+AC_SUBST(LDFLAGS)
+AC_SUBST(PICFLAGS)
+AC_SUBST(IRC_CFLAGS)
+AC_SUBST(SEDOBJ)
+
+
+if test "$prefix" = "NONE"; then 
+       AC_DEFINE_UNQUOTED(IRCD_PREFIX, "$ac_default_prefix", [Prefix where the ircd is installed.])
+
+else
+
+dnl Don't get bitten by Cygwin's stupidity if the user specified
+dnl a custom prefix with a trailing slash
+
+       prefix=`echo $prefix | sed 's/\/$//'`
+       AC_DEFINE_UNQUOTED(IRCD_PREFIX, "$prefix", [Prefix where the ircd is installed.])
+       
+fi
+
+AC_CONFIG_FILES(                       \
+       Makefile                        \
+       libcharybdis/Makefile           \
+       servlink/Makefile               \
+       extensions/Makefile             \
+       unsupported/Makefile            \
+       src/Makefile                    \
+       modules/Makefile                \
+       tools/Makefile                  \
+       doc/Makefile                    \
+       help/Makefile                   \
+)
+
+AC_OUTPUT
+
+if test "$cf_openssl_version_ok" = yes; then
+       openssl="yes"
+else
+       openssl="no"
+fi
+
+if test "$shared_modules" = yes; then
+       modules=shared
+else
+       modules=static
+fi
+
+echo "
+Configuration:
+       Install directory  : $prefix
+
+       Ziplinks           : $zlib
+       OpenSSL            : $openssl
+       Modules            : $modules
+       IPv6 support       : $have_v6
+       Socket Engine      : $SELECT_TYPE
+       Small network      : $small_net
+       Block allocator    : $balloc
+       ASM hashing code   : $ricer_hashing
+
+       Nickname length    : $NICKLEN
+       Topic length       : $TOPICLEN
+
+Use make to compile Charybdis, then make install to install it.
+"
diff --git a/doc/.cvsignore b/doc/.cvsignore
new file mode 100644 (file)
index 0000000..f3c7a7c
--- /dev/null
@@ -0,0 +1 @@
+Makefile
diff --git a/doc/CIDR.txt b/doc/CIDR.txt
new file mode 100644 (file)
index 0000000..ddb514f
--- /dev/null
@@ -0,0 +1,316 @@
+$Id: CIDR.txt 6 2005-09-10 01:02:21Z nenolod $
+
+CIDR Information
+----------------
+  Presently, we all use IPv4.  The format of IPv4 is the following:
+
+A.B.C.D
+
+  Where letters 'A' through 'D' are 8-bit values.  In English, this
+  means each digit can have a value of 0 to 255.  Example:
+
+129.56.4.234
+
+  Digits are called octets.  Oct meaning 8, hence 8-bit values.  An
+  octet cannot be greater than 255, and cannot be less than 0 (eg. a
+  negative number).
+
+  CIDR stands for "classless inter domain routing", details covered
+  in RFC's 1518 and 1519. It was introduced mainly due to waste within
+  A and B classes space. The goal was to make it possible to use
+  smaller nets than it would seem from (above) IP classes, for instance
+  by dividing one B class into 256 "C like" classes. The other goal was
+  to allow aggregation of routing information, so that routers could use
+  one aggregated route (like 194.145.96.0/20) instead of
+  advertising 16 C classes.
+
+  Class A are all these addresses which first bit is "0",
+  bitmap: 0nnnnnnn.hhhhhhhh.hhhhhhhh.hhhhhhhh (n=net, h=host)
+  IP range is 0.0.0.0 - 127.255.255.255
+
+  Class B are all these addresses which first two bits are "10",
+  bitmap: 10nnnnnn.nnnnnnnn.hhhhhhhh.hhhhhhhh (n=net, h=host)
+  IP range is 128.0.0.0 - 191.255.255.255
+
+  Class C are all these addresses which first three bits are "110",
+  bitmap: 110nnnnn.nnnnnnnn.nnnnnnnn.hhhhhhhh (n=net, h=host)
+  IP range is 192.0.0.0 - 223.255.255.255
+
+  Class D are all these addresses which first four bits are "1110",
+  this is multicast class and net/host bitmap doesn't apply here
+  IP range is 224.0.0.0 - 239.255.255.255
+  I bet they will never IRC, unless someone creates multicast IRC :)
+
+  Class E are all these addresses which first five bits are "11110",
+  this class is reserved for future use
+  IP range is 240.0.0.0 - 247.255.255.255
+
+  So, here is how CIDR notation comes into play.
+
+  For those of you who have real basic exposure to how networks are
+  set up, you should be aware of the term "netmask."  Basically, this
+  is a IPv4 value which specifies the "size" of a network.  You can
+  assume the word "size" means "range" if you want.
+
+  A chart describing the different classes in CIDR format and their
+  wildcard equivalents would probably help at this point:
+
+CIDR version   dot notation (netmask)  Wildcard equivalent
+-----------------------------------------------------------------
+A.0.0.0/8      A.0.0.0/255.0.0.0       A.*.*.*  or  A.*
+A.B.0.0/16     A.B.0.0/255.255.0.0     A.B.*.*  or  A.B.*
+A.B.C.0/24     A.B.C.0/255.255.255.0   A.B.C.*  or  A.B.C.*
+A.B.C.D/32     A.B.C.D/255.255.255.255 A.B.C.D
+
+
+  The question on any newbies mind at this point is "So what do all
+  of those values & numbers actually mean?"
+
+  Everything relating to computers is based on binary values (1s and
+  zeros).  Binary plays a *tremendous* role in CIDR notation.  Let's
+  break it down to the following table:
+
+          A            B            C            D
+       --------     --------     --------     --------
+/8  == 11111111  .  00000000  .  00000000  .  00000000  == 255.0.0.0
+/16 == 11111111  .  11111111  .  00000000  .  00000000  == 255.255.0.0
+/24 == 11111111  .  11111111  .  11111111  .  00000000  == 255.255.255.0
+/32 == 11111111  .  11111111  .  11111111  .  11111111  == 255.255.255.255
+
+  The above is basically a binary table for the most common netblock
+  sizes.  The "1"s you see above are the 8-bit values for each octet.
+  If you split an 8-bit value into each of it's bits, you find the
+  following:
+
+00000000
+^^^^^^^^_ 1sts place  (1)
+|||||||__ 2nds place  (2)
+||||||___ 3rds place  (4)
+|||||____ 4ths place  (8)
+||||_____ 5ths place  (16)
+|||______ 6ths place  (32)
+||_______ 7ths place  (64)
+|________ 8ths place  (128)
+
+  Now, since computers consider zero a number, you pretty much have
+  to subtract one (so-to-speak; this is not really how its done, but
+  just assume it's -1 :-) ) from all the values possible.  Some
+  examples of decimal values in binary:
+
+15  == 00001111  (from left to right: 8+4+2+1)
+16  == 00010000  (from left to right: 16)
+53  == 00110101  (from left to right: 32+16+4+1)
+79  == 01001111  (from left to right: 64+8+4+1)
+254 == 11111110  (from left to right: 128+64+32+16+8+4+2)
+
+  So, with 8 bits, the range (as I said before) is zero to 255.
+
+  If none of this is making sense to you at this point, you should
+  back up and re-read all of the above.  I realize it's a lot, but
+  it'll do you some good to re-read it until you understand :-).
+
+  So, let's modify the original table a bit by providing CIDR info
+  for /1 through /8:
+
+          A            B            C            D
+       --------     --------     --------     --------
+/1  == 10000000  .  00000000  .  00000000  .  00000000  == 128.0.0.0
+/2  == 11000000  .  00000000  .  00000000  .  00000000  == 192.0.0.0
+/3  == 11100000  .  00000000  .  00000000  .  00000000  == 224.0.0.0
+/4  == 11110000  .  00000000  .  00000000  .  00000000  == 240.0.0.0
+/5  == 11111000  .  00000000  .  00000000  .  00000000  == 248.0.0.0
+/6  == 11111100  .  00000000  .  00000000  .  00000000  == 252.0.0.0
+/7  == 11111110  .  00000000  .  00000000  .  00000000  == 254.0.0.0
+/8  == 11111111  .  00000000  .  00000000  .  00000000  == 255.0.0.0
+
+  At this point, all of this should making a lot of sense, and you
+  should be able to see the precision that you can get by using CIDR
+  at this point.  If not, well, I guess the best way to put it would
+  be that wildcards always assume /8, /16, or /24 (yes hello Piotr,
+  we can argue this later: I am referring to IPs *ONLY*, not domains
+  or FQDNs :-) ).
+
+  This table will provide a reference to all of the IPv4 CIDR values
+
+cidr|netmask (dot notation)
+----+---------------------
+/1  | 128.0.0.0
+/2  | 192.0.0.0
+/3  | 224.0.0.0
+/4  | 240.0.0.0
+/5  | 248.0.0.0
+/6  | 252.0.0.0
+/7  | 254.0.0.0
+/8  | 255.0.0.0
+/9  | 255.128.0.0
+/10 | 255.192.0.0
+/11 | 255.224.0.0
+/12 | 255.240.0.0
+/13 | 255.248.0.0
+/14 | 255.252.0.0
+/15 | 255.254.0.0
+/16 | 255.255.0.0
+/17 | 255.255.128.0
+/18 | 255.255.192.0
+/19 | 255.255.224.0
+/20 | 255.255.240.0
+/21 | 255.255.248.0
+/22 | 255.255.252.0
+/23 | 255.255.254.0
+/24 | 255.255.255.0
+/25 | 255.255.255.128
+/26 | 255.255.255.192
+/27 | 255.255.255.224
+/28 | 255.255.255.240
+/29 | 255.255.255.248
+/30 | 255.255.255.252
+/31 | 255.255.255.254
+/32 | 255.255.255.255
+
+  So, let's take all of the information above, and apply it to a
+  present-day situation on IRC.
+
+  Let's say you have a set of flooding clients who all show up from
+  the following hosts.  For lack-of a better example, I'll use a
+  subnet here at Best:
+
+nick1  (xyz@shell9.ba.best.com)  [206.184.139.140]
+nick2  (abc@shell8.ba.best.com)  [206.184.139.139]
+nick3  (foo@shell12.ba.best.com) [206.184.139.143]
+
+  Most people will assume the  they were all in the same class C
+  (206.184.139.0/24  or  206.184.139.*).
+
+  This, as a matter of fact, is not true.  Now, the reason *I* know
+  this is solely because I work on the network here; those IPs are
+  not delegated to a class C, but two portions of a class C (128 IPs
+  each).  That means the class C is actually split into these two
+  portions:
+
+Netblock               IP range
+--------               --------
+206.184.139.0/25       206.184.139.0   to 206.184.139.127
+206.184.139.128/25     206.184.139.128 to 206.184.139.255
+
+  For the record, 206.184.139.0 and 206.184.139.128 are both known as
+  "network addresses" (not to be confused with "netblocks" or "Ethernet
+  hardware addresses" or "MAC addresses").  Network addresses are
+  *ALWAYS EVEN*.
+
+  206.184.139.127 and 206.184.139.255 are what are known as broadcast
+  addresses.  Broadcast addresses are *ALWAYS ODD*.
+
+  Now, the aforementioned list of clients are in the 2nd subnet shown
+  above, not the first.  The reason for this should be obvious.
+
+  The remaining question is, "Well that's nice, you know what the netblock
+  is for Best.  What about us?  We don't know that!"
+
+  Believe it or not, you can find out the network block size by using
+  whois -h WHOIS.ARIN.NET on the IP in question.  ARIN keeps a list of
+  all network blocks and who owns them -- quite useful, trust me.  I
+  think I use ARIN 5 or 6 times a day, especially when dealing with
+  D-lines.  Example:
+
+$ whois -h whois.arin.net 206.184.139.140
+Best Internet Communications, Inc. (NETBLK-NBN-206-184-BEST)
+345 East Middlefield Road
+Mountain View, CA 94043
+
+Netname: NBN-206-184-BEST
+Netblock: 206.184.0.0 - 206.184.255.255
+Maintainer: BEST
+
+  Does this mean you should D-line 206.184.0.0/16?  Probably not.
+  That's an entire class B-sized block, while you're only trying
+  to deny access to a subnetted class C.
+
+  So then how do you get the *real* info?  Well, truth is, you don't.
+  You have to pretty much take a guess at what it is, if ARIN reports
+  something that's overly vague.  Best, for example, was assigned the
+  above class B-sized block.  We can subnet it however we want without
+  reporting back to ARIN how we have it subnetted.  We own the block,
+  and that's all that matters (to ARIN).
+
+  Not all subnets are like this, however.  Smaller subnets you may
+  find partitioned and listed on ARIN; I've seen /29 blocks for DSL
+  customers show up in ARIN before.
+
+  So, use ARIN any chance you get.  The more precision the better!
+
+  Now, there is a small issue I want to address regarding use of CIDR
+  notation.  Let's say you D-line the following in CIDR format (hi
+  sion ;-) ):
+
+205.100.132.18/24
+
+  Entries like this really makes my blood boil, solely because it adds
+  excessive confusion and is just basically pointless.  If you
+  examine the above, you'll see the /24 is specifying an entire
+  class C -- so then what's the purpose of using .18 versus .0?
+
+  There IS no purpose.  The netmask itself will mask out the .18 and
+  continue to successfully use 205.100.132.0/24.
+
+  Doing things this way just adds confusion, especially on non-octet-
+  aligned subnets (such as /8, /16, /24, or /32).  Seeing that on a
+  /27 or a /19 might make people go "wtf?"
+
+  I know for a fact this doc lacks a lot of necessary information,
+  like how the actual netmask/CIDR value play a role in "masking out"
+  the correct size, and what to do is WHOIS.ARIN.NET returns no
+  netblock information but instead a few different company names with
+  NIC handles.  I'm sure you can figure this stuff out on your own,
+  or just ask an administrator friend of yours who DOES know.  A lot
+  of us admins are BOFH types, but if you ask us the right questions,
+  you'll benefit from the answer quite thoroughly.
+
+  Oh, I almost forgot.  Most Linux systems use a different version of
+  "whois" than FreeBSD does.  The syntax for whois on Linux is
+  "whois <INFO>@whois.arin.net", while under FreeBSD it is
+  "whois -h whois.arin.net <INFO>"  Debian uses yet another version
+  of whois that is incompatible with the above syntax options.
+
+  Note that the FreeBSD whois client has shortcuts for the most commonly
+  used whois servers.  "whois -a <INFO>" is the shortcut for ARIN.
+
+  Also note that ARIN is not authoritative for all IP blocks on the 
+  Internet.  Take for example 212.158.123.66.  A whois query to ARIN
+  will return the following information:
+
+$ whois -h whois.arin.net 212.158.123.66
+European Regional Internet Registry/RIPE NCC (NET-RIPE-NCC-)
+   These addresses have been further assigned to European users.
+   Contact information can be found in the RIPE database, via the
+   WHOIS and TELNET servers at whois.ripe.net, and at
+   http://www.ripe.net/db/whois.html
+
+   Netname: RIPE-NCC-212
+   Netblock: 212.0.0.0 - 212.255.255.255
+   Maintainer: RIPE
+
+  This query tells us that it is a European IP block, and is further
+  handled by RIPE's whois server.  We must then query whois.ripe.net
+  to get more information.
+
+$ whois -h whois.ripe.net 212.158.123.66
+
+% Rights restricted by copyright. See
+  http://www.ripe.net/ripencc/pub-services/db/copyright.html
+
+inetnum:     212.158.120.0 - 212.158.123.255
+netname:     INSNET-P2P
+descr:       Point to Point Links for for London Nodes
+country:     GB
+--snip--
+
+  This tells us the actual IP block that the query was a part of.
+
+  Other whois servers that you may see blocks referred to are: 
+  whois.ripn.net for Russia, whois.apnic.net for Asia, Australia, and
+  the Pacific, and whois.6bone.net for IPv6 blocks.
+
+Contributed by Jeremy Chadwick <jdc@best.net>
+Piotr Kucharski <chopin@sgh.waw.pl> 
+W. Campbell <wcampbel@botbay.net> and
+Ariel Biener <ariel@fireball.tau.ac.il>
diff --git a/doc/Hybrid-team b/doc/Hybrid-team
new file mode 100644 (file)
index 0000000..d193166
--- /dev/null
@@ -0,0 +1,61 @@
+$Id: Hybrid-team 54 2005-09-10 05:12:55Z nenolod $
+
+The hybrid team is a group of ircd coders who were frustrated
+with the instability and all-out "dirtiness" of the EFnet ircd's
+available. "hybrid" is the name for the collective efforts of a group
+of people, all of us.
+
+Anyone is welcome to contribute to this effort. You are encouraged
+to participate in the Hybrid mailing list. To subscribe to the
+Hybrid List, use this link:
+  https://lists.ircd-hybrid.org/mailman/listinfo/hybrid
+
+The core team as, of this major release:
+
+adx, Piotr Nizynski <adx@irc7.pl>
+billy-jon, William Bierman III <bill@mu.org>
+cryogen, Stuart Walsh <stu@ipng.org.uk>
+Dianora, Diane Bruce <db@db.net>
+joshk, Joshua Kwan <joshk@triplehelix.org>
+kire, Erik Small <smalle@hawaii.edu>
+knight, Alan LeVee <alan.levee@prometheus-designs.net>
+metalrock, Jack Low <jclow@csupomona.edu>
+Michael, Michael Wobst <michael.wobst@gmail.com>
+Rodder, Jon Lusky <lusky@blown.net>
+Wohali, Joan Touzet <joant@ieee.org>
+
+The following people have contributed blood, sweat, and/or code to
+recent releases of Hybrid, in nick alphabetical order:
+
+A1kmm, Andrew Miller <a1kmm@mware.virtualave.net>
+AndroSyn, Aaron Sethman <androsyn@ratbox.org>
+bane, Dragan Dosen <bane@idolnet.org>
+bysin, Ben Kittridge <bkittridge@cfl.rr.com>
+cosine, Patrick Alken <wnder@uwns.underworld.net>
+David-T, David Taylor <davidt@yadt.co.uk>
+fl, Lee Hardy <lee@leeh.co.uk>
+Garion, Joost Vunderink <garion@efnet.nl>
+Habeeb, David Supuran <habeeb@cfl.rr.com>
+Hwy101, W. Campbell <wcampbel@botbay.net>
+jmallett, Juli Mallett <jmallett@FreeBSD.org>
+jv, Jakub Vlasek <jv@pilsedu.cz>
+k9, Jeremy Chadwick <ircd@jdc.parodius.com>
+kre, Dinko Korunic <kreator@fly.srk.fer.hr>
+madmax, Paul Lomax <madmax@efnet.org>
+nenolod, William Pitcock <nenolod@nenolod.net>
+Riedel, Dennis Vink, <riedel@chaotic.nl>
+scuzzy, David Todd <scuzzy@aniverse.net>
+spookey, David Colburn <spookey@spookey.org>
+TimeMr14C, Yusuf Iskenderoglu <uhc0@stud.uni-karlsruhe.de>
+toot, Toby Verrall <to7@antipope.fsnet.co.uk>
+vx0, Mark Miller <mark@oc768.net>
+wiz, Jason Dambrosio <jason@wiz.cx>
+Xride, Søren Straarup <xride@x12.dk>
+zb^3, Alfred Perlstein <alfred@freebsd.org>
+
+Others are welcome. Always. And if we left anyone off the above list,
+be sure to let us know that too. Many others have contributed to
+previous versions of this ircd and its ancestors, too many to list
+here.
+
+Send bug fixes/complaints/rotten tomatoes to bugs@ircd-hybrid.org.
diff --git a/doc/Makefile.in b/doc/Makefile.in
new file mode 100644 (file)
index 0000000..cbf39b7
--- /dev/null
@@ -0,0 +1,96 @@
+# $Id: Makefile.in 138 2005-09-12 00:48:18Z nenolod $
+CC             = @CC@
+INSTALL                = @INSTALL@
+INSTALL_BIN    = @INSTALL_PROGRAM@
+INSTALL_DATA   = @INSTALL_DATA@
+INSTALL_SUID   = @INSTALL_PROGRAM@ -o root -m 4755
+RM             = @RM@
+LEX            = @LEX@
+LEXLIB         = @LEXLIB@
+CFLAGS         = @IRC_CFLAGS@ -DIRCD_PREFIX=\"@prefix@\"
+LDFLAGS                = @LDFLAGS@
+MKDEP          = ${CC} -MM
+MV             = @MV@
+RM             = @RM@
+CP             = @CP@
+TOUCH          = @TOUCH@
+
+prefix         = @prefix@
+exec_prefix    = @exec_prefix@
+exec_suffix    = @exec_suffix@
+bindir         = @bindir@
+libexecdir     = @libexecdir@
+confdir                = @confdir@
+localstatedir  = @localstatedir@
+# Change this later! -- adrian
+moduledir      = @moduledir@
+automoduledir  = @moduledir@/autoload
+
+# Local to the etc Makefile
+mandir          = @mandir@/man8
+MANPAGES        = ircd.8
+
+CONFS          = example.conf reference.conf
+DEFAULTCONFS   = kline.conf dline.conf xline.conf resv.conf
+
+SSL_LIBS       = @SSL_LIBS@
+SSL_INCLUDES   = @SSL_INCLUDES@
+
+IRCDLIBS       = @LIBS@ $(SSL_LIBS)
+
+INCLUDES       = -I../include $(SSL_INCLUDES)
+CPPFLAGS       = ${INCLUDES} @CPPFLAGS@
+install-mkdirs:
+       -@if test ! -d $(DESTDIR)$(confdir); then \
+               echo "mkdir $(confdir)"; \
+               mkdir $(DESTDIR)$(confdir); \
+       fi
+
+       -@if test ! -d $(DESTDIR)$(mandir); then \
+               echo "mkdir $(mandir)"; \
+               mkdir $(DESTDIR)$(mandir); \
+       fi
+
+install: install-mkdirs build
+       @echo "ircd: installing example config files ($(CONFS))"
+       @for i in $(CONFS); do \
+               if test -f $(DESTDIR)$(confdir)/$$i; then \
+                       $(MV) $(DESTDIR)$(confdir)/$$i $(DESTDIR)$(confdir)/$$i.old; \
+               fi; \
+               $(INSTALL_DATA) $$i $(DESTDIR)$(confdir); \
+       done
+
+       @for i in $(DEFAULTCONFS); do \
+               if test ! -f $(DESTDIR)$(confdir)/$$i; then \
+                       echo "ircd: creating config file ($$i)"; \
+                       ${TOUCH} $(DESTDIR)$(confdir)/$$i; \
+               fi; \
+       done
+
+       -@if test ! -f $(DESTDIR)$(confdir)/ircd.motd; then \
+               echo "ircd: installing motd file (ircd.motd)"; \
+               $(INSTALL_DATA) ircd.motd $(DESTDIR)$(confdir); \
+       fi
+
+       -@if test -f $(DESTDIR)$(confdir)/links.txt; then \
+               $(RM) $(DESTDIR)$(confdir)/links.txt; \
+       fi
+
+       @echo "ircd: installing manpage"
+       @for i in $(MANPAGES); do \
+               if test ! -f $(DESTDIR)$(mandir)/$$i; then \
+                       $(INSTALL_DATA) $$i $(DESTDIR)$(mandir); \
+               fi; \
+       done
+
+build:
+
+clean:
+
+depend:
+
+lint:
+
+distclean:
+       ${RM} -f Makefile
diff --git a/doc/README.cidr_bans b/doc/README.cidr_bans
new file mode 100644 (file)
index 0000000..7ca9b5f
--- /dev/null
@@ -0,0 +1,17 @@
+$Id: README.cidr_bans 6 2005-09-10 01:02:21Z nenolod $ 
+
+
+Basically what this patch does is allow for users to use cidr masks when
+setting bans, exceptions, and invite invex(modes beI respectively).  This
+works for both IPv4 and IPv6 addresses.  
+
+I won't go into details of how cidr works here, but to use them, you could
+do something like:
+
+/mode #foo +b *!*@10.0.0.0/8 
+/mode #foo +e *!*@10.0.10.0/24
+
+Aaron Sethman <androsyn@ratbox.org>
+August 06, 2002
+
+
diff --git a/doc/Ratbox-team b/doc/Ratbox-team
new file mode 100644 (file)
index 0000000..b99dcd0
--- /dev/null
@@ -0,0 +1,18 @@
+$Id: Ratbox-team 1640 2006-06-05 00:02:19Z jilles $
+ircd-ratbox is an evolution where ircd-hybrid left off around version 7-rc1.  
+Currently the ircd-ratbox team consists of the following developers:
+AndroSyn, Aaron Sethman <androsyn -at- ratbox.org>
+anfl, Lee Hardy <lee -at- leeh.co.uk>
+
+Special thanks for support, code and ideas to:
+
+Hwy, W. Campbell <wcampbel -at- botbay.net>
+jilles, Jilles Tjoelker <jilles -at- stack.nl>
+larne, Edward Brocklesby <ejb -at- sdf.lonestar.org>
+Of course our work is based on the work of many, many others over the past
+10 or so years since irc has existed, including the work done by the Hybrid
+team, our thanks goes to them.
diff --git a/doc/Tao-of-IRC.940110 b/doc/Tao-of-IRC.940110
new file mode 100644 (file)
index 0000000..fa2f559
--- /dev/null
@@ -0,0 +1,272 @@
+
+The Tao of Internet Relay Chat
+Copyright (C) Ove Ruben R Olsen 1994
+Version of 940110
+Contributing masters: Master ScottM
+
+-----
+Something is formed by the electrons, born in the silent cable. Shaping
+and growing and ungrowing. It is there yet not there. It is the source of
+Internet Relay Chat. I do not know the name, thus I will call it the Tao
+of Internet Relay Chat.
+
+If the Tao is great, then the IRC is running ceaselessly. If the IRC is 
+great then the server is running without ever stoping. If the server is 
+great then the client will always be the server. The luser is then pleased 
+and there is Chat in the world.
+
+The Tao of IRC squits far away and connects on returning.
+
+
+-----
+The genetic potential of birth, a lot to know, yet unknown.
+
+In the begining there was nothing. 
+
+Out of nothing the Tao gave birth to tolsun.oulu.fi. tolsun gave birth to
+OuluBox. 
+
+OuluBox gave birth to rmsg.
+
+rmsg was not Tao, so MUT gave birth to IRC.
+
+No one knows when IRC came into existance, the mighty master WiZ have it 
+to be at the end of the eight month in the year of the Dragon.
+
+
+-----
+Each channel has its purpose, however humble. Each channel is the Yin and
+Yang of IRC. Each channels has it's place within the IRC.
+
+In the beginning there was only channel 0, thus channel 0 is the soil of
+IRC. 
+
+Channel 1 to channel 10 then was open as the sea. Channel 11 to 999 was the 
+trees and forests of IRC. Channels above 999 should not be mentioned, and
+channels below 0 were unborn and contained many secrets.
+
+This was not the right Tao, so IRC gave birth to +channels. 
+
++channels had the yin and yang. Mode does not.
+
+This was not the right Tao still, so IRC gave birth to #channels. 
+
+#channels have the yin and yang.
+
+Only channel 0 is the right path to Tao, but avoid speaking on channel 0.
+
+
+-----
+There was a great dispute among the Broom-Walkers of the Relay. Some of them
+wanted neither yin nor yang. Out of this Eris came into existance. Some of the
+Broom-Walkers then created Eris Free-net. 
+
+This was the right Tao.
+
+Kind Gentle and Boring Net was another wrong path to the Tao of Internet Relay 
+Chat.
+
+Some time later there was a quantity of some lusers who wanted to be 
+Broom-Walkers also. The Eris Free Broom-Walkers did not agree with them, 
+thus a new IRC was born. This IRC is called the Undernet. 
+
+But this is not the right Tao, either.
+
+
+-----
+There will always be disputes among the Broom-Walkers of Internet Relay Chat.
+
+This is the very nature of the IRC.
+
+
+-----
+Lusers that do not understand the Tao is always using the yang of Mode on 
+their channels. Lusers that do understand the Tao are always using Ignore
+on their channels.
+
+How could this not be so ?
+
+
+-----
+The wise sage luser is told about the Chat and uses it. The luser is told 
+about the IRC and is looking for it. The flock are told about the Tao and
+make a fool of the IRC.
+
+If there was no laughter, there would be no Tao.
+
+
+-----
+The master says:
+"Without the Tao of Internet Relay Chat, life becomes meaningless."
+
+The Relay of the old time was mysterious and sacred. We can neither imagine 
+its thoughts nor path; we are left but to describe.
+
+
+-----
+The sage luser must be aware like a frog crossing the highway.
+
+
+-----
+The great master Wumpus once dreamed that he was an automaton. When he awoke
+he exclaimed:
+       "I don't know whether I am Wumpus dreaming that I am a client,
+        or a client dreaming that I am Wumpus!"
+
+So was the first Automata born. 
+
+The master Nap then said:
+       "Any automata should not speak unless spoken to.
+        Any automata shall only whisper when spoken to."
+
+Thus replied the master Gnarfer:
+       "The lusers shall keep in mind that a automata can be either good or
+        bad. Create good automata, and the IRC will hail you and you will 
+        gain fame and fortune. Create bad automata and people will start to 
+        hate you, and finaly you will be /KILLed to ethernal damnation"
+
+Many lusers have fallen into the clutches of ethernal damnation. They where 
+not following the Tao.
+
+
+-----
+There once was a luser who went to #BotSex. Each day he saw the automatons. 
+The luser decided that he also would have such a automata.
+He asked another luser for his automata. The other luser gave his automata
+away.
+
+The luser was not within the Tao, so he just started the automata. The automata
+had only Yang inside so all the lusers files where deleted.
+
+Some moons laither the same luser then had become a sage luser, and did create
+his automata from the very grounds with materials found inside the IRC.
+The luser was now within the Tao and his automata lived happily ever after.
+
+
+-----
+There once was a master who wrote automatons without the help of master Phone.
+A novice luser, seeking to imitate him, began with the help of master Phone.
+When the novice luser asked the master to evaluate his automata the master
+replied: "What is a working automata for the master is not for the luser.
+You must must BE the IRC before automating."
+
+
+-----
+Master BigCheese gave birth to master Troy; his duty clear. Master Troy gave 
+birth to master Phone, for the Tao of Irc must be eternal and must flow as the 
+ceaseless river of Time itself.
+
+
+-----
+Master Phone once said about the ircII client:
+       "public_msg is for a message from someone NOT on the channel
+        public_other is for a message on a channel that doesn't belong to
+        a window. public is for a message on a channel that belongs to a 
+        window!"
+
+Out of this raised the mighty chaos.
+
+
+-----
+The sage luser came to the master who wrote automata without the help of 
+master Phone. The sage luser asked the master who wrote automata: "Which is 
+easiest to make. A automata with the help of master Phone or an automata 
+made with the help of a language ?"
+
+The master who wrote automata then replied:
+       "With the help of a language."
+
+The sage luser was disapointed and exclaimed: "But, with master Phone you
+do not need to know anything about the soil of IRC. Is not that the easiet
+way ?"
+
+"Not really" said the master who wrote automata, "when using master Phone
+you are closed inside a box. For sure, it is a great box for the lusers,
+but the master will need more power, thus a language is the only path to go.
+With the language the master will never have to limit himself. When using
+such a language the master will seek the best between the need and the
+availibility."
+
+"I see", said the sage luser.
+
+This is the essence of Tao of IRC automatas.
+
+
+-----
+A client should be light and be used for communication. The spirit of a good
+client is that it should be very convinient for the luser to use, but hard
+for the luser who want to create automata.
+There should never ever be too many functions or too few functions. 
+
+There should always be a ignore.
+
+Without ignore the client is not within the Tao of Chating.
+
+The client should always respond the luser with messages that will not 
+astnonish him too much. The server likewise. If the server does not, then it
+is the clients job to explain what the server says.
+
+A client which fails this, will be useless and cause confusion for the lusers.
+The only way to correct this is to use another client or to write a new one.
+
+
+-----
+A luser asked the masters on #IrcHelp: "My client does not work".
+The masters replied: "Upgrade your client".
+The luser then wondered why the master knew. The master then told him about
+the Protocol.
+
+"Your client does not work beaucse it does not understand the server. Why
+should it always work ? Only a fool would expect such. But, clients are made
+by humans, and humans are not perfect. Only Tao is.
+
+The IRC is solid. The IRC is floating, and will always be dynamic. Live with 
+that or /quit."
+
+
+-----
+The luser came to the masters of #IrcHelp, asking about the Tao of IRC within
+the client.
+The masters then said that the Tao of IRC always lies inside the client
+regardless of how the client connects to the server.
+
+"Is the Tao in irc ?" asked the luser.
+"It so is" replied the masters of #IrcHelp.
+"Is the Tao in the ircII, Kiwi, rxirc, vms, rockers and msa ?" asked the 
+luser.
+"In all of them and in the TPC, irchat, zenirc, zircon X11-irc and even the 
+dos irc has the Tao" said the master quietly.
+"Is the Tao in a telnet connection directly to the server ?" 
+
+The master then was quiet for a long time and said. "Please leave, such 
+questions are not within the Tao of IRC".
+
+
+-----
+The master says: "Without the Protocol of TCP the messages will not travel.
+                  Without the client, the server is useless."
+
+
+-----
+There once was a luser who used the ircII client. "ircII can do anything I 
+ever need for using IRC" said the emacs client user, "I have /ON's, I have 
+assignments, I have aliasing. Why don't you use this instead of the huge 
+emacs client, which also has a messy screen?"
+The emacs client user then replied by saying that "it is better to have a
+scripting language that is the client instead of have a client that has
+a scripting language." Upon hearing this, the ircII client luser fell silent.
+
+
+-----
+The master Wumpus said: "Time for you to leave. I did, now I'm happy."
+The master Gnarfer replied: "Use, but never overuse IRC, then you will also 
+be happy within IRC"
+
+
+-----
+A luser came unto the masters of #EU-Opers and asked, "How can I be, yet not 
+be, a user@host within the IRC?"
+The masters of #EU-Opers replied: "To be Tao is to be ones true self. To hide
+ones self is not Tao, and is not IRC, you have much to learn before you shall 
+be at rest within the Flow of Irc.  Please leave"
+
diff --git a/doc/challenge.txt b/doc/challenge.txt
new file mode 100644 (file)
index 0000000..3a07711
--- /dev/null
@@ -0,0 +1,86 @@
+------------------------------------------------------
+-    Oper Challenge/Response System Documentation    -
+- Copyright (C) 2006 Lee Hardy <lee -at- leeh.co.uk> -
+- Copyright (C) 2006 ircd-ratbox development team    -
+------------------------------------------------------
+
+The challenge/response system allows the ability to oper though public key
+authentication, without the insecurity of oper passwords.
+
+The challenge system documented here was redesigned in
+ircd-ratbox-2.2/charybdis-1.1 and is not compatible with earlier versions.
+
+This document does not describe the technical details of the challenge
+system.  If you are reading this as part of the ircd distribution, the
+programs referred to are contained in ratbox-respond, see
+http://respond.ircd-ratbox.org for more information and downloads.
+
+
+- Challenge basics -
+--------------------
+When a user requests a challenge to oper up, the ircd takes some random
+data, encodes it using the opers public key, encodes this output in base64
+and sends it to the user as a challenge.  The server then stores a hash of
+the original random data.
+
+The user must then decrypt the data using their private key and generate a
+hash of the decrypted data.  Then the hash is base64 encoded and sent back
+to the server.
+
+If the stored hash the server has matches the reply from the client, they
+are opered up.
+
+
+- Generating a public/private keypair -
+---------------------------------------
+The first step is to use the makekeypair script to generate a public and
+private key.  The public key is set in the ircd config (operator {};
+rsa_public_key_file) instead of a password, and the private key should 
+be kept secret.  It is highly recommended that the key is generated with 
+a secure password.  Generating keys without a password is fundamentally
+insecure.
+
+
+The commands used in makekeypair to generate keys are as follows:
+       openssl genrsa -out private.key -aes256 2048
+       openssl rsa -in private.key -out public.key -pubout
+
+If aes256 is not available, the following is used instead:
+       openssl genrsa -out private.key -des3 2048
+
+
+- Building ratbox-respond -
+---------------------------
+If you are using the unix based ratbox-respond this must be built.  For the
+windows version, ratbox-winrespond, please see http://respond.ircd-ratbox.org
+
+ratbox-respond takes the challenge from the server, and together with your 
+private key file generates a response to be sent back.  ratbox-respond
+requires the openssl headers (ie, development files) and openssl libraries
+are installed for compilation.
+
+Change into the ratbox-respond directory, and run:
+       ./configure
+       make
+
+This will generate a 'ratbox-respond' binary, which you may place wherever
+you like.  If configure does not detect your openssl installation, you may
+pass it the directory where it is installed to via --enable-openssl, this
+should be the base directory which has lib/ and include/openssl/ within it:
+       ./configure --enable-openssl=/path/to/opensslbase
+
+
+- Opering up -
+--------------
+Once you have your public key set in ircd and built ratbox-respond, you oper
+up by issuing "/challenge <opername>".  You should then run:
+       /path/to/ratbox-respond /path/to/private.key
+and input the challenge.  This will give you a response to paste back to the
+server.  The ratbox-respond binary also accepts piped input, see
+ratbox-respond/README for more information.
+
+A number of scripts for clients have already been written to automate this
+process, see client-scripts/README for more information.
+
+-- 
+$Id: challenge.txt 678 2006-02-03 20:25:01Z jilles $
diff --git a/doc/collision_fnc.txt b/doc/collision_fnc.txt
new file mode 100644 (file)
index 0000000..d8fafeb
--- /dev/null
@@ -0,0 +1,41 @@
+Nick collision FNC
+Jilles Tjoelker <jilles -at- stack.nl>
+--------------------------------------
+
+Nick collision FNC performs a forced nick change to the user's UID instead
+of a kill. The criteria for which user may keep the nick are the same as
+before. Server notices will say the clients are being "saved" instead of
+"killed". The client will get a 043 numeric, like this:
+:<server> 043 <uid> :Nick collision, forcing nick change to your unique ID
+
+The following conditions must be fulfilled:
+
+- All servers on the network must allow remote nicks starting with a digit.
+  This is not checked; if this is not fulfilled, users will be killed right
+  after being FNCed.
+
+- All servers on the path between the two clients must support TS6 and
+  nick collision FNC (SAVE capab). If this is not fulfilled, the collision is
+  resolved with kills as before. (This uses the ENCAP GCAP data for remotes.)
+
+- The general::collision_fnc option must be enabled on the server(s) that
+  detect the collision.
+
+Technical details:
+
+The following message is used to propagate the nick change coming from the
+server that detected the collision:
+
+:<sid> SAVE <uid> <ts>
+
+The TS is compared to the current nick TS for the user; if it is not equal,
+the message is dropped. This prevents nick desyncs if the user changed their
+nick after being collided. A SAVE message also generates a server notice to
++k.
+
+The SAVE message is used for propagation to the target's server, and also
+in several other cases if the destination supports SAVE. In other cases, a
+normal nick change or introduction with the UID as nick is sent.
+
+-- 
+$Id: collision_fnc.txt 276 2005-10-02 20:23:15Z jilles $
diff --git a/doc/example.conf b/doc/example.conf
new file mode 100755 (executable)
index 0000000..a0576c5
--- /dev/null
@@ -0,0 +1,422 @@
+/* doc/example.conf - brief example configuration file
+ *
+ * Copyright (C) 2000-2002 Hybrid Development Team
+ * Copyright (C) 2002-2005 ircd-ratbox development team
+ * Copyright (C) 2005-2006 charybdis development team
+ *
+ * $Id: example.conf 3131 2007-01-21 15:36:31Z jilles $
+ *
+ * See reference.conf for more information.
+ */
+
+/* Extensions */
+#loadmodule "extensions/createauthonly.so";
+#loadmodule "extensions/extb_account.so";
+#loadmodule "extensions/extb_canjoin.so";
+#loadmodule "extensions/extb_channel.so";
+#loadmodule "extensions/extb_extgecos.so";
+#loadmodule "extensions/extb_oper.so";
+#loadmodule "extensions/extb_realname.so";
+#loadmodule "extensions/extb_server.so";
+#loadmodule "extensions/hurt.so";
+#loadmodule "extensions/ip_cloaking.so";
+#loadmodule "extensions/m_findforwards.so";
+#loadmodule "extensions/m_identify.so";
+#loadmodule "extensions/no_oper_invis.so";
+#loadmodule "extensions/sno_farconnect.so";
+#loadmodule "extensions/sno_globalkline.so";
+#loadmodule "extensions/sno_globaloper.so";
+
+serverinfo {
+       name = "hades.arpa";
+       use_ts6 = yes;
+       sid = "42X";
+       description = "charybdis test server";
+       network_name = "AthemeNET";
+       network_desc = "Your IRC network.";
+       hub = yes;
+
+       /* On multi-homed hosts you may need the following. These define
+        * the addresses we connect from to other servers. */
+       /* for IPv4 */
+       #vhost = "192.169.0.1";
+       /* for IPv6 */
+       #vhost6 = "3ffe:80e8:546::2";
+};
+
+admin {
+       name = "Lazy admin (lazya)";
+       description = "AthemeNET client server";
+       email = "nobody@127.0.0.1";
+};
+
+log {
+       fname_userlog = "logs/userlog";
+       #fname_fuserlog = "logs/fuserlog";
+       fname_operlog = "logs/operlog";
+       #fname_foperlog = "logs/foperlog";
+       fname_serverlog = "logs/serverlog";
+       fname_glinelog = "logs/glinelog";
+       #fname_klinelog = "logs/klinelog";
+       fname_killlog = "logs/killlog";
+       fname_operspylog = "logs/operspylog";
+       #fname_ioerrorlog = "logs/ioerror";
+};
+
+/* class {} blocks MUST be specified before anything that uses them.  That
+ * means they must be defined before auth {} and before connect {}.
+ */
+class "users" {
+       ping_time = 2 minutes;
+        number_per_ident = 10;
+       number_per_ip = 10;
+        number_per_ip_global = 50;
+       cidr_bitlen = 64;
+       number_per_cidr = 8;
+       max_number = 3000;
+       sendq = 400 kbytes;
+};
+
+class "opers" {
+       ping_time = 5 minutes;
+       number_per_ip = 10;
+       max_number = 1000;
+       sendq = 1 megabyte;
+};
+
+class "server" {
+       ping_time = 5 minutes;
+       connectfreq = 5 minutes;
+       max_number = 1;
+       sendq = 4 megabytes;
+};
+
+listen {
+       /* If you want to listen on a specific IP only, specify host.
+        * host definitions apply only to the following port line.
+        */
+       #host = "192.169.0.1";
+       port = 5000, 6665 .. 6669;
+
+       /* Listen on IPv6 (if you used host= above). */
+       #host = "3ffe:1234:a:b:c::d";
+        #port = 5000, 6665 .. 6669;
+};
+
+/* auth {}: allow users to connect to the ircd (OLD I:)
+ * auth {} blocks MUST be specified in order of precedence.  The first one
+ * that matches a user will be used.  So place spoofs first, then specials,
+ * then general access, then restricted.
+ */
+auth {
+       /* user: the user@host allowed to connect.  multiple IPv4/IPv6 user 
+        * lines are permitted per auth block.
+        */
+       user = "*@172.16.0.0/12";
+       user = "*test@123D:B567:*";
+
+       /* password: an optional password that is required to use this block.
+        * By default this is not encrypted, specify the flag "encrypted" in
+        * flags = ...; below if it is.
+        */
+       password = "letmein";
+       
+       /* spoof: fake the users user@host to be be this.  You may either
+        * specify a host or a user@host to spoof to.  This is free-form,
+        * just do everyone a favour and dont abuse it. (OLD I: = flag)
+        */
+        spoof = "I.still.hate.packets";
+
+       /* Possible flags in auth:
+        * 
+        * encrypted                  | password is encrypted with mkpasswd
+        * spoof_notice               | give a notice when spoofing hosts
+        * exceed_limit (old > flag)  | allow user to exceed class user limits
+        * kline_exempt (old ^ flag)  | exempt this user from k/g/xlines&dnsbls
+        * dnsbl_exempt               | exempt this user from dnsbls
+        * gline_exempt (old _ flag)  | exempt this user from glines
+        * spambot_exempt             | exempt this user from spambot checks
+        * shide_exempt               | exempt this user from serverhiding
+        * jupe_exempt                | exempt this user from generating
+        *                              warnings joining juped channels
+        * resv_exempt                | exempt this user from resvs
+         * flood_exempt               | exempt this user from flood limits
+         *                                     USE WITH CAUTION.
+        * no_tilde     (old - flag)  | don't prefix ~ to username if no ident
+        * need_ident   (old + flag)  | require ident for user in this class
+        * need_sasl                  | require SASL id for user in this class
+        */
+       flags = kline_exempt, exceed_limit;
+       
+       /* class: the class the user is placed in */
+       class = "opers";
+};
+
+auth {
+       user = "*@*";
+       class = "users";
+};
+
+operator "god" {
+       /* name: the name of the oper must go above */
+
+       /* user: the user@host required for this operator.  CIDR *is*
+        * supported now. auth{} spoofs work here, other spoofs do not.
+        * multiple user="" lines are supported.
+        */
+       user = "*god@127.0.0.1";
+
+       /* password: the password required to oper.  Unless ~encrypted is
+        * contained in flags = ...; this will need to be encrypted using 
+        * mkpasswd, MD5 is supported
+        */
+       password = "etcnjl8juSU1E";
+
+       /* rsa key: the public key for this oper when using Challenge.
+        * A password should not be defined when this is used, see 
+        * doc/challenge.txt for more information.
+        */
+       #rsa_public_key_file = "/usr/local/ircd/etc/oper.pub";
+
+       /* umodes: the specific umodes this oper gets when they oper.
+        * If this is specified an oper will not be given oper_umodes
+        * These are described above oper_only_umodes in general {};
+        */
+       #umodes = locops, servnotice, operwall, wallop;
+
+       /* snomask: specific server notice mask on oper up.
+        * If this is specified an oper will not be given oper_snomask.
+        */
+       snomask = "+Zbfkrsuy";
+
+       /* privileges: controls the activities and commands an oper is
+        * allowed to do on the server.  You may prefix an option with ~ to
+        * disable it, ie ~operwall
+        *
+        * Default flags are operwall, remoteban and encrypted.
+        *
+        * Available options:
+        *
+        * encrypted:    the password above is encrypted [DEFAULT]
+        * local_kill:   allows local users to be /KILL'd
+        * global_kill:  allows local and remote users to be 
+        *               /KILL'd                           (OLD 'O' flag)
+        * remote:       allows remote SQUIT and CONNECT   (OLD 'R' flag)
+        * kline:        allows KILL, KLINE and DLINE      (OLD 'K' flag)
+        * unkline:      allows UNKLINE and UNDLINE        (OLD 'U' flag)
+        * gline:        allows GLINE                      (OLD 'G' flag)
+        * nick_changes: allows oper to see nickchanges    (OLD 'N' flag)
+        *               via usermode +n
+        * rehash:       allows oper to REHASH config      (OLD 'H' flag)
+        * die:          allows DIE and RESTART            (OLD 'D' flag)
+        * admin:        gives admin privileges.  admins
+        *               may (un)load modules and see the
+        *               real IPs of servers.
+        * hidden_admin: gives admin privileges except
+        *               will not have the admin lines in
+        *               stats p and whois.
+        * xline:        allows use of /quote xline/unxline
+        * operwall:     allows the oper to send operwalls [DEFAULT]
+        * oper_spy:     allows 'operspy' features to see through +s
+        *               channels etc. see /quote help operspy
+        * hidden_oper:  hides the oper from /stats p    (OLD UMODE +p) 
+        * remoteban:    allows remote kline etc [DEFAULT]
+         */
+       flags = global_kill, remote, kline, unkline, gline,
+               die, rehash, admin, xline, operwall;
+};
+
+connect "irc.uplink.com" {
+       host = "192.168.0.1";
+       send_password = "password";
+       accept_password = "anotherpassword";
+       port = 6666;
+       hub_mask = "*";
+       class = "server";
+       flags = compressed, topicburst;
+
+       /* If the connection is IPv6, uncomment below */
+       #aftype = ipv6;
+};
+
+service {
+       name = "services.int";
+};
+
+cluster {
+       name = "*";
+       flags = kline, tkline, unkline, xline, txline, unxline, resv, tresv, unresv;
+};
+
+shared {
+       oper = "*@*", "*";
+       flags = all, rehash;
+};
+
+/* exempt {}: IPs that are exempt from Dlines. (OLD d:) */
+exempt {
+       ip = "127.0.0.1";
+};
+
+channel {
+       use_invex = yes;
+       use_except = yes;
+       use_knock = yes;
+       use_forward = yes;
+       invite_ops_only = yes;
+       knock_delay = 5 minutes;
+       knock_delay_channel = 1 minute;
+       max_chans_per_user = 15;
+        max_bans = 100;
+        max_bans_large = 500;
+       default_split_user_count = 0;
+       default_split_server_count = 0;
+       no_create_on_split = no;
+       no_join_on_split = no;
+       burst_topicwho = yes;
+       kick_on_split_riding = no;
+};
+
+serverhide {
+       flatten_links = yes;
+       links_delay = 5 minutes;
+        hidden = no;
+       disable_hidden = no;
+};
+
+/* These are the blacklist settings.
+ * You can have multiple combinations of host and rejection reasons.
+ * They are used in pairs of one host/rejection reason.
+ *
+ * These settings should be adequate for most networks, and are (presently)
+ * required for use on AthemeNet.
+ *
+ * Word to the wise: Do not use blacklists like SPEWS for blocking IRC
+ * connections.
+ *
+ * Note: AHBL (the providers of the below BLs) request that they be
+ * contacted, via email, at admins@2mbit.com before using these BLs.
+ * See <http://www.ahbl.org/services.php> for more information.
+ */
+#blacklist {
+#      host = "ircbl.ahbl.org";
+#      reject_reason = "You have a host listed in the ircbl.ahbl.org blacklist.";
+#
+#      host = "tor.ahbl.org";
+#      reject_reason = "You are connecting from a TOR exit node.";
+#};
+
+alias "NickServ" {
+       target = "NickServ";
+};
+
+alias "ChanServ" {
+       target = "ChanServ";
+};
+
+alias "OperServ" {
+       target = "OperServ";
+};
+
+alias "MemoServ" {
+       target = "MemoServ";
+};
+
+alias "NS" {
+       target = "NickServ";
+};
+
+alias "CS" {
+       target = "ChanServ";
+};
+
+alias "OS" {
+       target = "OperServ";
+};
+
+alias "MS" {
+       target = "MemoServ";
+};
+
+general {
+       hide_error_messages = opers;
+       hide_spoof_ips = yes;
+
+       /*
+        * default_umodes: umodes to enable on connect.
+        * If you have enabled the ip_cloaking module, and you want
+        * to make use of it, add +h to this option, i.e.:
+        *      default_umodes = "+ih";
+        */
+       default_umodes = "+i";
+
+       default_operstring = "is an IRC Operator";
+       default_adminstring = "is a Server Administrator";
+       servicestring = "is a Network Service";
+       disable_fake_channels = no;
+        tkline_expire_notices = no;
+        default_floodcount = 10;
+       failed_oper_notice = yes;
+       dots_in_ident=2;
+        dot_in_ip6_addr = no;
+       min_nonwildcard = 4;
+       min_nonwildcard_simple = 3;
+        max_accept = 100;
+       max_monitor = 100;
+       anti_nick_flood = yes;
+       max_nick_time = 20 seconds;
+       max_nick_changes = 5;
+        anti_spam_exit_message_time = 5 minutes;
+       ts_warn_delta = 30 seconds;
+       ts_max_delta = 5 minutes;
+       client_exit = yes;
+       collision_fnc = yes;
+       global_snotices = yes;
+       dline_with_reason = yes;
+       kline_delay = 0 seconds;
+       kline_with_reason = yes;
+       kline_reason = "K-Lined";
+       identify_service = "NickServ@services.int";
+       identify_command = "IDENTIFY";
+       non_redundant_klines = yes;
+       warn_no_nline = yes;
+       stats_e_disabled = no;
+       stats_c_oper_only=no;
+       stats_h_oper_only=no;
+       stats_y_oper_only=no;
+       stats_o_oper_only=yes;
+       stats_P_oper_only=no;
+       stats_i_oper_only=masked;
+       stats_k_oper_only=masked;
+        map_oper_only = no;
+       operspy_admin_only = no;
+       operspy_dont_care_user_info = no;
+       caller_id_wait = 1 minute;
+       pace_wait_simple = 1 second;
+       pace_wait = 10 seconds;
+       short_motd = no;
+       ping_cookie = no;
+       connect_timeout = 30 seconds;
+       disable_auth = no;
+       no_oper_flood = yes;
+       glines = no;
+       gline_time = 1 day;
+       gline_min_cidr = 16;
+        idletime = 0;
+       max_targets = 4;
+       client_flood = 20;
+        use_whois_actually = no;
+       oper_only_umodes = operwall, locops, servnotice;
+       oper_umodes = locops, servnotice, operwall, wallop;
+       oper_snomask = "+s";
+        burst_away = yes;
+       nick_delay = 0 seconds; # 15 minutes if you want to enable this
+       reject_ban_time = 1 minute;
+       reject_after_count = 3;
+       reject_duration = 5 minutes;
+};
+
+modules {
+       path = "modules";
+       path = "modules/autoload";
+};
diff --git a/doc/extban.txt b/doc/extban.txt
new file mode 100644 (file)
index 0000000..4fe3a9e
--- /dev/null
@@ -0,0 +1,92 @@
+Extended bans
+Jilles Tjoelker <jilles -at- stack.nl>
+--------------------------------------
+
+Extended bans (ban conditionals) allow different checks than the usual
+nick!user@host or nick!user@ip match to determine whether someone should
+be banned, quieted, exempted or invited.
+
+Extended bans are of the form $[~]<type>[:<data>]. The <type> is one
+character (case insensitive) and determines the type of match. Most types
+allow or require an extra field <data>. If the tilde (~) is present, the
+result of the comparison will be negated, unless the ban is invalid in which
+case it will never match. Invalid bans are ones where <data> is missing but
+required or where <data> is otherwise invalid as noted below.
+
+Unless noted below, all types can be used with +b, +q, +e and +I.
+
+If any extended ban types are loaded, they are listed in 005 (RPL_ISUPPORT)
+as EXTBAN=$:<types>.
+
+Local users cannot add extended bans of an unknown type or invalid bans. If a
+remote user adds an extended ban of an unknown type, the mode change is
+processed normally. Furthermore, extended bans of an unknown type can always be
+listed or removed.
+
+The ability to send to a channel is cached; this cache may not be updated
+if a condition for an extended ban changes. To work around this, part and
+rejoin the channel, or add or remove a +b, +q or +e entry.
+
+The extban types that come with charybdis are:
+
+extb_account.so
+       $a
+matches all logged in users
+       $a:<mask>
+matches users logged in with a username matching the mask (* and ? wildcards)
+
+extb_channel.so
+       $c:<channel>
+matches users who are on the given channel; this is only valid if the channel
+exists and is not +s or +p. (The ops of the channel the ban is on cannot
+necessarily see whether the user is in the target channel, so it should not
+influence whether they can join either.)
+
+extb_oper.so
+       $o
+matches opers (most useful with +I)
+
+extb_realname.so
+       $r:<mask>
+matches users with a realname (gecos) matching the mask (* and ? wildcards);
+this can only be used with +b and +q
+
+extb_server.so
+       $s:<mask>
+matches users connected to a server matching the mask (* and ? wildcards);
+this can only be used with +b and +q
+
+Comparisons:
+
++b $~a is similar to +r but also prevents not logged in users talking or
+changing their nick while on channel.
+
++iI $o is the same as +O in dreamforge-derived ircds.
+
+Creating extban types:
+
+extban_table, indexed by the extban character, contains function pointers
+of the following type:
+typedef int (*ExtbanFunc)(const char *data, struct Client *client_p,
+               struct Channel *chptr, long mode_type);
+
+The arguments are as follows:
+data: the text after the colon, NULL if there was no colon
+client_p: the client to check; this is always a local client, which may be
+on or off channel
+chptr: the channel
+mode_type: CHFL_BAN, CHFL_QUIET, CHFL_EXCEPTION or CHFL_INVEX
+
+The return value:
+EXTBAN_INVALID: the mask is invalid, it never matches even if negated and
+cannot be added; if this is returned for one client_p it must be returned
+for all
+EXTBAN_NOMATCH: the client_p does not match the mask
+EXTBAN_MATCH: the client_p matches the mask
+
+The function is called whenever a (local) client needs to be checked against
+a +bqeI entry of the given extban type, and whenever a local client tries to
+add such an entry. (Clients are allowed to add bans matching themselves.)
+
+-- 
+$Id: extban.txt 1639 2006-06-04 23:26:47Z jilles $
diff --git a/doc/hooks.txt b/doc/hooks.txt
new file mode 100644 (file)
index 0000000..f85c0fd
--- /dev/null
@@ -0,0 +1,122 @@
+Hook documentation - <lee -at- leeh.co.uk>
+------------------------------------------
+
+Documentation on how to actually develop code to use hooks is contained in
+contrib/example_module.c, this document simply describes which hooks are
+available.
+
+There are various hook structures available that may be passed to hooks:
+hook_data              - struct Client *client; const void *arg1; 
+                         const void *arg2;
+hook_data_int          - struct Client *client; const void *arg1; int arg2;
+hook_data_client       - struct Client *client; struct Client *target;
+hook_data_channel      - struct Client *client; struct Channel *chptr;
+
+
+Spy Hooks
+---------
+The following spy hooks are called only when the request is handled by the
+local server.  They will not be called if the command is being sent remotely
+for another server to handle:
+"doing_admin"          - Passes hook_data:
+                         hdata->client = client requesting ADMIN
+
+"doing_info"           - Passes hook_data:
+                         hdata->client = client requesting INFO
+
+"doing_links"          - Passes hook_data:
+                         hdata->client = client doing LINKS
+                         (const char *) hdata->arg1 = optional mask
+
+"doing_motd"           - Passes hook_data:
+                         hdata->client = client doing MOTD
+
+"doing_stats"          - Passes hook_data_int:
+                         hdata->client = client doing STATS
+                         (const char *) hdata->arg1 = optional stats l target
+                         (char) hdata->arg2 = statchar being requested
+
+"doing_stats_p"                - Passes hook_data:
+                         hdata->client = client doing STATS p
+
+"doing_trace"          - Passes hook_data_client:
+                         hdata->client = client doing TRACE
+                         hdata->target = optional target of TRACE
+
+"doing_whois"          - Passes hook_data_client:
+                         hdata->client = local client doing WHOIS
+                         hdata->target = target of WHOIS
+
+"doing_whois_global"   - Passes hook_data_client:
+                         hdata->client = remote client doing WHOIS
+                         hdata->target = target of WHOIS
+
+
+Netburst Hooks
+--------------
+The following burst hooks are called when we are sending a netburst to a
+server.
+
+"burst_client"         - Sent after we have just burst a user.
+                         Passes hook_data_client:
+                         hdata->client = server we are bursting to
+                         hdata->target = user we have just burst
+
+"burst_channel"                - Sent after we have just burst a channel.
+                         Passes hook_data_channel:
+                         hdata->client = server we are bursting to
+                         hdata->chptr = channel we have just burst
+
+"burst_finished"       - Sent after we have just finished bursting users/chans
+                         Passes hook_data_client:
+                         hdata->client = server we are bursting to
+
+
+Server Hooks
+------------
+The following hooks are called during server connects/exits.
+
+"server_eob"           - Sent after a server finishes bursting to us.
+                         Passes struct Client, the server that has
+                         finished bursting.
+
+"server_introduced"    - Sent after a server is introduced to the network,
+                         local or remote.
+                         Passes hook_data_client:
+                         hdata->client = uplink server (&me if local)
+                         hdata->target = server being introduced
+
+
+Client Hooks
+------------
+The following hooks are called during various events related to clients.
+
+"introduce_client"     - Sent after introducing a client to the (rest of the)
+                         network.
+                         Passes hook_data_client:
+                         hdata->client = server that introduced this client
+                         hdata->target = client being introduced
+
+"new_local_user"       - Sent just before introducing a new local user
+                         to the network.
+                         Passes struct Client, the client being introduced.
+
+"new_remote_user"      - Sent just before introducing a new remote user
+                         to the rest of the network.
+                         Passes struct Client, the client being introduced.
+
+"umode_changed"                - Sent each time a user's mode or snomask changes.
+                         Passes hook_data_umode_changed:
+                         client = client whose modes are changing
+                         oldumodes = new user mode field
+                         oldsnomask = new snomask field
+
+
+The following are for debugging and take struct hook_io_data for arguments. 
+These can be used for a variety of purposes, but are aimed at the developer
+community.
+"iosend"
+"iorecv"
+"iorecvctrl"
+
+$Id: hooks.txt 710 2006-02-06 03:10:01Z gxti $
diff --git a/doc/index.txt b/doc/index.txt
new file mode 100644 (file)
index 0000000..7714a02
--- /dev/null
@@ -0,0 +1,29 @@
+
+# $Id: index.txt 6 2005-09-10 01:02:21Z nenolod $
+Here is the overview of the documents in the doc/ directory.
+
+CIDR.txt               - Description of CIDR in IPv4
+Tao-of-IRC.940110       - No comment...
+challenge.txt           - Overview of the challenge/response system for
+                          obtaining operator status
+example.conf            - An example ircd.conf file describing most of the
+                          user settable options
+guidelines.txt         - Documentation guidelines
+hooks.txt              - Overview of the hooks available
+index.txt              - This file
+ircd.8                  - The new revised manpage, read with the following
+                          commands in the prefix directory:
+                          man -M . ircd
+ircd.motd               - A default ircd.motd used by make install
+logfiles.txt           - Description of formatting of some logfiles
+modeg.txt               - An in depth description of the server side silence
+                          user mode (+g)
+modes.txt               - A list of all user and channel modes
+operguide.txt           - EFnet operator's guide
+opermyth.txt            - Oper myth's, describes what opers can and cannot do
+server-version-info     - Overview of the flags shown in /version
+whats-new.txt          - What new features are available
+
+Also in the contrib/ directory you will find:
+example_module.c - An example module, detailing what the code in a module
+                  does.  Useful for building your own modules.
diff --git a/doc/ircd.8 b/doc/ircd.8
new file mode 100644 (file)
index 0000000..009dfe5
--- /dev/null
@@ -0,0 +1,122 @@
+.\" @(#)ircd.8 2.0 22 April 2004
+.\" $Id: ircd.8 6 2005-09-10 01:02:21Z nenolod $
+.TH IRCD 8 "ircd-ratbox 22 April 2004
+.SH NAME
+ircd \- The Internet Relay Chat Program Server 
+.SH SYNOPSIS
+.hy 0
+.IP \fBircd\fP
+[-dlinefile filename] [-configfile filename] [-klinefile filename]
+[-logfile filename] [-pidfile filename] [-resvfile filename]
+[-xlinefile filename] [-conftest] [-foreground] [-version]
+.SH DESCRIPTION
+.LP
+\fIircd\fP is the server (daemon) program for the Internet Relay Chat
+Program.  The \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 the \fIircd\fP for processing
+and relaying to other ircd sites.
+.SH OPTIONS
+.TP
+.B \-dlinefile filename
+Specifies the D-line file to be used.  This file is used for both reading
+D-lines at startup, and writing to while \fIircd\fP is running.
+.TP
+.B \-configfile filename
+Specifies the ircd.conf file to be used for this ircdaemon. The option
+is used to override the default ircd.conf given at compile time.
+.TP
+.B \-klinefile filename
+Specifies the K-line file to be used.  This file is used for both reading
+K-lines at startup, and writing to while \fIircd\fP is running.
+.TP
+.B \-logfile filename
+Specifies an alternative logfile to be used than that specified in config.h
+.TP
+.B \-pidfile filename
+Specifies the ircd.pid used. The option is used to override the default
+ircd.pid given at compile time.
+.TP
+.B \-resvfile filename
+Specifies the resv.conf file to be used for this ircdaemon. The option
+is used to override the default resv.conf given at compile time.
+.TP
+.B \-xlinefile filename
+Specifies the xline.conf file to be used for this ircdaemon. The option
+is used to override the default xline.conf given at compile time.
+.TP
+.B \-conftest
+Makes \fIircd\fP check the ircd.conf for errors
+.TP
+.B \-foreground
+Makes \fIircd\fP run in the foreground
+.TP
+.B \-version
+Makes \fIircd\fP print its version, and exit.
+.SH USAGE
+If you plan to connect your \fIircd\fP server to an existing Irc-Network,
+you will need to alter your local IRC configuration file (typically named
+"ircd.conf") so that it will accept and make connections to other \fIircd\fP
+servers.  This file contains the hostnames, Network Addresses, and sometimes
+passwords for connections to other ircds around the world.  Because 
+description of the actual file format of the "ircd.conf" file is beyond the
+scope of this document, please refer to the file INSTALL in the IRC source
+files documentation directory.
+.LP
+.SH 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 \fBnot\fP part of your Unix's 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.  
+.SH EXAMPLE
+.RS
+.nf
+tolsun% \fBbin/ircd\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.
+.RS
+.nf
+leguin% \fBbin/ircd -foreground\fP
+.fi
+.RE
+.LP
+Runs ircd in the foreground.
+.RS
+.nf
+.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
+(c) 1997,1998,1999,2000,2001 The IRCD-Hybrid project.
+.LP
+For full COPYRIGHT see LICENSE file with IRC package.
+.LP
+.RE
+.SH FILES
+ "ircd.conf"
+.SH "SEE ALSO"
+ircd.conf(5)
+.SH BUGS
+None... ;-) if somebody finds one, please inform author
+.SH AUTHOR
+irc2.8 and earlier: Jarkko Oikarinen, currently jto@tolsun.oulu.fi.
+.LP
+ircd-hybrid-7: IRCD-Hybrid Project, ircd-hybrid@the-project.org.
+.LP
+manual page written by Jeff Trim, jtrim@orion.cair.du.edu,
+later modified by jto@tolsun.oulu.fi.
+.LP
+modified for ircd-hybrid-7 by Edward Brocklesby, ejb@klamath.uucp.leguin.org.uk.
+.LP
+updated by W. Campbell, wcampbel@botbay.net
diff --git a/doc/ircd.motd b/doc/ircd.motd
new file mode 100644 (file)
index 0000000..343031a
--- /dev/null
@@ -0,0 +1,2 @@
+This is charybdis MOTD you might replace it, but if not your friends will
+laugh at you.
diff --git a/doc/logfiles.txt b/doc/logfiles.txt
new file mode 100644 (file)
index 0000000..65865f6
--- /dev/null
@@ -0,0 +1,36 @@
+ircd-ratbox logfiles - Lee H <lee -at- leeh.co.uk>
+$Id: logfiles.txt 6 2005-09-10 01:02:21Z nenolod $
+---------------------------
+
+fname_killlog
+-------------
+<date> <time> <token> <source> <target> <targets server> <reason>
+
+Where token is one of:
+  L = local oper, local target
+  G = local oper, remote target
+  R = remote oper, remote target
+  O = remote oper, local target
+  S = server
+
+fname_glinelog
+--------------
+<date> <time> <token> <src nick> <src username> <src host> <src server> <user> <host> <reason>
+
+Where token is one of:
+  R = gline request
+  T = gline trigger, always by previous three requests
+
+fname_klinelog
+--------------
+<date> <time> [U]<token> <source> <time> <info> <reason>[|<oper_reason>]
+
+Time is always in minutes, 0 for permanent
+
+
+If 'U' is specified before token, it is a removal rather than an addition.
+Token is one of:
+  K = kline
+  D = dline
+  X = xline
+  R = resv
diff --git a/doc/modeg.txt b/doc/modeg.txt
new file mode 100644 (file)
index 0000000..5680f7e
--- /dev/null
@@ -0,0 +1,140 @@
+                         User Mode +g Documentation
+
+Hybrid 7 includes a new and power feature that all users can take advantage
+of to help prevent flooding and unwanted messages.  This new feature is 
+invoked by setting user mode +g.  When a client is set +g, that user will
+be in "Caller ID" mode.  Any user that messages a +g client will receive
+a notice saying that they are in +g (server side ignore) mode.  The target
+client (who is set +g) will also receive a notice saying that so and so
+messaged them, and that they are in +g mode.
+
+The target of the message will only receive one notification per minute, from
+any client, in order to help prevent flooding.  The sender will NOT have the
+rate limit, and will receive a notice saying the target is in +g mode every
+time they send a message.  Note that this behavior is similar to the way AWAY
+messages are done.
+
+There are numerous benefits for both opers and regular users, including the
+ability to stop spambot messages from ever reaching your client, stopping
+private message and CTCP floods, and being able to sit on IRC in privacy.
+
+One question that arises is how to message specific users, while blocking
+out everyone else.  The command ACCEPT is your answer.  To add a user to
+your accept list, issue the raw command ACCEPT <nick>,<nick>,<nick>,...
+
+You will not receive a reply from the ACCEPT command if it is succesful,
+only if an error has occured.  There are three possible errors, shown by
+numerics:
+
+   ERR_ACCEPTFULL (456): :irc.server 456 client :Accept list is full
+     - This is sent when an accept list is full.
+   ERR_ACCEPTEXIST (457): :irc.server 457 client target :already exists
+     - This is sent when a client tries to add a user to the accept list
+       that already exists there
+   ERR_ACCEPTNOT (458): :irc.server 458 client target :doesnt exist
+     - This is sent when a client tries to remove a user from their accept
+       list who is not on the accept list.
+
+That user will now be able to send messages to your client until the
+association is broken.
+
+Associations break in one of the following situations:  when an accepted user
+QUIT's (or is on the other side of a split), you QUIT, or the accepted user
+changes their nick.  The reason why a remote user's nick change will remove
+them from your accept list is so that you cannot track a user after they
+changed their nick.
+
+Viewing the accept list is also very easy.  Issue the raw command ACCEPT *.
+Removing a user from your accept list is also simple.  Issue the command
+ACCEPT -<nick>.  
+
+                              Sample Session
+
+The easiest way to see how this works is by experiencing it.  Seeing a sample
+session can help understand what goes on though.
+
+Client Hwy-LL is set +g initially.
+Client Hwy101 wants to message Hwy-LL
+
+Note that some clients may have to use /quote ACCEPT instead of /accept.
+
+--
+
+Client Hwy101:  /msg Hwy-LL hi
+Hwy101 will see:  -Hwy-LL- *** I'm in +g mode (server side ignore).
+                  -Hwy-LL- *** I've been informed you messaged me.
+
+Hwy-LL will see:  Client Hwy101 [wcampbel@admin.irc.monkie.org] is messaging
+                    you and you are +g
+
+The sender will receive the NOTICE from the target of the message, while
+the recipient will receive the NOTICE from the server.
+
+--
+
+If Hwy101 sends another message to Hwy-LL (before the minute expires), he will
+see:  -Hwy-LL- *** I'm in +g mode (server side ignore).
+and will not receive the second notice
+
+Hwy-LL will NOT see any notice.
+
+--
+
+Hwy-LL now wishes to see messages from Hwy101 and SpamBot
+
+Client Hwy-LL:  /accept Hwy101,SpamBot
+
+Neither side will be told of the change in the accept list, Hwy-LL should
+presume that the accept was succesful if no error occurs.
+
+Now Hwy-LL can see messages from Hwy101 and SpamBot without any blockage.
+If Hwy101 was also set +g, then he would have to issue /accept Hwy-LL
+before he would be able to see messages from Hwy-LL.
+
+--
+
+Hwy-LL now wants to see who is on his accept list.
+
+Client Hwy-LL:  /accept *
+
+Hwy-LL will see:
+  irc.server 281 Hwy-LL Hwy101 SpamBot
+  irc.server 282 Hwy-LL :End of /ACCEPT list
+
+The replies are in numeric form to help parsing by scripts.
+--
+
+Hwy-LL realises he added a spambot to his list, and wants to remove it, and
+allow messages from services
+
+Client Hwy-LL:  /accept -SpamBot,services
+
+Hwy-LL will now only accept messages from Hwy101 and services.
+
+--
+
+The nicks to be added can be in ANY order, however you cannot add or remove
+AND list.  
+    /ACCEPT x,y,-z,f,-a would be acceptable.
+    /ACCEPT x,y,-z,* would ignore the * and generate an invalid nick
+                     response.
+
+Like Dalnet and Undernet's SILENCE system, the accept list only exists while
+you are connected to IRC.  In order for you to have the same accept list
+every time you come onto IRC, you must put the accept commands into your 
+client's auto-perform, or manually issue the commands each time.  
+
+This system may seem similar to the SILENCE system, but it is actually a
+reverse SILENCE.  SILENCE ignores certain users and allows the rest.  Mode
++g ignores all users except certain ones (on your accept list.)  Both systems
+have their place, but the mode +g in Hybrid 7 is what the developers thought
+would be most useful for clients.
+
+The goals of this user mode is to provide protection from flooding and
+spamming, and to provide users with a means to keep their privacy.
+
+We hope that these goals are obtained.
+
+--
+W. Campbell
+$Id: modeg.txt 6 2005-09-10 01:02:21Z nenolod $
diff --git a/doc/modes.txt b/doc/modes.txt
new file mode 100644 (file)
index 0000000..e51c1c9
--- /dev/null
@@ -0,0 +1,10 @@
+Standard user modes are listed in help/opers/umode
+Standard server notice masks are listed in help/opers/snomask
+Standard channel modes are listed in help/opers/cmode
+
+The sgml docs have more detailed descriptions.
+
+User mode +h (hide hostname) is provided by contrib/ip_cloaking.so
+Server notice mask +F (far connects) is provided by contrib/sno_farconnect.so
+
+# $Id: modes.txt 996 2006-03-09 01:14:34Z jilles $
diff --git a/doc/monitor.txt b/doc/monitor.txt
new file mode 100644 (file)
index 0000000..d99889f
--- /dev/null
@@ -0,0 +1,111 @@
+MONITOR - Protocol for notification of when clients become online/offline
+             Lee Hardy <lee -at- leeh.co.uk>
+$Id: monitor.txt 6 2005-09-10 01:02:21Z nenolod $
+-------------------------------------------------------------------------
+
+Currently, ISON requests by clients use a large amount of bandwidth.  It is
+expected that it is more efficient for this to be done by the server at the 
+expense of cpu cycles.  The WATCH implementation that was designed to counter 
+this is (in my opinion) severely flawed.  This protocol was designed to 
+provide a cleaner implementation.
+
+The command used throughout this specification is "MONITOR".
+
+Each use of the MONITOR command takes a special modifier, indicating
+the operation being performed.  The client MUST NOT attempt to specify
+more than one modifier.  Only one special modifier may be used per MONITOR
+command.
+
+Thus it is impossible to combine additions to the list with removals from
+the list -- these MUST be done with two seperate commands.
+
+A client MUST NOT issue the MONITOR command more than once per second.
+Any attempts to do so will generate an error.
+
+In commands and numerics where multiple nicknames may occur, the length of
+the nickname list is limited only by the buffer size of 512 chars, as
+defined in RFC1459.
+
+Support of this specification is indicated by the MONITOR token in
+RPL_ISUPPORT (005).  This token takes an optional parameter, of the maximum
+amount of nicknames a client may have in their monitor list.  If no
+parameter is specified, there is no limit.  A typical token would be:
+MONITOR=100
+
+MONITOR + nick[,nick2]*
+-----------------------
+Adds the given list of nicknames to the list of nicknames being monitored.
+
+If any of the nicknames being added are online, the server will generate
+RPL_MONONLINE numerics listing those nicknames that are online.
+
+If any of the nicknames being added are offline, the server will generate
+RPL_MONOFFLINE numerics listing those nicknames that are offline.
+
+MONITOR - nick[,nick2]*
+-----------------------
+Removes the given list of nicknames from the list of nicknames being
+monitored.  No output will be returned for use of this command.
+
+MONITOR C
+---------
+Clears the list of nicknames being monitored.  No output will be returned
+for use of this command.
+
+MONITOR L
+---------
+Outputs the current list of nicknames being monitored.  All output will use
+RPL_MONLIST, and the output will be terminated with RPL_ENDOFMONLIST
+
+MONITOR S
+---------
+Outputs for each nickname in the list being monitored, whether the client is
+online or offline.  All nicks that are online will be sent using 
+RPL_MONONLINE, all nicks that are offline will be sent using RPL_MONOFFLINE.
+The list will be terminated with RPL_ENDOFMONLIST.
+
+
+Numeric replies
+---------------
+
+730 - RPL_MONONLINE
+-------------------
+:<server> 730 <nick> :nick!user@host[,nick!user@host]*
+
+This numeric is used to indicate to a client that either a nickname has just
+become online, or that a nickname they have added to their monitor list is
+online.
+
+731 - RPL_MONOFFLINE
+--------------------
+:<server> 731 <nick> :nick[,nick1]*
+
+This numeric is used to indicate to a client that either a nickname has just
+left the irc network, or that a nickname they have added to their monitor
+list is offline.
+
+The argument is a chained list of nicknames that are offline.
+
+732 - RPL_MONLIST
+-----------------
+:<server> 732 <nick> :nick[,nick1]*
+
+This numeric is used to indicate to a client the list of nicknames they have
+in their monitor list.
+
+733 - RPL_ENDOFMONLIST
+------------------------
+:<server> 733 <nick> :End of MONITOR list
+
+This numeric is used to indicate to a client the end of a monitor list.
+
+734 - ERR_MONLISTFULL
+---------------------
+:<server> 734 <nick> <limit> <nicks> :Monitor list is full.
+
+This numeric is used to indicate to a client that their monitor list is
+full, so the command failed.  The <limit> parameter is the maximum number of 
+nicknames a client may have in their list, the <nicks> parameter is the list
+of nicknames, as the client sent them, that cannot be added.
+
+
diff --git a/doc/old/Authors b/doc/old/Authors
new file mode 100644 (file)
index 0000000..0051d0b
--- /dev/null
@@ -0,0 +1,137 @@
+/************************************************************************
+ *   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.
+
+jarlek@ifi.uio.no added mail functions to irc.
+
+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>
diff --git a/doc/operguide.txt b/doc/operguide.txt
new file mode 100644 (file)
index 0000000..132d4df
--- /dev/null
@@ -0,0 +1,368 @@
+
+EFnet Oper Guide
+Last update: 02-21-2002
+Written and maintained by Riedel
+E-Mail: dennisv@vuurwerk.nl
+
+ 1.  Commands you should know about
+ 2.  The client of your choice
+ 3.  Your primary responsibilities
+ 4.  Re-routing
+ 4.1 Re-routing other servers and remote connects
+ 5.  Kills and klines
+ 6.  Kill and K-Line requests
+ 7.  Happy birthday!
+ 8.  Security
+ 9.  Know who your friends are
+10.  The TCM bot
+11.  Services 
+12.  G-Lines
+
+
+1. Commands you should know about
+
+  This is no longer covered here. IRCD-hybrid is changing too rapidly, so
+  this section would be outdated in no time ;) For an up-to-date version,
+  please download the latest hybrid at www.ircd-hybrid.org.
+
+
+2. The client of your choice
+
+  There are many IRC clients around for a wide variety of operating systems.
+  Being an IRC Operator doesn't *require* you to use a UNIX client, however
+  I personally prefer UNIX-based clients. If you're familiar with UNIX and
+  use UNIX for opering, I suggest ircII / epic. There are a lot of scripts
+  available for those two clients, and it's not that hard to write scripts
+  yourself to suite your needs. It is important that you know how to operate
+  your client, and familiarize yourself with the options and features. For
+  whatever client you chose this goes for any of them: You should be in
+  control of your client, instead of the client being in control of you.
+
+Resources :
+
+  www.mirc.co.uk       - mIRC (MS-Windows)
+  www.irchelp.org      - a variety of clients and scripts
+  ftp.blackened.com    - several UNIX based clients available
+
+
+3. Your primary responsibilities
+
+  As an IRC Operator, you're responsible for maintaining the server on a
+  real-time basis. You represent your server, and you represent the network.
+  Irresponsible / rude / offensive / stupid behavior may discredit your server
+  and the network. You should focus on the task you were chosen for...
+  maintainance.  Sounds simple, no? It means getting rid of users that abuse
+  the service, enforcing the server's policy and keeping the server linked.
+  Users will ask you questions, and expect you to know all the answers.. after
+  all, you're the oper!
+
+  Be prepared for users trying to fool you, sweet talk you into things you
+  don't want, lie and deceive. Most users are handling in good faith...
+  however, the abusers have learned how to manipulate opers. They have studied
+  the alien creature 'oper' for ages like biologists study animals. Be
+  paranoid, be curious and be suspicious. I can't stress the importancy of that
+  often enough.
+
+  Second priority has the network. You were not chosen to maintain the network
+  but you were chosen to maintain the server. However, you may want to be able
+  to reroute servers. If you see something broken, don't be afraid to fix it.
+  If you do, be sure you fix things and don't make it worse. Before you
+  step into routing, be sure you've familiarized yourself with the network's
+  topology, and be confident enough to perform such actions. (re)routing is
+  covered in the next chapter.
+
+  Opers on the network depend on a trusting relationship. You can usually take
+  the word from an oper. Other opers are considered -trusted-, however, there
+  are exceptions. Sometimes even opers lie to opers to get things done. Don't
+  be afraid to ask for proof of a certain statement, such as logs.
+  This doesn't mean you distrust the oper in question, but -you- and you alone
+  are responsible for your actions. You call the shots on your server, unless
+  your admin says otherwise.
+
+
+4. Re-routing
+
+  Re-routing is not hard, and it's not scary but it is important that you do it
+  right. The commands you'll use are SQUIT and CONNECT. First, a very simple
+  example. Let's say your server, irc.yourserver.com is lagged to it's uplink,
+  irc.uplink.com and you want to reroute your server. You have to think about
+  where you want your server to be linked, and you have to time your reroute.
+  An example topology :
+               
+irc.yourserver.com ---- irc.uplink.com
+                        |      |      \
+                        B      C      D
+                       / \
+                      E   F
+                         / \
+                        G   H --- O
+                      / | \ | \
+                     I  J K L  M
+                                \
+                                 N
+
+  In this case, you're uplinked by irc.uplink.com
+  irc.uplink.com also hubs B, C and D. Server B functions as hub for E and F;
+  F hubs G and H; H hubs L, M and O. G hubs I, J and K. M hubs N.
+  Your server is allowed to connect to server B, F and G. So you consider the
+  servers you're able to connect to. Is the lag caused by a server that uplinks
+  irc.uplink.com ? Use /stats ? irc.uplink.com to determine lag to the other
+  servers. If irc.uplink.com does not respond, the lag is to your uplink. If
+  so, you cannot be sure about the state of the other uplinks, so you'd have to
+  get on a remote server and determine lag by using /stats ? and /trace. For
+  example, you could connect to server N, and /trace yournick. Yournick, being
+  the nick on your server. You'll see which route it takes, and what the
+  problem server is. Example /trace output :
+
+S:[SERVER-N       ] V:[2.8/hybrid] U:[SERVER-M            ]
+S:[SERVER-M       ] V:[2.8/hybrid] U:[SERVER-H            ]
+S:[SERVER-H       ] V:[2.8/hybrid] U:[SERVER-F            ]
+S:[SERVER-F       ] V:[2.8/hybrid] U:[SERVER-B            ]
+S:[SERVER-B       ] V:[2.8/hybrid] U:[irc.uplink.com      ]
+S:[irc.uplink.com ] V:[2.8/hybrid] U:[irc.yourserver.com  ]
+
+  The trace doesn't complete... server-b announces irc.uplink.com, and
+  irc.uplink.com announces your server. Your server should return something
+  like :
+
+S:[irc.yourserver.] OPER [yournick!user@yourhost]
+
+  If it doesn't, we know the lag is only between yourserver and uplink.
+  Usually if there is lag between your server and your uplink, the send-queue
+  rises. This is not always the case. Sometimes your server can write perfectly
+  to your uplink, but not reverse. That is called one sided lag.
+
+  We pick server B to link to. It means we have to SQUIT and CONNECT.
+  To unlink from irc.uplink.com and connect to SERVER_B we'd type:
+  /quote SQUIT irc.uplink.com :reroute
+  /connect SERVER_B
+
+  we *DON'T* SQUIT irc.yourserver.com... and I'll try to explain why:
+  If we wanted to remove hub M from the network, and with it N, we'd issue
+  a SQUIT M. An SQUIT follows a path, relays the SQUIT request to each server
+  in that path. Finally it reaches server H, which is the hub for M. Server H
+  sees the SQUIT and drops the link to M.
+
+  Now a different situation, we want to separate yourserver, uplink, C and D
+  from the rest of the network, in order to reroute. We'd have to SQUIT server
+  B, since we want the -uplink- of server B (being irc.uplink.com) to drop the
+  link to server B.
+
+  If you'd SQUIT irc.yourserver.com, you ask yourserver.com to drop the link to
+  itself, which is impossible. If you SQUIT irc.uplink.com, you ask yourserver
+  to drop the link to uplink, which is what we want to do.
+
+  After the SQUIT and CONNECT, the new situation looks like this :
+
+                        irc.uplink.com
+                        |      |      \
+  irc.yourserver.com -- B      C      D
+                       / \
+                      E   F
+                         / \
+                        G   H --- O
+                      / | \ | \
+                     I  J K L  M
+                                \
+                                 N
+
+  If yourserver is a Hub, it makes the situation more complex, since your
+  actions have more impact.
+
+
+4.1 - Re-routing other servers and remote connects
+
+Example topology :
+
+                        irc.uplink.com
+                        |      |      \
+  irc.yourserver.com -- B      C      D
+                       / \
+                      E   F
+                         / \
+                        G   H --- O
+                      / | \ | \
+                     I  J K L  M
+                                \
+                                 N
+
+  Let's say, hub H is way lagged to F, but G to F is fine... we want to reroute
+  H, and stick H to G.
+
+  We'd do :
+
+  /quote SQUIT serverh :re-routing you babe
+  /connect serverh 6667 serverg
+
+  A global wallops will be sent :
+  !serverg! Remote CONNECT serverh 6667 from ItsMe
+
+  When re-routing, always give the server some time to prevent nick collides.
+  When there is lag, people will connect to another server. When you SQUIT and
+  CONNECT to fast, a lot of those clients will be collided. Also, stick to your
+  territory. How enthusiastic you may be, you cannot route the world. If you're
+  an oper on the US side, stick to the US side when re-routing. Needless to
+  say, if you're EU, keep it to EU ;)
+
+
+5. Kills and klines
+
+  As an oper, you're given the incredible power *cough* of KILL and KLINE.
+  /kill nick reason  disconnects a client from IRC with the specified reason.
+  A /quote kline *evil@*.dude.org :reason here  bans the user from your server.
+  Abusive kills and klines may draw attacks to your server, so always consider
+  if a kline or kill is deserved. If the server gets attacked after a valid
+  kill or kline, well.. tough luck. You should never be 'afraid' to kline
+  anyone on your server. If it's a good reason, make it so. Even if you know
+  it may cause the server to be attacked. Maybe good to think about is this:
+  - if /ignore solves the problem rather than a kick, /ignore
+  - kick if a ban is unneeded
+  - ban if a /kill is unwarranted for
+  - kill rather than kline if that solves the problem
+  - kline when a server ban is really needed.
+
+  You kline a user when you absolutely don't want this user to use the service
+  your server is providing.
+
+  Crosskills (killing users on another server) are another issue. Some admins
+  don't care if users get /kill'ed off their server, for any reason or no
+  reason at all... and other admins are very anal about it. A good way to go
+  (IMO) is to issue a KILL if there is an absolute need for the target user to
+  be disconnected. If there are active opers on that server, let them handle
+  it.  They'll be upset if you /kill a user off their server, without
+  contacting them.  /stats p irc.server.here shows the active opers on a
+  particular server. Some opers have multiple o-lines and are not watching all
+  sessions. If you can't find an active oper on a server, you can 
+  /quote operwall a request for opers from that server.
+
+  Ghost KILLs are another story, an often misunderstood one.
+  When you see a /KILL from an oper with the reason 'ghosted' they usually
+  KILL a client that's about to ping timeout. That is not what a ghost is!
+  To quote Dianora: "a ghost happens because a client misses being killed when
+  it should be. Its a race condition due to nick chasing". In other words,
+  Server X thinks client A has been KILLed, while server Y missed the KILL
+  for that client.
+
+
+6. Kill and K-Line requests
+
+  As previously mentioned, if an oper from another server contacts you and
+  requests a kill or a kline for a local client with a good reason, you can
+  usually trust this request. Opers depend on a trusting relationship. However,
+  since you're responsible for the kill or kline, it is not rude to ask for
+  proof. It depends on the oper making the request how thats interpreted, but
+  the way they respond to asking for proof tells more about them than about
+  you.
+
+  The more and longer you oper, how better you get to know the other opers.
+  You know who is honest, you'll know who are lying and deceiving. Before
+  you acquire this knowledge, you can merely rely on common sense and
+  instincts.  You'll probably make mistakes occasionally, and thats nothing to
+  be ashamed of.  Opers are - despite contrary believes - human.
+
+  Users occasionally will ask you to kill or kline a user/bot too. Some
+  requests are straight-forward and clear, others require you to be cautious. I
+  recommend to always investigate such requests, and when you're confident the
+  request is valid, issue the kill or kline.
+
+
+7. Happy birthday!
+
+  It is a custom on EFnet to birthday /kill opers of whom it is his/her
+  birthday.  Not all opers like this, but typically those opers don't let
+  others know about their birthday. You'll notice that the KILLS say a lot
+  about who likes who and who is friends with who.  Whether you want to
+  participate, is entirely up to you.
+
+
+8. Security
+
+  As with any privilege, you have to handle it cautiously and responsibly.
+  Be sure that your o/O line doesn't get compromised! Oper only from secure
+  hosts. You and only you should know your password. Don't share your oper
+  account, and make your oper password a UNIQUE one. If your o/O line gets
+  compromised, nasty things may/will happen. Imagine an oper with crosskill
+  capabilities who's operline gets 'hacked'... the results are often
+  disastrous and you will lose respect and trust from others. It can cause
+  your oper privileges to be revoked, or even the server to be (temporarily)
+  delinked.
+
+
+9. Know who your friends are
+
+  As an oper you will get a lot of users that want to be 'friends' with you.
+  Users offer you free* access to their *nix servers, ops in channels,
+  unlimited leech access to the biggest and fastest warez sites *gasp* and
+  more. They want favors in return. They say they don't but they truly want
+  something in return. They -expect- something in return. You could either
+  don't respond to such offers, or use them. The last option creates an even
+  more distorted image of opers and doesn't do any good for the user <-> oper
+  relationship.  Your *real* friends are usually the persons who were your
+  friends _before_ you acquired the extra privileges.
+
+
+10. The TCM Bot
+
+  A TCM bot can be a valuable tool for opers. It keeps record of all connected
+  clients, flags clients with multiple connections and has all sorts of other
+  useful commands. There are three different kind of TCM's in use on EFnet,
+  being OOMon, TCM-Dianora and TCM-Hybrid. Every one of them requires you to
+  log in to be able to access the privileged commands. On OOMon you DCC chat
+  the TCM bot and do '.auth yournick yourpass' where yournick is your oper
+  name in your o/O line. In TCM-Dianora and TCM-Hybrid you register with:
+  '.register yourpass', where yourpass is your password ;)
+  All TCM commands start with a period. If you forget the period, the text goes
+  into the 'partyline', where it is echoed to all connected opers.
+
+  Resources :  http://toast.blackened.com/oomon/help
+               http://www.db.net/~db/tcm.html
+
+
+11. Services
+
+  A recent addition to EFNet is Channel Fixer, aka ChanFix. This is an
+  automated service that re-ops clients on opless channels. There are a few
+  restrictions.  First, the channel has to be of significant size for ChanFix
+  to store it in its database. Second, it only logs static addresses.
+
+  How does it work? Periodically it stores information about the channel state
+  in its database, for every channel in there. On every 'run', a channel
+  operator gets one point. These scores make a top-5 of 'most frequent opped
+  clients'.  When a channel becomes opless, ChanFix will join and op the top-5
+  opped clients CURRENTLY IN THE CHANNEL.
+
+  Chanfix can be invoked manually by server administrators. /msg ChanFix
+  chanfix #channel is the command to do it. ChanFix will join, and treat the
+  channel as if it were opless. It lowers TS by one (resulting in a deop of
+  the entire channel) and re-ops the top-5 clients currently in the channel.
+  The Channel Fixer won't log or actively fix channels when there's a split of
+  significant size.  Needless to say, the chanfix command must be used with
+  caution.
+
+
+12. G-Lines
+
+  Oh yes! A G-Line section. Currently, a part of EFNet (EU-EFnet) has G-Lines
+  enabled. This was decided by the EU admin community and is now mandatory
+  within EU-EFnet. In order for a G-Line to be activated, three opers from
+  three different servers need to issue the _exact_ same G-Line. The reason
+  is not counted.
+
+  G-Lines work best when the EU side of EFNet is not fragmented. G-Lines
+  will, however, propogate through a Hybrid 6 hub (but not a CSr hub) even
+  if the hub server has G-Lines disabled. This propogation allows two halves
+  of EU-EFnet to have concurrent G-Lines set even when split by US hub servers.
+
+
+  Questions / Comments / Suggestions are welcome.
+  You can e-mail me: dennisv@vuurwerk.nl
+
+Best regards,
+--
+Dennis "Riedel" Vink       ___~___  Email - dennisv@vuurwerk.nl
+Unix System Administrator  \  |  /  Phone - +31 23 5111111
+Vuurwerk Internet           '|.|'   PGP   - 0xD68A7AAB
+
+And on the seventh day, He exited from append mode.
+
+# $Id: operguide.txt 6 2005-09-10 01:02:21Z nenolod $
diff --git a/doc/opermyth.txt b/doc/opermyth.txt
new file mode 100644 (file)
index 0000000..ef6b637
--- /dev/null
@@ -0,0 +1,137 @@
+
+Date: Thu, 30 Jul 1998 16:21:40-0700 (MST)
+To: operlist@the-project.org
+From: rayp@primenet.com (Ray Powers)
+Subject: The myths of opers....
+
+I've always wanted to write something like this.. Its half rant, half
+fact, so bear with it. Hopefully it will be worth reading.
+
+There's a lot of hate for opers for a lot of reasons. Some are directly
+oper related (i.e. 99% of us are colossal assholes), some are directly
+user related (i.e. 99% of you are raving lunatics), and some is just plain
+misconceptions. I'd like to take a minute to talk about part three in
+hopes of clearing a few things up. This will kind of be in a FAQ form,
+maybe you'll like it,  maybe not, but its worth a shot.
+
+Q: What can an oper on EFnet do.
+A: This is an EXACT list of what we can do:
+        1) /squit a server, separating it from the rest of the net
+        2) /die our server
+        3) /kill a user, this disconnects them from the server they are on
+        4) /kline a hostmask, this bans them from our server
+        5) /dline an ip, this bans them from our server, regardless of 
+           hostmask
+        6) See all invisible users on our server
+        7) Mass Msg/CTCP/notice a hostmask
+        8) Mass Msg/CTCP/notice a server
+        9) See and send Operwall/wallops notices
+
+That's it. We can see more server messages than you, but that's not the
+point.. The point to be shown here is very simple, *none* of these things
+have anything to do with channels. Which leads us to our next question.
+
+Q: What can opers *NOT* do, but keep being asked to anyways?
+A: We can *NOT*:
+        1) Enter a channel that is +i or +k without being invited or 
+           having the key
+        2) See who is inside a +s channel  
+        3) Op ourselves or op you on a channel (unless of course we are a 
+           channel op for that channel)
+        4) Tell you what XXXX's new nick is since they changed it to hide 
+           from you.
+        5) Deop someone for you on a channel (unless of course we are a 
+           channel op for that channel)
+
+Notice a trend, with the exception of 4, all of these are 100% channel
+related. EFnet is made so that opers have *NO* power of channels, for
+better or worse. If we don't help you with these requests, its not because
+we won't, its because we are completely incapable doing so. On the other
+hand....
+
+Q: What can opers do, but won't?
+A: This will be a bit differently done, because I figure I should explain 
+   why opers don't do these things, when they may normally make sense.
+        1) Why won't they kill somebody who has stolen your nick.
+              EFnet has gone on the basis of nicks not being owned, which is 
+           why there is no nickserv on EFnet.  Of course we see opers kill 
+           all the time for nicks, though, so it seems rather hypocrital, 
+           doesn't it?  
+              An oper who kills for his nick will tell you its because the 
+           other person was a bot, was juping his nick, or was imitating an 
+           oper.  It may be true, but it really comes down to the same 
+           feeling you get when your nick is taken "Hey! that's my name! I 
+           don't want that person using my name!" 
+              I personally, do not kill for nicks. If someone takes my nick, 
+           they can have it. Let them get my several hundred messages a day. 
+           :P  But the problem with the oper is this: How does an oper know 
+           that you are really the person that uses that nick, or are you 
+           the guy that wants to nick jupe that nick out from the real guy? 
+           Unless the oper knows you well, they don't.. And saying that 
+           people generally tell the truth means you haven't been on EFnet 
+           very long. 
+              I would prefer to think I am one of the more well respected 
+           people on the net and people still lie to me on a regular basis. 
+           So, the oper is stuck refusing to help because he can't tell who 
+           is who. Remember this line of reasoning, its going to be coming 
+           up a lot. :P
+        2) Why won't they kill that guy nuking/smurfing/ping -f'ing me?
+              This one is simple.  There is no way to prove that somebody is 
+           doing any of these things to you from an opers point of view. All 
+           logs are fakeable, and the oper has no way to firsthand prove its 
+           happening. Your best bet in this situation is to log what you can 
+           and complain loud and long to their ISPs.
+        3) Why won't they help me take my channel back?
+              There's a bunch of answers to this. First, it is popular 
+           opinion at EFnet that channels are not owned, and therefore, if 
+           you lose a channel, you should go make another one.  Notice I 
+           say popular instead of official, because EFnet has never had an 
+           "official" policy on much of anything. 
+              But more and more you see opers killing for takeovers, so why 
+           are they helping their channels and not yours.  
+              Well, first, let's say your channel was taken over, and is now 
+           +smtinlk. How exactly is the oper supposed to find out who is 
+           oped in the channel right now to mass kill them? Even if they do get 
+           all the nicks, they have to somehow manage to kill them all in 
+           one hit, or they'll all just op each other again and it will be 
+           fruitless. Or worse, they could have it all set up, and some 
+           other oper could kill them halfway through because they don't 
+           like mass-kills and it would be all ruined. 
+              Or, let's say the mass-kill goes off, then the channel is 
+           opless and generally speaking, chaos begins. People start 
+           mass-nuking or flooding the channel to clear it out, or just to 
+           be annoying. And there's still a 50/50 chance that takeover
+           people will get the channel back on a split and we'll have to try 
+           to do it all over again.  
+              If you're about to ask why they don't split their server,
+           the answer is very simple: We are not about to screw up roughly 
+           30,000 peoples chatting for your channel. Its rude. This of 
+           course is all based on the fact that we can prove its taken over, 
+           as per the conversation about nicks, we often can't.
+        4) But.. its obvious they took it from me! The topic says 
+           "Ha ha, we took your channel Rick!" for Pete's sake! And 
+           there's only One op, so you can kill him and get the channel 
+           back immediately!
+              This one is a bit more complex, but its really a personal 
+           call. That one op could be a rampant smurfpup with a penis so 
+           tiny he has no choice but to rampantly smurf and synflood anyone 
+           that gets in his way.  This is popularly known on irc as SPS, or 
+           Small Penis Syndrome.  In this case, if the oper does help you 
+           out, they could end up with their server being downed for a day 
+           or two, and it really isn't worth it for your channel, no 
+           offense.
+
+Keep in mind that this is all spoken from the perspective of someone who
+*DOES* help with channels when possible, but understands greatly the
+reasons not to, and judges each situation very carefully.
+
+That's the gist of the information I was trying to get across.  If you
+were cluefull enough to get on operlist, a lot of this may be common
+knowledge to you, but sometimes its good to step back and see why opers do
+what they do a lot of the time. 
+
+Hoping this is of value to SOMEONE....
+
+Ray Powers
+Monkster/MimePunk/PrimeMonk/PacMonk/MtgMonk/Ihavefartoomanynickstonickjupe
+
diff --git a/doc/reference.conf b/doc/reference.conf
new file mode 100755 (executable)
index 0000000..6fcb82e
--- /dev/null
@@ -0,0 +1,1122 @@
+/* doc/reference.conf - charybdis Example configuration file
+ *
+ * Copyright (C) 2000-2002 Hybrid Development Team
+ * Copyright (C) 2002-2005 ircd-ratbox development team
+ * Copyright (C) 2005-2006 charybdis development team
+ *
+ * Written by ejb, wcampbel, db, leeh and others
+ *
+ * $Id: reference.conf 3131 2007-01-21 15:36:31Z jilles $
+ */
+
+/* IMPORTANT NOTES:
+ *
+ * class {} blocks MUST be specified before anything that uses them.  That
+ * means they must be defined before auth {} and before connect {}.
+ *
+ * auth {} blocks MUST be specified in order of precedence.  The first one
+ * that matches a user will be used.  So place spoofs first, then specials,
+ * then general access, then restricted.
+ *
+ * Both shell style (#) and C style comments are supported.
+ *
+ * Files may be included by either:
+ *        .include "filename"
+ *        .include <filename>
+ *
+ * Times/durations are written as:
+ *        12 hours 30 minutes 1 second
+ *        
+ * Valid units of time:
+ *        month, week, day, hour, minute, second
+ *
+ * Valid units of size:
+ *        megabyte/mbyte/mb, kilobyte/kbyte/kb, byte
+ *
+ * Sizes and times may be singular or plural.  
+ */ 
+
+/* Extensions:
+ *
+ * Charybdis contains several extensions that are not enabled by default.
+ * To use them, uncomment the lines below.
+ *
+ * Restrict channel creation to logged in users   -- createauthonly.so
+ * Account bans (+b $a[:mask])                    -- extb_account.so
+ * Banned from another channel (+b $j:mask)       -- extb_canjoin.so
+ * Other-channel bans (+b $c:mask)                -- extb_channel.so
+ * Extended ban (+b $x:mask)                      -- extb_extgecos.so
+ * Oper bans (+b $o)                              -- extb_oper.so
+ * Realname (gecos) bans (+b $r:mask)             -- extb_realname.so
+ * Server bans (+b $s:mask)                       -- extb_server.so
+ * HURT system                                    -- hurt.so
+ * Host mangling (umode +h)                       -- ip_cloaking.so
+ * Find channel forwards                          -- m_findforwards.so
+ * /identify support                              -- m_identify.so
+ * Opers cannot be invisible (umode +i)           -- no_oper_invis.so
+ * Far connection notices (snomask +F)            -- sno_farconnect.so
+ * Remote k/d/g/x line active notices             -- sno_globalkline.so
+ * Remote oper up notices                         -- sno_globaloper.so
+ */
+#loadmodule "extensions/createauthonly.so";
+#loadmodule "extensions/extb_account.so";
+#loadmodule "extensions/extb_canjoin.so";
+#loadmodule "extensions/extb_channel.so";
+#loadmodule "extensions/extb_extgecos.so";
+#loadmodule "extensions/extb_oper.so";
+#loadmodule "extensions/extb_realname.so";
+#loadmodule "extensions/extb_server.so";
+#loadmodule "extensions/hurt.so";
+#loadmodule "extensions/ip_cloaking.so";
+#loadmodule "extensions/m_findforwards.so";
+#loadmodule "extensions/m_identify.so";
+#loadmodule "extensions/no_oper_invis.so";
+#loadmodule "extensions/sno_farconnect.so";
+#loadmodule "extensions/sno_globalkline.so";
+#loadmodule "extensions/sno_globaloper.so";
+/* serverinfo {}:  Contains information about the server. (OLD M:) */
+serverinfo {
+       /* name: the name of our server */
+       name = "hades.arpa";
+
+       /* use ts6: whether we want to use the TS6 protocol to other servers
+        * or not.
+        */
+       use_ts6 = yes;
+
+       /* sid: the unique server id of our server.  This must be three
+        * characters long.  The first character must be a digit [0-9], the
+        * remaining two chars may be letters [A-Z] or digits [0-9].
+        *
+        * This must be specified even if use_ts6 is set to no.
+        */
+       sid = "42X";
+
+       /* description: the description of our server.  '[' and ']' may not
+        * be used here for compatibility with older servers.
+        */
+       description = "charybdis test server";
+
+       /* network info: the name and description of the network this server
+        * is on.  Shown in the 005 reply and used with serverhiding.
+        */
+       network_name = "MyNet";
+       network_desc = "This is My Network";
+
+       /* hub: allow this server to act as a hub and have multiple servers
+        * connected to it.  
+        */
+       hub = no;
+
+       /* vhost: the IP to bind to when we connect outward to ipv4 servers.
+        * This should be an ipv4 IP only.
+        */
+       #vhost = "192.169.0.1";
+
+       /* vhost6: the IP to bind to when we connect outward to ipv6 servers.
+        * This should be an ipv6 IP only.
+        */
+       #vhost6 = "3ffe:80e8:546::2";
+};
+
+/* admin {}: contains admin information about the server. (OLD A:) */
+admin {
+       name = "Smurf target";
+       description = "Main Server Administrator";
+       email = "<syn@packets.r.us>";
+};
+
+/* log {}: contains information about logfiles. */
+log {
+       /* logfiles: the logfiles to use for specific activity.  if these
+        * paths are defined, then ircd will log to them, otherwise it wont.
+        *
+        * The confs are, in order:
+        * - userlog:    user exits
+        * - fuserlog:   failed user connections
+        * - operlog:    /oper usage
+        * - foperlog:   failed /oper usage
+        * - serverlog:  server connects/disconnects
+        * - glinelog:   glines
+        * - klinelog:   klines, etc
+        * - killlog:    kills
+        * - operspylog: operspy usage
+        * - ioerrorlog: IO errors
+        */
+       fname_userlog = "logs/userlog";
+       #fname_fuserlog = "logs/fuserlog";
+       fname_operlog = "logs/operlog";
+       #fname_foperlog = "logs/foperlog";
+       fname_serverlog = "logs/serverlog";
+       fname_glinelog = "logs/glinelog";
+       #fname_klinelog = "logs/klinelog";
+       fname_killlog = "logs/killlog";
+       fname_operspylog = "logs/operspylog";
+       #fname_ioerrorlog = "logs/ioerror";
+};
+
+/* class {}: contain information about classes for users (OLD Y:) */
+class "users" {
+       /* class name must go above */
+
+       /* ping time: how often a client must reply to a PING from the
+        * server before they are dropped.
+        */
+       ping_time = 2 minutes;
+
+        /* number per ident: the number of users per user@host networkwide
+         * allowed to connect.  Unidented connections are classified as
+         * the same ident.
+         */
+        number_per_ident = 2;
+
+       /* number per ip: the number of local users per host allowed */
+       number_per_ip = 3;
+
+        /* number per ip global: the number of network wide connections
+         * per host allowed for a user, including connections to the
+         * local server.
+         */
+        number_per_ip_global = 5;
+
+       /* cidr_bitlen:  Limits numbers of connections from a subnet size
+        * the following example makes the subnet /64 this is useful
+        * for IPv6 connections in particular
+        * Also note that the way charybdis is written if you have
+        * compiled support for IPv6, IPv4 cidr bitlens need to be modified
+        * Basically to get the approriate length add 96 to the IPv4 length
+        * For example for a /24 do 96+24 = 120
+        *
+        */
+       cidr_bitlen = 64;
+
+       /* number_per_cidr:  Number of connections to allow from a subnet of the 
+        * size given in cidr_bitlen.  4 seems to be a good default to me.
+        */
+       number_per_cidr = 4;
+
+       /* max number: the maximum number of users allowed in this class */
+       max_number = 100;
+
+       /* sendq: the amount of data allowed in a clients queue before
+        * they are dropped.
+        */
+       sendq = 100 kbytes;
+};
+
+class "restricted" {
+       ping_time = 1 minute 30 seconds;
+       number_per_ip = 1;
+       max_number = 100;
+       sendq = 60kb;
+};
+
+class "opers" {
+       ping_time = 5 minutes;
+       number_per_ip = 10;
+       max_number = 100;
+       sendq = 100kbytes;
+};
+
+class "server" {
+       ping_time = 5 minutes;
+
+       /* connectfreq: only used in server classes.  specifies the delay
+        * between autoconnecting to servers.
+        */
+       connectfreq = 5 minutes;
+
+       /* max number: the amount of servers to autoconnect to */
+       max_number = 1;
+
+       /* sendq: servers need a higher sendq as they are sent more data */
+       sendq=2 megabytes;
+};
+
+/* listen {}: contain information about the ports ircd listens on (OLD P:) */
+listen {
+       /* port: the specific port to listen on.  if no host is specified
+        * before, it will listen on all available IPs.
+        *
+        * ports are seperated via a comma, a range may be specified using ".."
+        */
+       
+       /* port: listen on all available IPs, ports 5000 and 6665 to 6669 */
+       port = 5000, 6665 .. 6669;
+
+       /* host: set a specific IP/host the ports after the line will listen 
+        * on.  This may be ipv4 or ipv6.
+        */
+       host = "1.2.3.4";
+       port = 7000, 7001;
+
+       host = "3ffe:1234:a:b:c::d";
+        port = 7002;
+};
+
+/* auth {}: allow users to connect to the ircd (OLD I:) */
+auth {
+       /* user: the user@host allowed to connect.  multiple IPv4/IPv6 user 
+        * lines are permitted per auth block.
+        */
+       user = "*@172.16.0.0/12";
+       user = "*test@123D:B567:*";
+
+       /* password: an optional password that is required to use this block.
+        * By default this is not encrypted, specify the flag "encrypted" in
+        * flags = ...; below if it is.
+        */
+       password = "letmein";
+       
+       /* spoof: fake the users user@host to be be this.  You may either
+        * specify a host or a user@host to spoof to.  This is free-form,
+        * just do everyone a favour and dont abuse it. (OLD I: = flag)
+        */
+        spoof = "I.still.hate.packets";
+
+       /* Possible flags in auth:
+        * 
+        * encrypted                  | password is encrypted with mkpasswd
+        * spoof_notice               | give a notice when spoofing hosts
+        * exceed_limit (old > flag)  | allow user to exceed class user limits
+        * kline_exempt (old ^ flag)  | exempt this user from k/g/xlines&dnsbls
+        * dnsbl_exempt               | exempt this user from dnsbls
+        * gline_exempt (old _ flag)  | exempt this user from glines
+        * spambot_exempt             | exempt this user from spambot checks
+        * shide_exempt               | exempt this user from serverhiding
+        * jupe_exempt                | exempt this user from generating
+        *                              warnings joining juped channels
+        * resv_exempt                | exempt this user from resvs
+         * flood_exempt               | exempt this user from flood limits
+         *                                     USE WITH CAUTION.
+        * no_tilde     (old - flag)  | don't prefix ~ to username if no ident
+        * need_ident   (old + flag)  | require ident for user in this class
+        * need_sasl                  | require SASL id for user in this class
+        */
+       flags = kline_exempt, exceed_limit;
+       
+       /* class: the class the user is placed in */
+       class = "opers";
+};
+
+auth {
+       /* redirect: the server and port to redirect a user to.  A user does
+        * not have to obey the redirection, the ircd just suggests to them
+        * an alternative server.
+        */
+       redirserv = "irc.some.domain";
+       redirport = 6667;
+       
+       user = "*.some.domain";
+
+       /* class: a class is required even though it is not used */
+       class = "users";
+};
+
+auth {
+       user = "*@*";
+       class = "users";
+       
+       flags = need_ident;
+};
+
+/* operator {}: defines ircd operators. (OLD O:)
+ * charybdis no longer supports local operators, privileges are
+ * controlled via flags.
+ */
+operator "god" {
+       /* name: the name of the oper must go above */
+
+       /* user: the user@host required for this operator.  CIDR *is*
+        * supported now. auth{} spoofs work here, other spoofs do not.
+        * multiple user="" lines are supported.
+        */
+       user = "*god@*";
+       user = "*@127.0.0.1";
+
+       /* password: the password required to oper.  Unless ~encrypted is
+        * contained in flags = ...; this will need to be encrypted using 
+        * mkpasswd, MD5 is supported
+        */
+       password = "etcnjl8juSU1E";
+
+       /* rsa key: the public key for this oper when using Challenge.
+        * A password should not be defined when this is used, see 
+        * doc/challenge.txt for more information.
+        */
+       #rsa_public_key_file = "/usr/local/ircd/etc/oper.pub";
+
+       /* umodes: the specific umodes this oper gets when they oper.
+        * If this is specified an oper will not be given oper_umodes
+        * These are described above oper_only_umodes in general {};
+        */
+       #umodes = locops, servnotice, operwall, wallop;
+
+       /* snomask: specific server notice mask on oper up.
+        * If this is specified an oper will not be given oper_snomask.
+        */
+       snomask = "+Zbfkrsuy";
+
+       /* privileges: controls the activities and commands an oper is
+        * allowed to do on the server.  You may prefix an option with ~ to
+        * disable it, ie ~operwall
+        *
+        * Default flags are operwall, remoteban and encrypted.
+        *
+        * Available options:
+        *
+        * encrypted:    the password above is encrypted [DEFAULT]
+        * local_kill:   allows local users to be /KILL'd
+        * global_kill:  allows local and remote users to be 
+        *               /KILL'd                           (OLD 'O' flag)
+        * remote:       allows remote SQUIT and CONNECT   (OLD 'R' flag)
+        * kline:        allows KILL, KLINE and DLINE      (OLD 'K' flag)
+        * unkline:      allows UNKLINE and UNDLINE        (OLD 'U' flag)
+        * gline:        allows GLINE                      (OLD 'G' flag)
+        * nick_changes: allows oper to see nickchanges    (OLD 'N' flag)
+        *               via usermode +n
+        * rehash:       allows oper to REHASH config      (OLD 'H' flag)
+        * die:          allows DIE and RESTART            (OLD 'D' flag)
+        * admin:        gives admin privileges.  admins
+        *               may (un)load modules and see the
+        *               real IPs of servers.
+        * hidden_admin: gives admin privileges except
+        *               will not have the admin lines in
+        *               stats p and whois.
+        * xline:        allows use of /quote xline/unxline
+        * operwall:     allows the oper to send operwalls [DEFAULT]
+        * oper_spy:     allows 'operspy' features to see through +s
+        *               channels etc. see /quote help operspy
+        * hidden_oper:  hides the oper from /stats p    (OLD UMODE +p) 
+        * remoteban:    allows remote kline etc [DEFAULT]
+         */
+       flags = global_kill, remote, kline, unkline, gline,
+               die, rehash, admin, xline, operwall;
+};
+
+/* connect {}: controls servers we connect to (OLD C:, N:, H:, L:) */
+connect "irc.uplink.com" {
+       /* the name must go above */
+
+       /* host: the host or IP to connect to.  If a hostname is used it
+        * must match the reverse dns of the server.
+        */
+       host = "192.168.0.1";
+
+       /* vhost: the host or IP to bind to for this connection.  If this
+        * is not specified, the default vhost (in serverinfo {}) is used.
+        */
+       #vhost = "192.168.0.50";
+
+       /* passwords: the passwords we send (OLD C:) and accept (OLD N:).
+        * The remote server will have these passwords reversed.
+        */
+       send_password = "password";
+       accept_password = "anotherpassword";
+
+       /* port: the port to connect to this server on */
+       port = 6666;
+
+       /* hub mask: the mask of servers that this server may hub. Multiple
+        * entries are permitted
+        */
+       hub_mask = "*";
+
+       /* leaf mask: the mask of servers this server may not hub.  Multiple
+        * entries are permitted.  Useful for forbidding EU -> US -> EU routes.
+        */
+       #leaf_mask = "*.uk";
+
+       /* class: the class this server is in */
+       class = "server";
+
+       /* flags: controls special options for this server
+        * encrypted    - marks the accept_password as being crypt()'d
+        * autoconn     - automatically connect to this server
+        * compressed   - compress traffic via ziplinks
+        * topicburst   - burst topics between servers
+        */
+       flags = compressed, topicburst;
+};
+
+connect "ipv6.some.server" {
+        host = "3ffd:dead:beef::1";
+        send_password = "password";
+        accept_password = "password";
+        port = 6666;
+
+       /* aftype: controls whether the connection uses "ipv4" or "ipv6".
+        * Default is ipv4.
+        */
+       aftype = ipv6;
+        class = "server";
+};
+
+/* cluster {}; servers that we propagate things to automatically.
+ * NOTE: This does NOT grant them privileges to apply anything locally,
+ *       you must add a seperate shared block for that.  Clustering will
+ *       only be done for actions by LOCAL opers, that arent directed
+ *       remotely.
+ */
+cluster {
+       /* name: the server to share with, this can be a wildcard and may be
+        * stacked.
+        */
+       /* flags: list of what to share, all the name lines above this (up
+        * until another flags entry) will receive these flags.
+        *
+        *    kline   - share perm klines
+        *    tkline  - share temp klines
+        *    unkline - share unklines
+        *    locops  - share locops
+        *    xline   - share perm xlines
+        *    txline  - share temp xlines
+        *    unxline - share unxlines
+        *    resv    - share perm resvs
+        *    tresv   - share temp resvs
+        *    unresv  - share unresvs
+        *    all     - share all of the above
+        */
+
+       /* share klines/unklines/xlines with *.lan */
+       name = "*.lan";
+       flags = kline, unkline, xline;
+
+       /* share locops with irc.ircd-ratbox.org and ircd.ircd-ratbox.org */
+       name = "irc.ircd-ratbox.org";
+       name = "ircd.ircd-ratbox.org";
+       flags = locops;
+};
+
+/* service{}: privileged servers (services). These servers have extra
+ * privileges such as setting login names on users and introducing clients
+ * with umode +S (unkickable, hide channels, etc). This does not allow them
+ * to set bans, you need a separate shared{} for that.
+ * Do not place normal servers here.
+ * There may be only one service{} block.
+ */
+service {
+       /* name: the server name. These may be stacked. */
+       name = "services.int";
+};
+
+/* shared {}: users that are allowed to place remote bans on our server.
+ * NOTE: These are ordered top down.  The first one the user@host and server
+ *       matches will be used.  Their access will then be decided on that
+ *       block and will not fall back to another block that matches.
+ */
+shared {
+       /* oper: the user@host and server the user must be on to set klines.
+        * The first field must be a user@host, the second field is an
+        * optional server.  These may be stacked.
+        */
+       /* flags: list of what to allow them to place, all the oper lines
+        * above this (up until another flags entry) will receive these
+        * flags.  This *must* be present.
+        *
+        *    kline   - allow setting perm/temp klines
+        *    tkline  - allow setting temp klines
+        *    unkline - allow removing klines
+        *    xline   - allow setting perm/temp xlines
+        *    txline  - allow setting temp xlines
+        *    unxline - allow removing xlines
+        *    resv    - allow setting perm/temp resvs
+        *    tresv   - allow setting temp resvs
+        *    unresv  - allow removing xlines
+        *    all     - allow oper/server to do all of above.
+        *    locops  - allow locops - only used for servers who cluster
+        *    rehash  - allow rehashing
+        *    none    - disallow everything
+        */
+
+       /* allow flame@*.leeh.co.uk on server irc.ircd-ratbox.org and
+        * allow leeh@*.leeh.co.uk on server ircd.ircd-ratbox.org to kline
+        */
+       oper = "flame@*.leeh.co.uk", "irc.ircd-ratbox.org";
+       oper = "leeh@*.leeh.co.uk", "ircd.ircd-ratbox.org";
+       flags = kline;
+
+       /* you may forbid certain opers/servers from doing anything */
+       oper = "irc@vanity.oper", "*";
+       oper = "*@*", "irc.vanity.server";
+       oper = "irc@another.vanity.oper", "bigger.vanity.server";
+       flags = none;
+
+       /* or allow everyone to place temp klines */
+       oper = "*@*";
+       flags = tkline;
+};
+
+/* exempt {}: IPs that are exempt from Dlines. (OLD d:) */
+exempt {
+       ip = "192.168.0.0/16";
+
+       /* these may be stacked */
+       ip = "127.0.0.1";
+       ip = "10.0.0.0/8";
+};
+
+/* The channel block contains options pertaining to channels */
+channel {
+       /* invex: Enable/disable channel mode +I, a n!u@h list of masks
+        * that can join a +i channel without an invite.
+        */
+       use_invex = yes;
+
+       /* except: Enable/disable channel mode +e, a n!u@h list of masks
+        * that can join a channel through a ban (+b).
+        */
+       use_except = yes;
+
+       /* forward: Enable/disable channel mode +f, a channel to forward
+        * users to if they can't join because of +i etc.
+        */
+       use_forward = yes;
+
+       /* knock: Allows users to request an invite to a channel that
+        * is locked somehow (+ikl).  If the channel is +p or you are banned
+        * the knock will not be sent.
+        */
+       use_knock = yes;
+
+       /* invite ops only: Restrict /invite to ops on channels, rather than
+        * allowing unopped users to invite people to a -i channel.
+        */
+       invite_ops_only = yes;
+
+       /* knock delay: The amount of time a user must wait between issuing
+        * the knock command.
+        */
+       knock_delay = 5 minutes;
+
+       /* knock channel delay: How often a knock to any specific channel
+        * is permitted, regardless of the user sending the knock.
+        */
+       knock_delay_channel = 1 minute;
+
+       /* max chans: The maximum number of channels a user can join/be on. */
+       max_chans_per_user = 15;
+
+        /* max bans: maximum number of +b/e/I/q modes in a channel */
+        max_bans = 25;
+
+        /* max bans: maximum number of +b/e/I/q modes in a +L channel */
+        max_bans_large = 500;
+
+        /* splitcode: split users, split servers and either no join on split
+        * or no create on split must be enabled for split checking.
+        * splitmode will be entered on either split users or split servers
+        * dropping below the limit.
+        *
+        * you may force splitmode to be permanent by /quote set splitmode on
+        */
+
+       /* split users: when the usercount is lower than this level, consider
+        * ourselves split.  this must be set for automatic splitmode
+        */
+       default_split_user_count = 0;
+
+       /* split servers: when the amount of servers that have acknowledged
+        * theyve finished bursting is lower than this, consider ourselves 
+        * split.  this must be set for automatic splitmode
+        */
+       default_split_server_count = 0;
+
+       /* split: no create: disallow users creating channels on split */
+       no_create_on_split = no;
+
+       /* split: no join: disallow users joining channels at all on a split */
+       no_join_on_split = no;
+
+       /* burst topicwho: when bursting topics, also burst the topic setter */
+       burst_topicwho = yes;
+
+       /* kick on split riding: kick users riding splits to join +i or +k
+        * channels. more precisely, if a bursting server sends an SJOIN
+        * for a channel with a lower TS with either a +i mode or a +k
+        * mode with a different key, kick all local users.
+        *
+        * note: this does not take +r, +b, +e and +I into account.
+        *
+        * warning: if there are any TS5 servers on the network, this
+        * will cause ban desyncs if they send such an SJOIN and the
+        * splitriders added any bans (our side will lose them, the TS5
+        * side will accept them). we will send a notice to the channel
+        * if this happens. most services do not send such SJOINs but
+        * ratbox-services does.
+        */
+       kick_on_split_riding = no;
+};
+
+
+/* The serverhide block contains the options regarding serverhiding */
+serverhide {
+       /* flatten links: this option will show all servers in /links appear
+        * that they are linked to this current server
+        */
+       flatten_links = no;
+
+       /* links delay: how often to update the links file when it is
+        * flattened.
+        */
+       links_delay = 5 minutes;
+
+       /* hidden: hide this server from a /links output on servers that
+        * support it.  this allows hub servers to be hidden etc.
+        */
+        hidden = no;
+
+       /* disable hidden: prevent servers hiding themselves from a
+        * /links ouput.
+        */
+       disable_hidden = no;
+};
+
+/* These are the blacklist settings.
+ * You can have multiple combinations of host and rejection reasons.
+ * They are used in pairs of one host/rejection reason.
+ *
+ * These settings should be adequate for most networks, and are (presently)
+ * required for use on AthemeNet.
+ *
+ * Word to the wise: Do not use blacklists like SPEWS for blocking IRC
+ * connections.
+ *
+ * Note: AHBL (the providers of the below BLs) request that they be
+ * contacted, via email, at admins@2mbit.com before using these BLs.
+ * See <http://www.ahbl.org/services.php> for more information.
+ */
+#blacklist {
+#      host = "ircbl.ahbl.org";
+#      reject_reason = "You have a host listed in the ircbl.ahbl.org blacklist.";
+#
+#      host = "tor.ahbl.org";
+#      reject_reason = "You are connecting from a TOR exit node.";
+#};
+
+/*
+ * Alias blocks allow you to define custom commands. (Old m_sshortcut.c)
+ * They send PRIVMSG to the given target. A real command takes
+ * precedence above an alias.
+ */
+alias "NickServ" {
+       /* the name must go above */
+
+       /* target: the target nick (must be a network service) or
+        * user@server (cannot be this server, only opers can use
+        * user starting with "opers" reliably, interpreted on the target
+        * server only so you may need to use nick@server instead)
+        */
+       target = "NickServ";
+};
+
+alias "ChanServ" {
+       target = "ChanServ";
+};
+
+alias "OperServ" {
+       target = "OperServ";
+};
+
+alias "MemoServ" {
+       target = "MemoServ";
+};
+
+alias "NS" {
+       target = "NickServ";
+};
+
+alias "CS" {
+       target = "ChanServ";
+};
+
+alias "OS" {
+       target = "OperServ";
+};
+
+alias "MS" {
+       target = "MemoServ";
+};
+
+/* The general block contains many of the options that were once compiled
+ * in options in config.h.  The general block is read at start time.
+ */
+general {
+       /* hide error messages: defines whether error messages from
+        * servers are hidden or not.  These can sometimes contain IPs and
+        * can have an adverse effect on server ip hiding.  Set to:
+        *   yes:   hide from opers and admin
+        *   opers: hide from opers only
+        *   no:    do not hide error messages
+        */
+       hide_error_messages = opers;
+
+       /* hide spoof ips: hide the real ips of auth{} spoofed users
+        * If disabled, local opers can see them.
+        * Dynamic spoofs (e.g. set by services) are unaffected by this;
+        * any oper (local and remote) can see the real ip.
+        * Warning: for whowas, this is checked when the client exits,
+        * not when the IP is shown.
+        */
+       hide_spoof_ips = yes;
+
+       /* default umodes: umodes to set upon connection
+        * If you have enabled the ip_cloaking extension, and you wish for
+        * incoming clients to be set +h upon connection, add +h to the umode
+        * string below.
+        */
+       default_umodes = "+i";
+
+       /* default operstring: defines the default oper response
+        * in /whois queries, eg "is an IRC Operator".
+        * After startup use /quote set operstring to change.
+        */
+       default_operstring = "is an IRC Operator";
+
+       /* default adminstring: defines the default admin response
+        * in /whois queries, eg "is a Server Administrator".
+        * After startup use /quote set adminstring to change.
+        */
+       default_adminstring = "is a Server Administrator";
+
+       /* servicestring: defines the response for opered services (+S)
+        * in /whois queries, eg "is a Network Service".
+        * This is updated on rehash.
+        */
+       servicestring = "is a Network Service";
+
+       /* disable fake channels: disable local users joining fake versions
+        * of channels, eg #foo^B^B.  Disables bold, mirc colour, reverse,
+        * underline and hard space.  (ASCII 2, 3, 22, 31, 160 respectively).
+        */
+       disable_fake_channels = no;
+
+        /* tkline_expire_notices: give a notice to opers when a tkline
+         * expires
+         */
+        tkline_expire_notices = no;
+
+       /* floodcount: the default value of floodcount that is configurable
+        * via /quote set floodcount.  This is the amount of lines a user
+        * may send to any other user/channel in one second.
+        */
+        default_floodcount = 10;
+
+       /* failed oper notice: send a notice to all opers on the server when 
+        * someone tries to OPER and uses the wrong password, host or ident.
+        */
+       failed_oper_notice = yes;
+
+       /* dots in ident: the amount of '.' characters permitted in an ident
+        * reply before the user is rejected.
+        */
+       dots_in_ident=2;
+
+       /* dot in ipv6: ircd-hybrid-6.0 and earlier will disallow hosts 
+        * without a '.' in them.  this will add one to the end.  only needed
+        * for older servers.
+        */
+        dot_in_ip6_addr = no;
+        
+        /* min nonwildcard: the minimum non wildcard characters in k/d/g lines
+        * placed via the server.  klines hand placed are exempt from limits.
+        * wildcard chars: '.' '*' '?' '@'
+        */
+       min_nonwildcard = 4;
+
+       /* min nonwildcard simple: the minimum non wildcard characters in
+        * xlines/resvs placed via the server.
+        * wildcard chars: '*' '?'
+        */
+       min_nonwildcard_simple = 3;
+
+        /* max accept: maximum allowed /accept's for +g usermode */
+        max_accept = 20;
+
+       /* max monitor: the maximum amount of nicknames a client may have in
+        * their monitor (server-side notify) list.
+        */
+       max_monitor = 100;
+
+       /* nick flood: enable the nickflood control code */
+       anti_nick_flood = yes;
+
+       /* nick flood: the nick changes allowed in the specified period */
+       max_nick_time = 20 seconds;
+       max_nick_changes = 5;
+
+        /* anti spam time: the minimum time a user must be connected before
+        * custom quit messages are allowed.
+        */
+        anti_spam_exit_message_time = 5 minutes;
+
+       /* ts delta: the time delta allowed between server clocks before
+        * a warning is given, or before the link is dropped.  all servers
+        * should run ntpdate/rdate to keep clocks in sync
+        */
+       ts_warn_delta = 30 seconds;
+       ts_max_delta = 5 minutes;
+
+       /* client exit: prepend a users quit message with "Client exit: " */
+       client_exit = yes;
+
+       /* collision fnc: change user's nick to their UID instead of
+        * killing them, if possible. This setting only applies to nick
+        * collisions detected on this server. Only enable this if
+        * all servers on the network allow remote nicks to start with
+        * a digit.
+        */
+       collision_fnc = yes;
+
+       /* global snotices: send out certain snotices (most +b, +f, +y,
+        * some +s) to other servers via ENCAP SNOTE. Received SNOTEs are
+        * displayed unconditionally.
+        */
+       global_snotices = yes;
+       
+       /* dline reason: show the user the dline reason when they connect 
+        * and are dlined.
+        */
+       dline_with_reason = yes;
+       
+       /* kline delay: delay the checking of klines until a specified time.
+        * Useful if large kline lists are applied often to prevent the
+        * server eating CPU.
+        */
+       kline_delay = 0 seconds;
+
+       /* kline reason: show the user the reason why they are k/d/glined 
+        * on exit.  may give away who set k/dline when set via tcm.
+        */
+       kline_with_reason = yes;
+
+       /* kline reason: make the users quit message on channels this
+        * reason instead of the oper's reason.
+        */
+       kline_reason = "Connection closed";
+
+       /* identify to services via server password
+        * if auth{} block had no password but the user specified a
+        * server password anyway, send a PRIVMSG to <identify_service>
+        * with as text <identify_command> <password>.
+        */
+       identify_service = "NickServ@services.int";
+       identify_command = "IDENTIFY";
+
+       /* non redundant klines: flag and ignore redundant klines */
+       non_redundant_klines = yes;
+
+       /* warn no nline: warn opers about servers that try to connect but
+        * we dont have a connect {} block for.  Twits with misconfigured 
+        * servers can get really annoying with this enabled.
+        */
+       warn_no_nline = yes;
+
+       /* stats e disabled: disable stats e.  useful if server ips are
+        * exempted and you dont want them listing on irc.
+        */
+       stats_e_disabled = no;
+
+       /* stats c oper only: make stats c (connect {}) oper only */
+       stats_c_oper_only=no;
+
+       /* stats h oper only: make stats h (hub_mask/leaf_mask) oper only */
+       stats_h_oper_only=no;
+
+       /* stats y oper only: make stats y (class {}) oper only */
+       stats_y_oper_only=no;
+
+       /* stats o oper only: make stats o (opers) oper only */
+       stats_o_oper_only=yes;
+
+       /* stats P oper only: make stats P (ports) oper only
+        * NOTE: users doing stats P will never be given the ips that the 
+        * server listens on, simply the ports.
+        */
+       stats_P_oper_only=no;
+
+       /* stats i oper only: make stats i (auth {}) oper only. set to:
+        *     yes:    show users no auth blocks, made oper only.
+        *     masked: show users first matching auth block
+        *     no:     show users all auth blocks.
+        */
+       stats_i_oper_only=masked;
+
+       /* stats k/K oper only: make stats k/K (klines) oper only.  set to:
+        *     yes:    show users no auth blocks, made oper only
+        *     masked: show users first matching auth block
+        *     no:     show users all auth blocks.
+        */
+       stats_k_oper_only=masked;
+
+        /* map oper only: make /map oper only */
+        map_oper_only = no;
+
+       /* operspy admin only: make operspy notices to +Z admin only */
+       operspy_admin_only = no;
+
+       /* operspy dont care user info: treat /who mask as if there was
+        * an '!' always; do not log or server notice about operspy
+        * /who mask, /masktrace and /scan. channel information is still
+        * protected. */
+       operspy_dont_care_user_info = no;
+
+       /* caller id wait: time between notifying a +g user that somebody
+        * is messaging them.
+        */
+       caller_id_wait = 1 minute;
+
+       /* pace wait simple: time between use of less intensive commands
+        * (HELP, remote WHOIS, WHOWAS)
+        */
+       pace_wait_simple = 1 second;
+
+       /* pace wait: time between more intensive commands
+        * (ADMIN, INFO, LIST, LUSERS, MOTD, STATS, VERSION)
+        */
+       pace_wait = 10 seconds;
+
+       /* short motd: send clients a notice telling them to read the motd
+        * instead of forcing a motd to clients who may simply ignore it.
+        */
+       short_motd = no;
+
+       /* ping cookies: require clients to respond exactly to a ping command,
+        * can help block certain types of drones and FTP PASV mode spoofing.
+        */
+       ping_cookie = no;
+
+       /* connect timeout: sets how long we should wait for a connection
+        * request to succeed
+        */
+       connect_timeout = 30 seconds;
+
+       /* disable auth: disables identd checking */
+       disable_auth = no;
+
+       /* no oper flood: increase flood limits for opers. */
+       no_oper_flood = yes;
+
+       /* glines: enable glines, network wide temp klines */
+       glines = no;
+
+       /* gline time: the amount of time a gline will remain before expiring */
+       gline_time = 1 day;
+
+       /* gline_min_cidr: If using a CIDR gline, the minimum length the
+        * mask must be
+        */
+       gline_min_cidr = 16;
+
+       /* idletime: the maximum amount of time a user may idle before
+        * they are disconnected
+        */
+        idletime = 0;
+
+       /* REMOVE ME.  The following line checks you've been reading. */
+       havent_read_conf = yes;
+       
+       /* max targets: the maximum amount of targets in a single 
+        * PRIVMSG/NOTICE.  set to 999 NOT 0 for unlimited.
+        */
+       max_targets = 4;
+
+       /* client flood: maximum number of lines in a clients queue before
+        * they are dropped for flooding.
+        */
+       client_flood = 20;
+
+        /* use_whois_actually: send clients requesting a whois a numeric
+         * giving the real IP of non-spoofed clients to prevent DNS abuse.
+         */
+        use_whois_actually = yes;
+
+       /* usermodes configurable: a list of usermodes for the options below
+        *
+        * +g - callerid   - Server Side Ignore
+        * +D - deaf       - Don't see channel messages
+        * +i - invisible  - Not shown in NAMES or WHO unless you share a 
+        *                   a channel
+        * +l - locops     - See LOCOPS messages
+        * +Q - noforward  - Unaffected by channel forwarding
+        * +R - regonlymsg - No messages from unindentified
+        * +s - servnotice - See server notices
+        * +w - wallop     - See oper and server generated WALLOPS
+        * +z - operwall   - See operwalls
+        */
+        
+       /* oper only umodes: usermodes only opers may set */
+       oper_only_umodes = operwall, locops, servnotice;
+
+       /* oper umodes: default usermodes opers get when they /oper */
+       oper_umodes = locops, servnotice, operwall, wallop;
+
+       /* oper snomask: default snomask opers get when they /oper,
+        * provided they have umode +s set */
+       oper_snomask = "+s";
+
+       /* servlink path: path to 'servlink' program used by ircd to handle
+        * encrypted/compressed server <-> server links.
+        *
+        * only define if servlink is not in same directory as ircd itself.
+        */
+       #servlink_path = "/usr/local/ircd/bin/servlink";
+
+       /* use egd: if your system does not have *random devices yet you
+        * want to use OpenSSL and encrypted links, enable this.  Beware -
+        * EGD is *very* CPU intensive when gathering data for its pool
+        */
+       #use_egd = yes;
+
+       /* egdpool path: path to EGD pool. Not necessary for OpenSSL >= 0.9.7
+        * which automatically finds the path.
+        */
+       #egdpool_path = "/var/run/egd-pool";
+
+
+       /* compression level: level of compression for compressed links between
+        * servers.  
+        *
+        * values are between: 1 (least compression, fastest)
+        *                and: 9 (most compression, slowest).
+        */
+       #compression_level = 6;
+
+        /* burst_away: This enables bursting away messages to servers.
+         * With this disabled, we will only propogate AWAY messages
+         * as users send them, but never burst them.  Be warned though
+         * enabling this could increase the size of a burst significantly
+         * for a large network, like EFnet.
+         */
+        burst_away = yes;
+
+       /* nick delay: This locks nicks of split clients for the given time
+        * or until a remote client uses the nick. This significantly
+        * reduces nick collisions on short splits but it can be annoying.
+        * To make things as fair as possible, this should be the same on
+        * all servers. If you enable this, the suggested value is 15 minutes.
+        */
+       nick_delay = 0 seconds;
+
+       /* reject time: the amount of rejections through klines/dlines etc
+        * allowed in the given time before the rejection is cached and
+        * a pseudo temp dline is placed
+        */
+       reject_ban_time = 1 minute;
+       reject_after_count = 3;
+
+       /* reject duration: the amount of time to cache the rejection */
+       reject_duration = 5 minutes;
+};
+
+modules {
+       /* module path: paths to search for modules specified below and 
+        * in /modload.
+        */
+       path = "/usr/local/ircd/modules";
+       path = "/usr/local/ircd/modules/autoload";
+
+       /* module: the name of a module to load on startup/rehash */
+       #module = "some_module.so";
+};
diff --git a/doc/server-version-info b/doc/server-version-info
new file mode 100644 (file)
index 0000000..5315729
--- /dev/null
@@ -0,0 +1,51 @@
+                              Server VERSION Info
+
+   $Id: server-version-info 1851 2006-08-24 17:16:53Z jilles $
+
+   Copyright (c) 2001 by ircd-hybrid team
+   Copyright (c) 2002 ircd-ratbox development team
+
+     ----------------------------------------------------------------------
+
+   When you type /version, you will often see something like this:
+
+ ircd-ratbox-1.0rc7(20021120_0). embers.lan egGHIKMpZ6 TS5ow
+
+   Ever wondered what those funny chars mean after the version number? Well
+   here they are:
+
+   +----------------------------+
+   | 'e'  | USE_EXCEPT          |
+   |------+---------------------|
+   | 'g'  | NO_FAKE_GLINES      |
+   |------+---------------------|
+   | 'G'  | GLINES              |
+   |------+---------------------|
+   | 'H'  | HUB                 |
+   |------+---------------------|
+   | 'I'  | USE_INVEX           |
+   |------+---------------------|
+   | 'K'  | USE_KNOCK           |
+   |------+---------------------|
+   | 'M'  | IDLE_FROM_MSG       |
+   |------+---------------------|
+   | 'p'  | CRYPT_OPER_PASSWORD |
+   |------+---------------------|
+   | 'S'  | OPERS_SEE_ALL_USERS |
+   |------+---------------------|
+   | 'T'  | IGNORE_BOGUS_TS     |
+   |------+---------------------|
+   | 'Z'  | ZIPLINKS            |
+   |------+---------------------|
+   | '6'  | IPv6                |
+   |------+---------------------|
+   |      |                     |
+   |------+---------------------|
+   | 'TS' | Supports TS         |
+   |------+---------------------|
+   | '5'  | TS Version 5        |
+   |------+---------------------|
+   | 'o'  | TS Only             |
+   |------+---------------------|
+   | 'w'  | TS Warnings         |
+   +----------------------------+
diff --git a/doc/services.txt b/doc/services.txt
new file mode 100644 (file)
index 0000000..eb27b9f
--- /dev/null
@@ -0,0 +1,55 @@
+ratbox-services compatibility documentation - Lee H <lee -at- leeh.co.uk>
+-------------------------------------------------------------------------
+
+Compatibility with ratbox-services can be enabled by passing the
+'--enable-services' flag to configure.  It will add the following features
+to ircd:
+
+1. Channel mode +r
+
+   A simple mode taking no parameters, will require users are logged in
+   with user services before they may join the channel.
+
+   Gives numeric 477 to users who arent logged in:
+   :<server> 477 <nick> <channel> :Cannot join channel (+r)
+
+2. service block to ircd.conf
+
+   Ability to specify the names of services servers in ircd.conf:
+   service {
+       name = "services.ircd-ratbox.org";
+       name = "backup-services.ircd-ratbox.org";
+   };
+
+   These must be specified for certain features to work.  You may specify as
+   many name entries as you wish, however you must define only one service
+   block.
+
+   Entries will be listed in stats U with the flag 's'.
+
+3. Services protection
+
+   Services will be protected from being deopped or kicked from a channel.
+
+4. Username tracking through netsplits
+
+   When users are logged in, the username they are logged in with will be
+   preserved on a netsplit, so users will not have to relogin when the
+   network merges together.
+
+5. Username given on WHOIS
+
+   When users are logged in, WHOIS will also give numeric 330:
+   :<server> 330 <yournick> <targetnick> <loginname> :is logged in as
+
+   Note this needs to be a remote whois to work when the target is
+   on a different server.
+
+6. Forced nick change
+
+   When using nickname services and a client requests they regain a
+   nickname, services can perform a forced nick change on the client.
+   This forcibly changes the clients nickname to the one they requested
+   they regain, ensuring they can always regain their nickname.
+
+# $Id: services.txt 6 2005-09-10 01:02:21Z nenolod $
diff --git a/doc/sgml/oper-guide/charybdis-oper-guide.sgml b/doc/sgml/oper-guide/charybdis-oper-guide.sgml
new file mode 100644 (file)
index 0000000..70a9a3b
--- /dev/null
@@ -0,0 +1,57 @@
+<!DOCTYPE Book PUBLIC "-//OASIS//DTD DocBook V4.2//EN" [
+<!ENTITY intro SYSTEM "intro.sgml">
+<!ENTITY oprivs SYSTEM "oprivs.sgml">
+<!ENTITY umodes SYSTEM "umodes.sgml">
+<!ENTITY cmodes SYSTEM "cmodes.sgml">
+<!ENTITY ucommands SYSTEM "ucommands.sgml">
+<!ENTITY commands SYSTEM "commands.sgml">
+<!ENTITY config SYSTEM "config.sgml">
+]>
+<book id="charybdis-oper-guide">
+  <bookinfo>
+    <date>24 November 2005</date>
+    <title>Operators guide for the charybdis IRC server</title>
+    <author>
+      <firstname>William</firstname>
+      <surname>Pitcock</surname>
+    </author>
+    <address><email>nenolod@nenolod.net</email></address>
+    <copyright>
+      <year>2005-2007</year>
+      <holder>William Pitcock and Jilles Tjoelker</holder>
+    </copyright>
+    <legalnotice>
+      <para>
+       Permission is granted to copy, distribute and/or modify this document under the terms of the GNU
+       General Public License, Version 2 or any later version published by the Free Software Foundation
+      </para>
+    </legalnotice>
+  </bookinfo>
+  <toc>
+  </toc>
+  &intro;
+  &umodes;
+  &cmodes;
+  &ucommands;
+  &commands;
+  &oprivs;
+  &config;
+</book>
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-namecase-general:t
+sgml-general-insert-case:lower
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:("/usr/lib/sgml/catalog")
+sgml-local-ecat-files:nil
+fill-column: 105
+End:
+-->
diff --git a/doc/sgml/oper-guide/cmodes.sgml b/doc/sgml/oper-guide/cmodes.sgml
new file mode 100644 (file)
index 0000000..ee18a4d
--- /dev/null
@@ -0,0 +1,314 @@
+  <chapter id="cmodes">
+    <title>Cmodes</title>
+    <sect1>
+      <title>Meanings of channel modes</title>
+      <sect2>
+       <title>+b, channel ban</title>
+       <para>
+         Bans take one parameter which can take several forms.
+         The most common form is +b nick!user@host.
+         The wildcards * and ? are allowed, matching zero-or-more, and
+         exactly-one characters respectively. The masks will be trimmed to fit the maximum allowable
+         length for the relevant element.
+         Bans are also checked against the IP address, even if it resolved or
+         is spoofed.
+         CIDR is supported, like *!*@10.0.0.0/8. This is most useful with
+         IPv6.
+         Bans are not checked against the real hostname behind any kind
+         of spoof, except if host mangling is in use (e.g.
+         <filename>extensions/ip_cloaking.so</filename>):
+         if the user's host is mangled, their real hostname is checked
+         additionally, and if a user has no spoof but could enable mangling,
+         the mangled form of their hostname is checked additionally.
+         Hence, it is not possible to evade bans by toggling
+         host mangling.
+       </para>
+       <para>
+         The second form (extban) is +b $type or +b $type:data. 
+         type is a single character (case insensitive) indicating the
+         type of match, optionally preceded by a tilde (~) to negate the
+         comparison. data depends on type. Each type is loaded as a module.
+         The available types (if any)
+         are listed in the EXTBAN token of the 005 (RPL_ISUPPORT) numeric.
+         See <filename>doc/extban.txt</filename> in the source distribution
+         for more information.
+       </para>
+       <para>
+         If no parameter is given, the list of bans is returned. All users
+         can use this form. The plus sign should also be omitted.
+       </para>
+       <para>
+         Matching users will not be allowed to join the channel or knock
+         on it. If they are already on the channel, they may not send to
+         it or change their nick.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+c, colour filter</title>
+       <para>
+         This cmode activates the colour filter for the channel. This filters out bold, underline,
+         reverse video, beeps, mIRC colour codes, and ANSI escapes. Note that escape sequences will
+         usually leave cruft sent to the channel, just without the escape characters themselves.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+e, ban exemption</title>
+       <para>
+         This mode takes one parameter of the same form as bans, which
+         overrides +b and +q bans for all clients it matches.
+       </para>
+       <para>
+         Only channel operators can see +e changes or request the list.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+f, channel forwarding</title>
+       <para>
+         This mode takes one parameter, the name of a channel (+f #channel). If the channel also has the
+         +i cmode set, and somebody attempts to join without either being expliticly invited, or having
+         an invex (+I), then they will instead join the channel named in the mode parameter. The client
+         will also be sent a 470 numeric giving the original and target channels.
+       </para>
+        <para>
+          Users are similarly forwarded if the +j cmode is set and their attempt to join is throttled,
+         if +l is set and there are already too many users in the channel
+         or if +r is set and they are not identified.
+        </para>
+        <para>
+          Forwards may only be set to +F channels, or to channels the setter
+          has ops in.
+        </para>
+       <para>
+         Without parameter (/mode #channel f or /mode #channel +f) the
+         forward channel is returned. This form also works off channel.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+F, allow anybody to forward to this</title>
+       <para>
+         When this mode is set, anybody may set a forward from a channel
+         they have ops in to this channel. Otherwise they have to have ops
+         in this channel.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+g, allow anybody to invite</title>
+       <para>
+         When this mode is set, anybody may use the INVITE command on the channel in question. When it
+         is unset, only channel operators may use the INVITE command
+         (unless the invite_ops_only option is disabled and +i is
+         not set).
+       </para>
+       <para>
+         When this mode is set together with +i, all channel members can influence who can join.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+i, invite only</title>
+       <para>
+         When this cmode is set, no client can join the channel unless they have an invex (+I) or are
+         invited with the INVITE command.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+I, invite exception (invex)</title>
+       <para>
+         This mode takes one parameter of the same form as bans. Matching
+         clients do not need to be invited to join the channel when it is invite-only (+i).
+       </para>
+       <para>
+         Only channel operators can see +I changes or request the list.
+       </para>
+      </sect2>
+      <sect2>
+        <title>+j, join throttling</title>
+        <para>
+          This mode takes one parameter of the form <replaceable>n</replaceable>:<replaceable>t</replaceable>, where <replaceable>n</replaceable> and <replaceable>t</replaceable> are positive integers. Only <replaceable>n</replaceable> users may join in each period of <replaceable>t</replaceable> seconds.
+        </para>
+       <para>
+         Due to propagation delays between servers, more users may be
+         able to join (by racing for the last slot on each server).
+       </para>
+      </sect2>
+      <sect2>
+       <title>+k, key (channel password)</title>
+       <para>
+         Taking one parameter, when set, this mode requires a user to supply the key in order to join
+         the channel: /JOIN #channel key.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+l, channel member limit</title>
+       <para>
+         Takes one numeric parameter, the number of users which are allowed to be in the channel before
+         further joins are blocked.
+       </para>
+       <para>
+         Due to propagation delays between servers, more users may be
+         able to join (by racing for the last slot on each server).
+       </para>
+      </sect2>
+      <sect2>
+       <title>+L, large ban list</title>
+       <para>
+         Channels with this mode will be allowed larger banlists (by default,
+          500 instead of 50 entries for +b, +q, +e and +I together).
+         Only network operators may set this mode.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+m, moderated</title>
+       <para>
+         When a channel is set +m, only users with +o or +v on the channel can send to it.
+       </para>
+       <para>
+         Users can still knock on the channel or change their nick.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+n, no external messages</title>
+       <para>
+         When set, this mode prevents users from sending to the channel without being in it themselves.
+         This is recommended.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+o, channel operator</title>
+       <para>
+         This mode takes one parameter, a nick, and grants or removes channel
+         operator privilege to that user. Channel operators have full control
+         over the channel, having the ability to set all channel modes except
+         +L and +P, and kick users.
+         Like voiced users, channel operators can always
+         send to the channel, overriding +b, +m and +q modes and the
+         per-channel flood limit.
+         In most clients channel operators are marked with an '@' sign.
+       </para>
+       <para>
+         The privilege is lost if the user leaves the channel or server
+         in any way.
+       </para>
+       <para>
+         Most networks will run channel registration services (e.g. ChanServ)
+         which ensure the founder (and users designated by the founder) can
+         always gain channel operator privileges and provide some features
+         to manage the channel.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+p, paranoid channel</title>
+       <para>
+         When set, the KNOCK command cannot be used on the channel
+         to request an invite, and users will not be shown the
+         channel in WHOIS replies unless they are on it.
+         Unlike in traditional IRC, +p and +s can be set together.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+P, permanent channel</title>
+       <para>
+         Channels with this mode (which is accessible only to network operators) set will not be destroyed
+         when the last user leaves.
+       </para>
+       <para>
+         This makes it less likely modes, bans and the topic will be lost and
+         makes it harder to abuse network splits, but also causes more
+         unwanted restoring of old modes, bans and topics after long splits.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+q, quiet</title>
+       <para>
+         This mode behaves exactly like +b (ban), except that the user may still join
+         the channel. The net effect is that they cannot knock on the channel,
+         send to the channel or change their nick while on channel.
+       </para>
+      </sect2>
+      <sect2>
+        <title>+Q, block forwarded users</title>
+        <para>
+          Channels with this mode set are not valid targets for forwarding. Any attempt to forward to
+          this channel will be ignored, and the user will be handled as if the attempt was never made (by
+          sending them the relevant error message).
+        </para>
+        <para>
+          This does not affect the ability to set +f.
+        </para>
+      </sect2>
+      <sect2>
+        <title>+r, block unidentified</title>
+        <para>
+          When set, this mode prevents unidentified users from joining.
+        </para>
+      </sect2>
+      <!-- not planned (jilles)
+      <sect2>
+        <title>+R, quiet unidentified</title>
+        <para>
+          When set, this mode prevents unidentified users from sending to the channel, although they can
+          still join.
+        </para>
+       <para>
+         Please note that this mode is not implemented in Charybdis 1.0.x, and is documented in
+         expectation for upcoming Charybdis 1.1.
+       </para>
+      </sect2>
+      -->
+      <sect2>
+       <title>+s, secret channel</title>
+       <para>
+         When set, this mode prevents the channel from appearing in the
+         output of the LIST, WHO and WHOIS command by users who are not on
+         it. Also, the server will refuse to answer WHO, NAMES, TOPIC and
+         LIST queries from users not on the channel.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+t, topic limit</title>
+       <para>
+         When set, this mode prevents users who are not channel operators
+         from changing the topic.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+v, voice</title>
+       <para>
+         This mode takes one parameter, a nick, and grants or removes voice
+         privilege to that user. Voiced users can always send to the channel,
+         overriding +b, +m and +q modes and the per-channel flood limit.
+         In most clients voiced users are marked with a plus sign.
+       </para>
+       <para>
+         The privilege is lost if the user leaves the channel or server
+         in any way.
+       </para>
+      </sect2>
+      <sect2>
+        <title>+z, reduced moderation</title>
+        <para>
+          When +z is set, the effects of +m are relaxed. For each message, if that message
+          would normally be blocked by moderation, it is instead sent to all channel operators. This is intended for use in moderated debates.
+        </para>
+        <para>
+          Note that +n and channel bans/quiets are unaffected by this. To silence a given user completely,
+         remove them from the channel.
+        </para>
+      </sect2>
+    </sect1>
+  </chapter>
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-namecase-general:t
+sgml-general-insert-case:lower
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:("charybdis-oper-guide.sgml" "book")
+sgml-exposed-tags:nil
+fill-column:105
+End:
+-->
diff --git a/doc/sgml/oper-guide/commands.sgml b/doc/sgml/oper-guide/commands.sgml
new file mode 100644 (file)
index 0000000..25726e2
--- /dev/null
@@ -0,0 +1,1095 @@
+  <chapter id="commands">
+    <title>Operator Commands</title>
+    <sect1>
+      <title>Network management commands</title>
+      <note>
+       <para>
+         Except STATS letters, all commands and names are case insensitive.
+       </para>
+      </note>
+      <sect2>
+       <title>CONNECT</title>
+       <cmdsynopsis><command>CONNECT</command> 
+         <arg choice=plain><replaceable>target</replaceable></arg> 
+         <arg><replaceable>port</replaceable></arg> 
+         <arg><replaceable>source</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         Initiate a connection attempt to server <replaceable class=parameter>target</replaceable>. If a port is
+         given, connect to that port on the target, otherwise use the one given in <filename>ircd.conf</filename>. If 
+         <replaceable class=parameter>source</replaceable> is given, tell that server to initiate the connection
+         attempt, otherwise it will be made from the server you are attached to.
+       </para>
+      </sect2>
+      <sect2>
+       <title>SQUIT</title>
+       <cmdsynopsis>
+         <command>SQUIT</command>
+         <arg choice=plain><replaceable>server</replaceable></arg>
+         <arg><replaceable>reason</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         Closes down the link to <replaceable>server</replaceable> from this side of the network. If a reason is
+         given, it will be sent out in the server notices on both sides of the link.
+       </para>
+      </sect2>
+      <sect2>
+       <title>REHASH</title>
+       <cmdsynopsis>
+         <command>REHASH</command>
+         <group>
+           <arg>BANS</arg>
+           <arg>DNS</arg>
+           <arg>MOTD</arg>
+           <arg>OMOTD</arg>
+           <arg>GLINES</arg>
+           <arg>PGLINES</arg>
+           <arg>TKLINES</arg>
+           <arg>TDLINES</arg>
+           <arg>TXLINES</arg>
+           <arg>TRESVS</arg>
+           <arg>REJECTCACHE</arg>
+           <arg>HELP</arg>
+         </group>
+         <arg><replaceable>server</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         With no parameter given, <filename>ircd.conf</filename> will be reread and parsed.
+         The server argument is a wildcard match of server names.
+       </para>
+       <variablelist>
+         <title>Parameters</title>
+         <varlistentry>
+           <term>BANS</term>
+           <listitem>
+             <para>Rereads <filename>kline.conf</filename>, <filename>dline.conf</filename>, <filename>xline.conf</filename>, <filename>resv.conf</filename> and their .perm variants</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>DNS</term>
+           <listitem>
+             <para>Reread <filename>/etc/resolv.conf</filename>.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>MOTD</term>
+           <listitem>
+             <para>Reload the MOTD file</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>OMOTD</term>
+           <listitem>
+             <para>Reload the operator MOTD file</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>GLINES</term>
+           <listitem>
+             <para>Clears G:lines.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>PGLINES</term>
+           <listitem>
+             <para>Clears pending G:lines.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>TKLINES</term>
+           <listitem>
+             <para>Clears temporary K:lines.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>TDLINES</term>
+           <listitem>
+             <para>Clears temporary D:lines.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>TXLINES</term>
+           <listitem>
+             <para>Clears temporary X:lines.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>TRESVS</term>
+           <listitem>
+             <para>Clears temporary reservations.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>REJECTCACHE</term>
+           <listitem>
+             <para>Clears the client rejection cache.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>HELP</term>
+           <listitem>
+             <para>Refreshes the help system cache.</para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+      </sect2>
+      <sect2>
+       <title>RESTART</title>
+       <cmdsynopsis>
+         <command>RESTART</command>
+         <arg choice=plain><replaceable>server</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         Cause an immediate total shutdown of the IRC server, and restart from scratch as if it had just been executed.
+       </para>
+       <para>
+         This reexecutes the ircd using the compiled-in path, visible
+         as SPATH in INFO.
+       </para>
+       <note>
+         <para>This command cannot be used remotely. The server name is used only as a safety measure.</para>
+       </note>
+      </sect2>
+      <sect2>
+       <title>DIE</title>
+       <cmdsynopsis>
+         <command>DIE</command>
+         <arg choice=plain><replaceable>server</replaceable></arg>
+       </cmdsynopsis>
+       <para>Immediately terminate the IRC server, after sending notices to all connected clients and servers</para>
+       <note>
+         <para>This command cannot be used remotely. The server name is used only as a safety measure.</para>
+       </note>
+      </sect2>
+      <sect2>
+       <title>SET</title>
+       <cmdsynopsis>
+         <command>SET</command>
+         <group>
+           <arg>LOG</arg>
+           <arg>MAX</arg>
+           <arg>SPLITDELAY</arg>
+           <arg>SMALLNET</arg>
+           <arg>SPAMNUM</arg>
+           <arg>SPAMTIME</arg>
+         </group>
+         <arg choice=plain><replaceable>value</replaceable></arg>
+       </cmdsynopsis>
+       <para>The SET command sets a runtime-configurable value</para>
+       <variablelist>
+         <varlistentry>
+           <term>LOG</term>
+           <listitem>
+             <para>Logging level for ircd.log and syslog</para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+       <variablelist>
+         <varlistentry>
+           <term>MAX</term>
+           <listitem>
+             <para>Set the maximum connections allowed (may not exceed the compiled-in value HARD_FDLIMIT)</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>DRONETIME</term>
+           <listitem>
+             <para>Number of seconds in which DRONECOUNT messages must occur to trip the drone alarm</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>DRONECOUNT</term>
+           <listitem>
+             <para>Number of messages which constitutes a drone flood. 0 disables drone flood checking.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>SPLITDELAY</term>
+           <listitem>
+             <para>Number of minutes after a connect burst begins until joining an empty channel will give you ops</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>SMALLNET</term>
+           <listitem>
+             <para>Sets the number of servers which are needed to constitute <quote>attached to the network</quote>, as opposed to <quote>split</quote></para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>SPAMNUM</term>
+           <listitem>
+             <para>Sets the number of JOINs/PARTs which constitutes a possible spambot</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>SPAMTIME</term>
+           <listitem>
+             <para>Staying on a channel for less than this length of time adds to the SPAMNUM count</para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+      </sect2>
+    </sect1>
+    <sect1 id="usercommands">
+      <title>User management commands</title>
+      <sect2>
+       <title>KILL</title>
+       <cmdsynopsis>
+         <command>KILL</command>
+         <arg choice=plain><replaceable>nick</replaceable></arg>
+         <arg><replaceable>reason</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         Disconnects the user with the given nick from the server they are connected to,
+         with the reason given, if present, and broadcast a server notice announcing this.
+       </para>
+       <para>
+         Your nick and the reason will appear on channels.
+       </para>
+      </sect2>
+      <sect2>
+       <title>CLOSE</title>
+       <para>
+         Closes all connections from and to clients and servers who have not completed registering.
+       </para>
+      </sect2>
+      <sect2>
+       <title>KLINE</title>
+       <cmdsynopsis>
+         <command>KLINE</command>
+         <arg><replaceable>length</replaceable></arg>
+         <group>
+           <arg choice=plain><replaceable>user</replaceable>@<replaceable>host</replaceable></arg>
+           <arg choice=plain><replaceable>user</replaceable>@<replaceable>a</replaceable>.<replaceable>b</replaceable>.<replaceable>c</replaceable>.<replaceable>d</replaceable></arg>
+         </group>
+         <arg>ON <replaceable>servername</replaceable></arg>
+         <arg>:<replaceable>reason</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         Adds a K:line to <filename>kline.conf</filename> to ban the given user@host from using that
+         server.
+       </para>
+       <para>
+         If the optional parameter <replaceable>length</replaceable> is given, the K:line will
+         be temporary (i.e. it will not be stored on disk) and last that
+         long in minutes.
+       </para>
+       <para>
+         If an IP address is given, the ban will be against all hosts matching that IP regardless
+         of DNS. The IP address can be given as a full address (192.168.0.1), as a CIDR mask
+         (192.168.0.0/24), or as a glob (192.168.0.*).
+       </para>
+       <para>
+         All clients matching the K:line will be disconnected from the server immediately.
+       </para>
+       <para>
+         If a reason is specified, it will be sent to the client when they are disconnected, and
+         whenever a connection is attempted which is banned.
+       </para>
+       <para>
+         If the ON part is specified, the K:line is set on servers matching
+         the given mask (provided a matching shared{} block exists there).
+         Otherwise, if specified in a cluster{} block, the K:Line will be
+         propagated across the network accordingly.
+       </para>
+      </sect2>
+      <sect2>
+       <title>UNKLINE</title>
+       <cmdsynopsis>
+         <command>UNKLINE</command>
+         <arg choice=plain><replaceable>user</replaceable>@<replaceable>host</replaceable></arg>
+         <arg>ON <replaceable>servername</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         Will attempt to remove a K:line matching user@host from <filename>kline.conf</filename>, and will flush
+         a temporary K:line.
+       </para>
+      </sect2>
+      <sect2>
+       <title>XLINE</title>
+       <cmdsynopsis>
+         <command>XLINE</command>
+         <arg><replaceable>length</replaceable></arg>
+         <arg choice=plain><replaceable>mask</replaceable></arg>
+         <arg>ON <replaceable>servername</replaceable></arg>
+         <arg>:<replaceable>reason</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         Works similarly to KLINE, but matches against the real name field.
+         The wildcards are * (any sequence), ? (any character),
+         # (a digit) and @ (a letter); wildcard characters can be
+         escaped with a backslash.
+       </para>
+       <para>
+         Use \s for a space; this currently interferes with the
+         check whether the mask is already xlined and UNXLINE.
+       </para>
+       <para>
+         All clients matching the X:line will be disconnected from the server immediately.
+       </para>
+       <para>
+         The reason is never sent to users. Instead, they will be exited
+         with <quote>Bad user info</quote>.
+       </para>
+       <para>
+         If the ON part is specified, the X:line is set on servers matching
+         the given mask (provided a matching shared{} block exists there).
+         Otherwise, if specified in a cluster{} block, the X:line will be
+         propagated across the network accordingly.
+       </para>
+      </sect2>
+      <sect2>
+       <title>UNXLINE</title>
+       <cmdsynopsis>
+         <command>UNXLINE</command>
+         <arg choice=plain><replaceable>mask</replaceable></arg>
+         <arg>ON <replaceable>servername</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         Will attempt to remove an X:line from <filename>xline.conf</filename>, and will flush
+         a temporary X:line.
+       </para>
+      </sect2>
+      <sect2>
+       <title>RESV</title>
+       <cmdsynopsis>
+         <command>RESV</command>
+         <arg><replaceable>length</replaceable></arg>
+         <group>
+           <arg choice=plain><replaceable>channel</replaceable></arg>
+           <arg choice=plain><replaceable>mask</replaceable></arg>
+         </group>
+         <arg>ON <replaceable>servername</replaceable></arg>
+         <arg>:<replaceable>reason</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         If used on a channel, <quote>jupes</quote> the channel locally. Joins to the
+         channel will be disallowed and generate a server notice on +y, and
+         users will not be able to send to the channel. Channel jupes cannot
+         contain wildcards.
+       </para>
+       <para>
+         If used on a nickname mask, prevents local users from using a nick
+         matching the mask (the same wildcard characters as xlines). There
+         is no way to exempt the initial nick from this.
+       </para>
+       <para>
+         In neither case will current users of the nick or channel be
+         kicked or disconnected.
+       </para>
+       <para>
+         This facility is not designed to make certain nicks
+         or channels oper-only.
+       </para>
+       <para>
+         The reason is never sent to users.
+       </para>
+       <para>
+         If the ON part is specified, the resv is set on servers matching
+         the given mask (provided a matching shared{} block exists there).
+         Otherwise, if specified in a cluster{} block, the resv will be
+         propagated across the network accordingly.
+       </para>
+      </sect2>
+      <sect2>
+       <title>UNRESV</title>
+       <cmdsynopsis>
+         <command>UNRESV</command>
+         <group>
+           <arg choice=plain><replaceable>channel</replaceable></arg>
+           <arg choice=plain><replaceable>mask</replaceable></arg>
+         </group>
+         <arg>ON <replaceable>servername</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         Will attempt to remove a resv from <filename>resv.conf</filename>, and will flush
+         a temporary resv.
+       </para>
+      </sect2>
+      <sect2>
+       <title>DLINE</title>
+       <cmdsynopsis>
+         <command>DLINE</command>
+         <arg><replaceable>length</replaceable></arg>
+         <arg choice=plain><replaceable>a</replaceable>.<replaceable>b</replaceable>.<replaceable>c</replaceable>.<replaceable>d</replaceable></arg>
+         <arg>:<replaceable>reason</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         Adds a D:line to <filename>dline.conf</filename>, which will deny any connections
+         from the given IP address.
+       </para>
+       <para>
+         If the optional parameter <replaceable>length</replaceable> is given, the D:line will
+         be temporary (i.e. it will not be stored on disk) and last that
+         long in minutes.
+       </para>
+       <para>
+         If a reason is specified, it will be sent to the client when they are disconnected, and,
+         if dline_reason is enabled,
+         whenever a connection is attempted which is banned.
+       </para>
+       <para>
+         D:lines are less load on a server, and may be more appropriate if somebody is flooding
+         connections.
+       </para>
+       <para>
+         D:lines cannot be set remotely on other servers.
+       </para>
+       <para>
+         Only exempt{} blocks exempt from D:lines on initial connection.
+         Being a server or having kline_exempt in auth{} does
+         <emphasis>not</emphasis> exempt (different from K/G/X:lines).
+       </para>
+      </sect2>
+      <sect2>
+       <title>UNDLINE</title>
+       <cmdsynopsis>
+         <command>UNDLINE</command>
+         <arg choice=plain><replaceable>a.b.c.d</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         Will attempt to remove a D:line from <filename>dline.conf</filename>, and will flush
+         a temporary D:line.
+       </para>
+      </sect2>
+      <sect2>
+       <title>GLINE</title>
+       <cmdsynopsis>
+         <command>GLINE</command>
+         <group>
+           <arg choice=plain><replaceable>user</replaceable>@<replaceable>host</replaceable></arg>
+           <arg choice=plain><replaceable>user</replaceable>@<replaceable>a</replaceable>.<replaceable>b</replaceable>.<replaceable>c</replaceable>.<replaceable>d</replaceable></arg>
+         </group>
+         <arg choice=plain>:<replaceable>reason</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         Attempts to add a network-wide ban for the given mask.
+         It takes three different opers on three different servers
+         requesting the same G:line to have it triggered for a configured
+         time.
+       </para>
+       <para>
+         Once triggered, a G:line is similar to a temporary K:line on
+         each server. No further propagation or on-disk storage is done.
+       </para>
+       <note><para>
+         This command can be enabled or disabled in the configuration file.
+         If it is disabled, no oper on the server can issue a G:line and no
+         G:lined user is banned, but G:lines are still propagated to other
+         servers which may have G:lines enabled.
+       </para></note>
+      </sect2>
+      <sect2>
+       <title>UNGLINE</title>
+       <cmdsynopsis>
+         <command>UNGLINE</command>
+         <group>
+           <arg choice=plain><replaceable>user</replaceable>@<replaceable>host</replaceable></arg>
+           <arg choice=plain><replaceable>user</replaceable>@<replaceable>a</replaceable>.<replaceable>b</replaceable>.<replaceable>c</replaceable>.<replaceable>d</replaceable></arg>
+         </group>
+       </cmdsynopsis>
+       <para>
+         Removes the given G:line on this server.
+       </para>
+      </sect2>
+      <sect2>
+       <title>TESTGECOS</title>
+       <cmdsynopsis>
+         <command>TESTGECOS</command>
+         <arg choice=plain><replaceable>gecos</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         Looks up X:Lines matching the given gecos.
+       </para>
+      </sect2>
+      <sect2>
+       <title>TESTLINE</title>
+       <cmdsynopsis>
+         <command>TESTLINE</command>
+         <arg><replaceable>nick</replaceable>!</arg>
+         <group>
+           <arg choice=plain><replaceable>user</replaceable>@<replaceable>host</replaceable></arg>
+           <arg choice=plain><replaceable>a</replaceable>.<replaceable>b</replaceable>.<replaceable>c</replaceable>.<replaceable>d</replaceable></arg>
+         </group>
+       </cmdsynopsis>
+       <para>
+         Looks up the given hostmask or IP address and reports back on any auth{} blocks, D:, G:, or K: lines found.
+         If <replaceable>nick</replaceable> is given, also searches for
+         nick resvs.
+       </para>
+       <para>
+         For temporary items the number of minutes until the item expires
+         is shown (as opposed to the hit count in STATS q/Q/x/X).
+       </para>
+        <para>
+         This command will not perform DNS lookups; for best
+         results you must testline a host and its IP form.
+        </para>
+       <para>
+         The given username should begin with a tilde (~) if identd is not
+         in use. As of charybdis 2.1.1, no_tilde and username truncation will
+         be taken into account like in the normal client access check.
+       </para>
+      </sect2>
+      <sect2>
+       <title>TESTMASK</title>
+        <cmdsynopsis>
+          <command>TESTMASK</command>
+          <arg choice=plain><replaceable>hostmask</replaceable></arg>
+         <arg><replaceable>gecos</replaceable></arg>
+        </cmdsynopsis>
+       <para>
+          Searches the network for users that match the hostmask and gecos given,
+         returning the number of matching users on this server and other servers.
+       </para>
+       <para>
+         The <replaceable>hostmask</replaceable> is of the form user@host
+         or user@ip/cidr with * and ? wildcards, optionally preceded by
+         nick!.
+       </para>
+       <para>
+         The <replaceable>gecos</replaceable> field accepts the same wildcards
+         as xlines.
+       </para>
+       <para>
+         The IP address checked against is 255.255.255.255 if the IP address
+         is unknown (remote client on a TS5 server) or 0 if the IP address
+         is hidden (auth{} spoof).
+       </para>
+      </sect2>
+      <sect2>
+       <title>LUSERS</title>
+       <cmdsynopsis>
+         <command>LUSERS</command>
+         <arg><replaceable>mask</replaceable></arg>
+         <group>
+           <arg><replaceable>nick</replaceable></arg>
+           <arg><replaceable>server</replaceable></arg>
+         </group>
+       </cmdsynopsis>
+       <para>
+         Shows various user and channel counts.
+       </para>
+       <para>
+         The <replaceable>mask</replaceable> parameter is obsolete
+         but must be used when querying a remote server.
+       </para>
+      </sect2>
+      <sect2>
+       <title>TRACE</title>
+       <cmdsynopsis>
+         <command>TRACE</command>
+         <group>
+           <arg><replaceable>server</replaceable></arg>
+           <arg><replaceable>nick</replaceable></arg>
+         </group>
+         <arg><replaceable>location</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         With no argument or one argument which is the current server,
+         TRACE gives a list of all connections to the current server
+         and a summary of connection classes.
+       </para>
+       <para>
+         With one argument which is another server, TRACE displays the path 
+         to the specified server, and all servers, opers and -i users
+         on that server, along with a summary of connection classes.
+       </para>
+       <para>
+         With one argument which is a client, TRACE displays the
+         path to that client, and that client's information.
+       </para>
+       <para>
+         If location is given, the command is executed on that server;
+         no path is displayed.
+       </para>
+       <para>
+         When listing connections, type, name and class is shown
+         in addition to information depending on the type:
+       </para>
+       <variablelist>
+         <title>TRACE types</title>
+         <varlistentry>
+           <term>Try.</term>
+           <listitem><para>
+             A server we are trying to make a TCP connection to.
+           </para></listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>H.S.</term>
+           <listitem><para>
+             A server we have established a TCP connection to, but is not
+             yet registered.
+           </para></listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>????</term>
+           <listitem><para>
+             An incoming connection that has not yet registered as
+             a user or a server (<quote>unknown</quote>).
+             Shows the username, hostname, IP address
+             and the time the connection has been open. It is possible
+             that the ident or DNS lookups have not completed yet, and in
+             any case no tildes are shown here.
+             Unknown connections may not have a name yet.
+           </para></listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>User</term>
+           <listitem><para>
+             A registered unopered user.
+             Shows the username, hostname, IP address, the time the client
+             has not sent anything (as in STATS l) and the time the user has
+             been idle (from PRIVMSG only, as in WHOIS).
+           </para></listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>Oper</term>
+           <listitem><para>
+             Like User, but opered.
+           </para></listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>Serv</term>
+           <listitem><para>
+             A registered server.
+             Shows the number of servers and users reached via this link,
+             who made this connection and the time the server has not sent
+             anything.
+           </para></listitem>
+         </varlistentry>
+       </variablelist>
+      </sect2>
+      <sect2>
+       <title>ETRACE</title>
+       <cmdsynopsis>
+         <command>ETRACE</command>
+         <arg><replaceable>nick</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         Shows client information about the given target, or about all local clients if
+         no target is specified.
+       </para>
+      </sect2>
+      <sect2>
+        <title>MASKTRACE</title>
+        <cmdsynopsis>
+          <command>MASKTRACE</command>
+          <arg choice=plain><replaceable>hostmask</replaceable></arg>
+         <arg><replaceable>gecos</replaceable></arg>
+        </cmdsynopsis>
+        <para>
+          Searches the local server or network for users that match the hostmask and gecos given.
+         Network searches require the oper_spy privilege and an '!'
+         before the hostmask.
+         The matching works the same way as TESTMASK.
+        </para>
+       <para>
+         The <replaceable>hostmask</replaceable> is of the form user@host
+         or user@ip/cidr with * and ? wildcards, optionally preceded by
+         nick!.
+       </para>
+       <para>
+         The <replaceable>gecos</replaceable> field accepts the same wildcards
+         as xlines.
+       </para>
+       <para>
+         The IP address field contains 255.255.255.255 if the IP address
+         is unknown (remote client on a TS5 server) or 0 if the IP address
+         is hidden (auth{} spoof).
+       </para>
+      </sect2>
+      <sect2>
+        <title>CHANTRACE</title>
+        <cmdsynopsis>
+          <command>CHANTRACE</command>
+          <arg choice=plain><replaceable>channel</replaceable></arg>
+        </cmdsynopsis>
+        <para>
+         Displays information about users in a channel.
+         Opers with the oper_spy privilege
+         can get the information without being on the channel,
+         by prefixing the channel name with an '!'.
+        </para>
+       <para>
+         The IP address field contains 255.255.255.255 if the IP address
+         is unknown (remote client on a TS5 server) or 0 if the IP address
+         is hidden (auth{} spoof).
+       </para>
+      </sect2>
+      <sect2>
+        <title>SCAN</title>
+        <cmdsynopsis>
+          <command>SCAN UMODES</command>
+          <arg choice=plain>+<replaceable>modes</replaceable>-<replaceable>modes</replaceable></arg>
+         <arg>no-list</arg>
+         <arg>list</arg>
+         <arg>global</arg>
+         <arg>list-max <replaceable>number</replaceable></arg>
+         <arg>mask <replaceable>nick!user@host</replaceable></arg>
+        </cmdsynopsis>
+        <para>
+          Searches the local server or network for users that have the umodes given with + and do not have the umodes given with -.
+          no-list disables the listing of matching users and only shows the count.
+         list enables the listing (default).
+         global extends the search to the entire network instead of local users only.
+         list-max limits the listing of matching users to the given amount.
+         mask causes only users matching the given nick!user@host mask
+         to be selected. Only the displayed host is considered, not the
+         IP address or real host behind dynamic spoofs.
+       </para>
+       <para>
+         The IP address field contains 255.255.255.255 if the IP address
+         is unknown (remote client on a TS5 server) or 0 if the IP address
+         is hidden (auth{} spoof).
+       </para>
+       <para>
+         Network searches where a listing is given or the mask option is used
+         are operspy commands.
+        </para>
+      </sect2>
+      <sect2>
+       <title>CHGHOST</title>
+       <cmdsynopsis>
+         <command>CHGHOST</command>
+         <arg choice=plain><replaceable>nick</replaceable></arg>
+         <arg choice=plain><replaceable>value</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         Set the hostname associated with a particular nick for the duration of this session.
+         This command is disabled by default because of the abuse potential
+         and little practical use.
+       </para>
+      </sect2>
+    </sect1>
+    <sect1 id="misccommands">
+      <title>Miscellaneous commands</title>
+      <sect2>
+       <title>ADMIN</title>
+       <cmdsynopsis>
+         <command>ADMIN</command>
+         <group>
+           <arg><replaceable>nick</replaceable></arg>
+           <arg><replaceable>server</replaceable></arg>
+         </group>
+       </cmdsynopsis>
+       <para>
+         Shows the information in the admin{} block.
+       </para>
+      </sect2>
+      <sect2>
+       <title>INFO</title>
+       <cmdsynopsis>
+         <command>INFO</command>
+         <group>
+           <arg><replaceable>nick</replaceable></arg>
+           <arg><replaceable>server</replaceable></arg>
+         </group>
+       </cmdsynopsis>
+       <para>
+         Shows information about the authors of the IRC server, and
+         some information about this server instance.
+         Opers also get a list of configuration options.
+       </para>
+      </sect2>
+      <sect2>
+       <title>TIME</title>
+       <cmdsynopsis>
+         <command>TIME</command>
+         <group>
+           <arg><replaceable>nick</replaceable></arg>
+           <arg><replaceable>server</replaceable></arg>
+         </group>
+       </cmdsynopsis>
+       <para>
+         Shows the local time on the given server, in a human-readable format.
+       </para>
+      </sect2>
+      <sect2>
+       <title>VERSION</title>
+       <cmdsynopsis>
+         <command>VERSION</command>
+         <group>
+           <arg><replaceable>nick</replaceable></arg>
+           <arg><replaceable>server</replaceable></arg>
+         </group>
+       </cmdsynopsis>
+       <para>
+         Shows version information, a few compile/config options,
+         the SID and the 005 numerics.
+         The 005 numeric will be remapped to 105 for remote requests.
+       </para>
+      </sect2>
+      <sect2>
+       <title>STATS</title>
+       <cmdsynopsis>
+         <command>STATS</command>
+         <arg><replaceable>type</replaceable></arg>
+         <group>
+           <arg><replaceable>nick</replaceable></arg>
+           <arg><replaceable>server</replaceable></arg>
+         </group>
+       </cmdsynopsis>
+       <para>
+         Display various statistics and configuration information.
+       </para>
+       <variablelist>
+         <title>Values for <replaceable>type</replaceable></title>
+         <varlistentry>
+           <term>A</term>
+           <listitem>
+             <para>Show DNS servers</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>b</term>
+           <listitem>
+             <para>Show active nick delays</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>B</term>
+           <listitem>
+             <para>Show hash statistics</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>c</term>
+           <listitem>
+             <para>Show connect blocks</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>d</term>
+           <listitem>
+             <para>Show temporary D:lines</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>D</term>
+           <listitem>
+             <para>Show permanent D:lines</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>e</term>
+           <listitem>
+             <para>Show exempt blocks (exceptions to D:lines)</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>E</term>
+           <listitem>
+             <para>Show events</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>f</term>
+           <listitem>
+             <para>Show file descriptors</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>g</term>
+           <listitem>
+             <para>Show pending glines</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>G</term>
+           <listitem>
+             <para>Show active glines</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>h</term>
+           <listitem>
+             <para>Show hub_mask/leaf_mask</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>i</term>
+           <listitem>
+             <para>Show auth blocks, or matched auth blocks</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>k</term>
+           <listitem>
+             <para>Show temporary K:lines, or matched temporary K:lines</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>K</term>
+           <listitem>
+             <para>Show permanent K:lines, or matched permanent K:lines</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>l</term>
+           <listitem>
+             <para>
+               Show hostname and link information about the given nick.
+               With a server name, show information about opers and servers
+               on that server; opers also get information about all local users
+               if they query their own server.
+             </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>L</term>
+           <listitem>
+             <para>Like l, but show IP address instead of hostname</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>m</term>
+           <listitem>
+             <para>Show commands and their usage statistics (total counts, total bytes, counts from server connections)</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>n</term>
+           <listitem>
+             <para>Show blacklist blocks (DNS blacklists) with hit counts.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>o</term>
+           <listitem>
+             <para>Show operator blocks</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>p</term>
+           <listitem>
+             <para>Show logged on network operators which are not set AWAY.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>P</term>
+           <listitem>
+             <para>Show listen blocks</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>q</term>
+           <listitem>
+             <para>Show temporarily resv'ed nicks and channels</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>Q</term>
+           <listitem>
+             <para>Show permanently resv'ed nicks and channels</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>r</term>
+           <listitem>
+             <para>Show resource usage by the ircd</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>t</term>
+           <listitem>
+             <para>Show generic server statistics</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>u</term>
+           <listitem>
+             <para>Show server uptime</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>U</term>
+           <listitem>
+             <para>Show shared (c), cluster (C) and service (s) blocks</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>v</term>
+           <listitem>
+             <para>Show connected servers and brief status</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>x</term>
+           <listitem>
+             <para>Show temporary X:lines</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>X</term>
+           <listitem>
+             <para>Show permanent X:lines</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>y</term>
+           <listitem>
+             <para>Show class blocks</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>z</term>
+           <listitem>
+             <para>Show memory usage statistics</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>Z</term>
+           <listitem>
+             <para>Show ziplinks statistics</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>?</term>
+           <listitem>
+             <para>Show connected servers and sendq information about them</para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+      </sect2>
+      <sect2>
+       <title>WALLOPS</title>
+       <cmdsynopsis>
+         <command>WALLOPS</command>
+         <arg choice=plain>:<replaceable>message</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         Sends a WALLOPS message to all users who have the +w umode set. This is for
+         things you don't mind the whole network knowing about.
+       </para>
+      </sect2>
+      <sect2>
+       <title>OPERWALL</title>
+       <cmdsynopsis>
+         <command>OPERWALL</command>
+         <arg choice=plain>:<replaceable>message</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         Sends an OPERWALL message to all opers who have the +z umode set. +z is restricted,
+         OPERWALL should be considered private communications.
+       </para>
+      </sect2>
+    </sect1>
+  </chapter>
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-namecase-general:t
+sgml-general-insert-case:lower
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document: ("charybdis-oper-guide.sgml" "book")
+sgml-exposed-tags:nil
+sgml-local-ecat-files:nil
+fill-column:105
+End:
+-->
diff --git a/doc/sgml/oper-guide/config.sgml b/doc/sgml/oper-guide/config.sgml
new file mode 100644 (file)
index 0000000..e3c0950
--- /dev/null
@@ -0,0 +1,1101 @@
+  <chapter id="config">
+    <title>Server config file format</title>
+    <sect1>
+      <title>General format</title>
+      <para>
+       The config file consists of a series of BIND-style blocks. Each block consists of a series
+       of values inside it which pertain to configuration settings that apply to the given block.
+      </para>
+      <para>
+       Several values take lists of values and have defaults preset inside
+       them. Prefix a keyword with a tilde (~) to override the default and
+       disable it.
+      </para>
+      <para>
+       A line may also be a .include directive, which is of the form <synopsis>.include "<replaceable>file</replaceable>"</synopsis>
+       and causes <replaceable>file</replaceable> to be read in at that point, before the rest of the current file is
+       processed.
+       Relative paths are first tried relative to PREFIX and then relative
+       to ETCPATH (normally PREFIX/etc).
+      </para>
+      <para>
+       Anything from a # to the end of a line is a comment. Blank lines are ignored. C-style comments are also supported.
+      </para>
+    </sect1>
+    <sect1 id="configlines">
+      <title>Specific blocks and directives</title>
+      <para>
+       Not all configuration blocks and directives are listed here, only the most common ones. More blocks and directives will
+       be documented in later revisions of this manual.
+      </para>
+      <sect2>
+       <title>loadmodule directive</title>
+       <synopsis>
+loadmodule "<replaceable>text</replaceable>";</synopsis>
+       <para>
+         Loads a module into the IRCd. In charybdis 1.1, most modules are automatically loaded in. In future versions, it is
+         intended to remove this behaviour as to allow for easy customization of the IRCd's featureset.
+       </para>
+      </sect2>
+      <sect2>
+       <title>serverinfo {} block</title>
+       <synopsis>
+serverinfo {
+        name = "<replaceable>text</replaceable>";
+        use_ts6 = <replaceable>boolean</replaceable>;
+        sid = "<replaceable>text</replaceable>";
+        description = "<replaceable>text</replaceable>";
+        network_name = "<replaceable>text</replaceable>";
+        network_desc = "<replaceable>text</replaceable>";
+        hub = <replaceable>boolean</replaceable>;
+        vhost = "<replaceable>text</replaceable>";
+        vhost6 = "<replaceable>text</replaceable>";
+};</synopsis>
+       <para>
+         The serverinfo {} block defines the core operational parameters of the IRC server.
+       </para>
+       <variablelist>
+         <title>serverinfo {} variables</title>
+         <varlistentry>
+           <term>name</term>
+           <listitem>
+             <para>
+               The name of the IRC server that you are configuring. This
+               must contain at least one dot. It is not necessarily equal
+               to any DNS name. This must be unique on the IRC network.
+             </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>use_ts6</term>
+           <listitem>
+             <para>
+                A boolean which defines whether or not you want to use the new TS6 protocol, which provides
+                many improvements over the old protocol, TS5, which is used in Hyperion.
+              </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>sid</term>
+           <listitem>
+             <para>
+                A unique ID which describes the server. This is required regardless of whether you are using
+               TS6 or not.
+               This consists of one digit and two characters which can be
+               digits or letters.
+             </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>description</term>
+           <listitem>
+             <para>
+               A user-defined field of text which describes the IRC server. This information is used in
+               /links and /whois requests. Geographical location information could be a useful use of
+               this field, but most administrators put a witty saying inside it instead.
+             </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>network_name</term>
+           <listitem>
+             <para>
+               The name of the IRC network that this server will be a member of.
+               This is used in the welcome message and NETWORK= in 005.
+             </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>network_desc</term>
+           <listitem>
+             <para>
+               A description of the IRC network that this server will be a member of.
+               This is currently unused.
+             </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>hub</term>
+           <listitem>
+             <para>
+               A boolean which defines whether or not this IRC server will be serving as a hub, i.e. have multiple servers connected to it.
+             </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>vhost</term>
+           <listitem>
+             <para>
+               An optional text field which defines an IP from which to connect outward to other IRC servers.
+             </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>vhost6</term>
+           <listitem>
+             <para>
+               An optional text field which defines an IPv6 IP from which to connect outward to other IRC servers.
+             </para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+      </sect2>
+      <sect2>
+       <title>admin {} block</title>
+       <synopsis>
+admin {
+       name = "<replaceable>text</replaceable>";
+       description = "<replaceable>text</replaceable>";
+       email = "<replaceable>text</replaceable>";
+};</synopsis>
+       <para>
+         This block provides the information which is returned by the ADMIN command.
+       </para>
+       <variablelist>
+         <title>admin {} variables</title>
+         <varlistentry>
+           <term>name</term>
+           <listitem>
+             <para>The name of the administrator running this service.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>description</term>
+           <listitem>
+             <para>The description of the administrator's position in the network.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>email</term>
+           <listitem>
+             <para>A point of contact for the administrator, usually an e-mail address.</para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+      </sect2>
+      <sect2>
+       <title>class {} block</title>
+       <synopsis>
+class "<replaceable>name</replaceable>" {
+        ping_time = <replaceable>duration</replaceable>;
+        number_per_ident = <replaceable>number</replaceable>;
+        number_per_ip = <replaceable>number</replaceable>;
+        number_per_ip_global = <replaceable>number</replaceable>;
+        cidr_bitlen = <replaceable>number</replaceable>;
+        number_per_cidr = <replaceable>number</replaceable>;
+        max_number = <replaceable>number</replaceable>;
+        sendq = <replaceable>size</replaceable>;
+};</synopsis>
+       <synopsis>
+class "<replaceable>name</replaceable>" {
+        ping_time = <replaceable>duration</replaceable>;
+        connectfreq = <replaceable>duration</replaceable>;
+        max_number = <replaceable>number</replaceable>;
+        sendq = <replaceable>size</replaceable>;
+};</synopsis>
+       <para>
+         Class blocks define classes of connections for later use.
+         The class name is used to connect them to
+         other blocks in the config file (auth{} and connect{}).
+         They must be defined before they are used.
+       </para>
+       <para>
+         Classes are used both for client and server connections,
+         but most variables are different.
+       </para>
+       <variablelist>
+         <title>class {} variables: client classes</title>
+         <varlistentry>
+           <term>ping_time</term>
+           <listitem>
+             <para>The amount of time between checking pings for clients, e.g.: 2 minutes</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>number_per_ident</term>
+           <listitem>
+             <para>The amount of clients which may be connected from a single identd username on a per-IP basis, globally. Unidented clients all count as the same username.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>number_per_ip</term>
+           <listitem>
+             <para>The amount of clients which may be connected from a single IP address.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>number_per_ip_global</term>
+           <listitem>
+             <para>The amount of clients which may be connected globally from a single IP address.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>cidr_bitlen</term>
+           <listitem>
+             <para>The netblock length to use with CIDR-based client limiting for this class.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>number_per_cidr</term>
+           <listitem>
+             <para>The amount of clients which may be connected from a single netblock.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>max_number</term>
+           <listitem>
+             <para>The maximum amount of clients which may use this class at any given time.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>sendq</term>
+           <listitem>
+             <para>The maximum size of the queue of data to be sent to a client before it is dropped.</para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+       <variablelist>
+         <title>class {} variables: server classes</title>
+         <varlistentry>
+           <term>ping_time</term>
+           <listitem>
+             <para>The amount of time between checking pings for servers, e.g.: 2 minutes</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>connectfreq</term>
+           <listitem>
+             <para>The amount of time between autoconnects. This must at least be one minute, as autoconnects are evaluated with that granularity.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>max_number</term>
+           <listitem>
+             <para>The amount of servers to autoconnect to in this class. More precisely, no autoconnects are done if the number of servers in this class is greater than or equal max_number</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>sendq</term>
+           <listitem>
+             <para>The maximum size of the queue of data to be sent to a server before it is dropped.</para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+      </sect2>
+      <sect2>
+       <title>auth {} block</title>
+       <synopsis>
+auth {
+       user = "<replaceable>hostmask</replaceable>";
+       password = "<replaceable>text</replaceable>";
+       spoof = "<replaceable>text</replaceable>";
+       flags = <replaceable>list</replaceable>;
+       class = "<replaceable>text</replaceable>";
+};</synopsis>
+       <para>
+         auth {} blocks allow client connections to the server, and set various properties concerning those connections.
+       </para>
+        <para>
+          Auth blocks are evaluated from top to bottom in priority, so put special blocks first.
+        </para>
+       <variablelist>
+         <title>auth {} variables</title>
+         <varlistentry>
+            <term>user</term>
+            <listitem>
+              <para>A hostmask (user@host) that the auth{} block is matched against. You can have multiple user entries.</para>
+            </listitem>
+          </varlistentry>
+         <varlistentry>
+            <term>password</term>
+            <listitem>
+              <para>
+               An optional password to use for authenticating into this auth{}
+               block.  If the password is wrong the user will not be able to
+               connect (will not fall back on another auth{} block).
+             </para>
+            </listitem>
+          </varlistentry>
+         <varlistentry>
+            <term>spoof</term>
+            <listitem>
+              <para>An optional fake hostname (or user@host) to apply to users authenticated to this auth{} block.</para>
+            </listitem>
+          </varlistentry>
+         <varlistentry>
+            <term>flags</term>
+            <listitem>
+              <para>A list of flags to apply to this auth{} block. They are listed below.</para>
+            </listitem>
+          </varlistentry>
+         <varlistentry>
+            <term>class</term>
+            <listitem>
+              <para>A name of a class to put users matching this auth{} block into.</para>
+            </listitem>
+          </varlistentry>
+        </variablelist>
+       <variablelist>
+         <title>auth {} flags</title>
+         <varlistentry>
+           <term>encrypted</term>
+           <listitem>
+             <para>The password used has been encrypted.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>spoof_notice</term>
+           <listitem>
+             <para>Causes the IRCd to send out a server notice when activating a spoof provided by this auth{} block.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>exceed_limit</term>
+           <listitem>
+             <para>Users in this auth{} block can exceed class-wide limitations.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>dnsbl_exempt</term>
+           <listitem>
+             <para>Users in this auth{} block are exempted from DNS blacklist checks. However, they will still be warned if they are listed.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>kline_exempt</term>
+           <listitem>
+             <para>Users in this auth{} block are exempted from DNS blacklists, k:lines, g:lines and x:lines, and will not be disconnected because of d:lines.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>gline_exempt</term>
+           <listitem>
+             <para>Users in this auth{} block are exempted from g:lines.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>spambot_exempt</term>
+           <listitem>
+             <para>Users in this auth{} block are exempted from spambot checks.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>shide_exempt</term>
+           <listitem>
+             <para>Users in this auth{} block are exempted from some serverhiding effects.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>jupe_exempt</term>
+           <listitem>
+             <para>Users in this auth{} block do not trigger an alarm when joining juped channels.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>resv_exempt</term>
+           <listitem>
+             <para>Users in this auth{} block may use reserved nicknames and channels.</para>
+             <note><para>The initial nickname may still not be reserved.</para></note>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>flood_exempt</term>
+           <listitem>
+             <para>
+                Users in this auth{} block may send arbitrary amounts of
+               commands per time unit to the server. This does not exempt
+               them from any other flood limits.
+                You should use this setting with caution.
+              </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>no_tilde</term>
+           <listitem>
+             <para>Users in this auth{} block will not have a tilde added to their username if they do not run identd.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>need_ident</term>
+           <listitem>
+             <para>Users in this auth{} block must have identd, otherwise they will be rejected.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>need_sasl</term>
+           <listitem>
+             <para>Users in this auth{} block must identify via SASL, otherwise they will be rejected.</para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+      </sect2>
+      <sect2>
+       <title>exempt {} block</title>
+       <synopsis>
+exempt {
+       ip = "<replaceable>ip</replaceable>";
+};</synopsis>
+       <para>
+         An exempt block specifies IP addresses which are exempt from D:lines.
+         Multiple addresses can be specified in one block.
+         Clients coming from these addresses can still be K/G/X:lined or
+         banned by a DNS blacklist unless
+         they also have appropriate flags in their auth{} block.
+       </para>
+       <variablelist>
+         <title>exempt {} variables</title>
+         <varlistentry>
+           <term>ip</term>
+           <listitem>
+             <para>The IP address or CIDR range to exempt.</para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+      </sect2>
+      <sect2>
+       <title>operator {} block</title>
+       <synopsis>
+operator "<replaceable>name</replaceable>" {
+       user = "<replaceable>hostmask</replaceable>";
+       password = "<replaceable>text</replaceable>";
+       rsa_public_key_file = "<replaceable>text</replaceable>";
+       umodes = <replaceable>list</replaceable>;
+       snomask = "<replaceable>text</replaceable>";
+       flags = <replaceable>list</replaceable>;
+};</synopsis>
+       <para>
+         Operator blocks define who may use the OPER command to gain extended privileges.
+       </para>
+        <variablelist>
+          <title>operator {} variables</title>
+         <varlistentry>
+           <term>user</term>
+           <listitem>
+             <para>
+               A hostmask that users trying to use this operator {} block
+               must match. This is checked against the original host and IP
+               address; CIDR is also supported. So auth {} spoofs work in
+               operator {} blocks; the real host behind them is not checked.
+               Other kind of spoofs do not work in operator {} blocks; the
+               real host behind them is checked.
+             </para>
+             <para>
+               Note that this is different from charybdis 1.x where all
+               kinds of spoofs worked in operator {} blocks.
+             </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>password</term>
+           <listitem>
+              <para>
+               A password used with the OPER command to use this operator {} block.
+               Passwords are encrypted by default, but may be unencrypted if ~encrypted is present
+               in the flags list.
+             </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>rsa_public_key_file</term>
+           <listitem>
+              <para>
+               An optional path to a RSA public key file associated with the operator {} block.
+               This information is used by the CHALLENGE command, which is an alternative authentication
+               scheme to the traditional OPER command.
+             </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>umodes</term>
+           <listitem>
+              <para>A list of usermodes to apply to successfully opered clients.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>snomask</term>
+           <listitem>
+              <para>
+               An snomask to apply to successfully opered clients.
+             </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>flags</term>
+           <listitem>
+              <para>
+               A listing of privileges granted to operators using this block.
+               By default, the operwall and remoteban privileges are granted;
+               use ~operwall and ~remoteban to disable them if necessary.
+             </para>
+             <para>
+               In addition, a flag designating if the password is encrypted is here.
+               Privileges are documented elsewhere in this guide.
+             </para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+      </sect2>
+      <sect2>
+       <title>connect {} block</title>
+       <synopsis>
+connect "<replaceable>name</replaceable>" {
+       host = "<replaceable>text</replaceable>";
+       send_password = "<replaceable>text</replaceable>";
+       accept_password = "<replaceable>text</replaceable>";
+       port = <replaceable>number</replaceable>;
+       hub_mask = "<replaceable>mask</replaceable>";
+       leaf_mask = "<replaceable>mask</replaceable>";
+       class = "<replaceable>text</replaceable>";
+       flags = <replaceable>list</replaceable>;
+       aftype = <replaceable>protocol</replaceable>;
+};</synopsis>
+       <para>
+         Connect blocks define what servers may connect or be connected to.
+       </para>
+       <variablelist>
+         <title>connect {} variables</title>
+         <varlistentry>
+           <term>host</term>
+           <listitem>
+             <para>The hostname or IP to connect to.</para>
+             <note><para>
+               Charybdis uses solely DNS for all hostname/address lookups
+               (no <filename>/etc/hosts</filename> or anything else).
+               Furthermore, if a hostname is used, it must have an A or AAAA
+               record (no CNAME) and it must be the primary
+               hostname for inbound connections to work.
+             </para></note>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>send_password</term>
+           <listitem>
+             <para>The password to send to the other server.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>accept_password</term>
+           <listitem>
+             <para>The password that should be accepted from the other server.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>port</term>
+           <listitem>
+             <para>The port on the other server to connect to.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>hub_mask</term>
+           <listitem>
+             <para>
+               An optional domain mask of servers allowed to be introduced
+               by this link. Usually, "*" is fine. Multiple hub_masks may be
+               specified, and any of them may be introduced.
+               Violation of hub_mask and leaf_mask restrictions will
+               cause the local link to be closed.
+             </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>leaf_mask</term>
+           <listitem>
+             <para>
+               An optional domain mask of servers not allowed to be
+               introduced by this link. Multiple leaf_masks may be specified,
+               and none of them may be introduced. leaf_mask has priority
+               over hub_mask.
+             </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>class</term>
+           <listitem>
+             <para>The name of the class this server should be placed into.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>flags</term>
+           <listitem>
+             <para>A list of flags concerning the connect block. They are listed below.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>aftype</term>
+           <listitem>
+             <para>The protocol that should be used to connect with, either ipv4 or ipv6. This defaults to ipv4 unless host is a numeric IPv6 address.</para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+       <variablelist>
+         <title>connect {} flags</title>
+         <varlistentry>
+           <term>encrypted</term>
+           <listitem>
+             <para>The value for accept_password has been encrypted.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>autoconn</term>
+           <listitem>
+             <para>
+               The server should automatically try to connect to the server defined in this 
+               connect {} block if it's not connected already and max_number
+               in the class is not reached yet.
+              </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>compressed</term>
+           <listitem>
+             <para>Ziplinks should be used with this server connection.
+             This compresses traffic using zlib, saving some bandwidth
+             and speeding up netbursts.</para>
+             <para>If you have trouble setting up a link, you should
+             turn this off as it often hides error messages.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>topicburst</term>
+           <listitem>
+             <para>Topics should be bursted to this server.</para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+      </sect2>
+      <sect2>
+       <title>listen {} block</title>
+       <synopsis>
+listen {
+       host = "<replaceable>text</replaceable>";
+       port = <replaceable>number</replaceable>;
+};</synopsis>
+       <para>
+         A listen block specifies what ports a server should listen on.
+       </para>
+       <variablelist>
+         <title>listen {} variables</title>
+         <varlistentry>
+           <term>host</term>
+           <listitem>
+             <para>An optional host to bind to. Otherwise, the ircd will listen on all available hosts.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>port</term>
+           <listitem>
+             <para>
+               A port to listen on. You can specify multiple ports via commas, and define a range by seperating
+               the start and end ports with two dots (..).
+             </para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+      </sect2>
+      <sect2>
+       <title>modules {} block</title>
+       <synopsis>
+modules {
+       path = "<replaceable>text</replaceable>";
+       module = <replaceable>text</replaceable>;
+};</synopsis>
+       <para>
+         The modules block specifies information for loadable modules.
+       </para>
+       <variablelist>
+         <title>modules {} variables</title>
+         <varlistentry>
+           <term>path</term>
+           <listitem>
+             <para>Specifies a path to search for loadable modules.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>module</term>
+           <listitem>
+             <para>
+               Specifies a module to load, similar to loadmodule.
+             </para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+      </sect2>
+      <sect2>
+       <title>general {} block</title>
+       <synopsis>
+modules {
+       <replaceable>values</replaceable>
+};</synopsis>
+       <para>
+         The general block specifies a variety of options, many of which
+         were in <filename>config.h</filename> in older daemons.
+         The options are documented in <filename>reference.conf</filename>.
+       </para>
+      </sect2>
+      <sect2>
+       <title>channel {} block</title>
+       <synopsis>
+modules {
+       <replaceable>values</replaceable>
+};</synopsis>
+       <para>
+         The channel block specifies a variety of channel-related options,
+         many of which were in <filename>config.h</filename> in older daemons.
+         The options are documented in <filename>reference.conf</filename>.
+       </para>
+      </sect2>
+      <sect2>
+       <title>serverhide {} block</title>
+       <synopsis>
+modules {
+       <replaceable>values</replaceable>
+};</synopsis>
+       <para>
+         The serverhide block specifies options related to server hiding.
+         The options are documented in <filename>reference.conf</filename>.
+       </para>
+      </sect2>
+      <sect2>
+       <title>blacklist {} block</title>
+       <synopsis>
+blacklist {
+       host = "<replaceable>text</replaceable>";
+       reject_reason = "<replaceable>text</replaceable>";
+};</synopsis>
+       <para>
+         The blacklist block specifies DNS blacklists to check.
+         Listed clients will not be allowed to connect.
+         IPv6 clients are not checked against these.
+       </para>
+       <para>
+         Multiple blacklists can be specified, in pairs with first host
+         then reject_reason.
+       </para>
+       <variablelist>
+         <title>blacklist {} variables</title>
+         <varlistentry>
+           <term>host</term>
+           <listitem>
+             <para>The DNSBL to use.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>reject_reason</term>
+           <listitem>
+             <para>The reason to send to listed clients when disconnecting them.</para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+      </sect2>
+      <sect2>
+       <title>alias {} block</title>
+       <synopsis>
+alias "<replaceable>name</replaceable>" {
+       target = "<replaceable>text</replaceable>";
+};</synopsis>
+       <para>
+         Alias blocks allow the definition of custom commands.
+         These commands send PRIVMSG to the given target. A real
+         command takes precedence above an alias.
+       </para>
+       <variablelist>
+         <title>alias {} variables</title>
+         <varlistentry>
+           <term>target</term>
+           <listitem>
+             <para>
+               The target nick (must be a network service (umode +S)) or
+               user@server.
+               In the latter case, the server cannot be this server,
+               only opers can use user starting with "opers" reliably and
+               the user is interpreted on the target server only
+               so you may need to use nick@server instead).
+             </para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+      </sect2>
+      <sect2>
+       <title>cluster {} block</title>
+       <synopsis>
+cluster {
+       name = "<replaceable>text</replaceable>";
+       flags = <replaceable>list</replaceable>;
+};</synopsis>
+       <para>
+         The cluster block specifies servers we propagate things to
+         automatically.
+         This does not allow them to set bans, you need a separate shared{}
+         block for that.
+       </para>
+       <para>
+         Having overlapping cluster{} items will cause the command to
+         be executed twice on the target servers. This is particularly
+         undesirable for ban removals.
+       </para>
+       <para>
+         The letters in parentheses denote the flags in /stats U.
+       </para>
+       <variablelist>
+         <title>cluster {} variables</title>
+         <varlistentry>
+           <term>name</term>
+           <listitem>
+             <para>The server name to share with, this may contain wildcards
+             and may be stacked.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>flags</term>
+           <listitem>
+             <para>The list of what to share, all the name lines above this
+             (up to another flags entry) will receive these flags.
+             They are listed below.</para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+       <variablelist>
+         <title>cluster {} flags</title>
+         <varlistentry>
+           <term>kline (K)</term>
+           <listitem>
+             <para>Permanent K:lines</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>tkline (k)</term>
+           <listitem>
+             <para>Temporary K:lines</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>unkline (U)</term>
+           <listitem>
+             <para>K:line removals</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>xline (X)</term>
+           <listitem>
+             <para>Permanent X:lines</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>txline (x)</term>
+           <listitem>
+             <para>Temporary X:lines</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>unxline (Y)</term>
+           <listitem>
+             <para>X:line removals</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>resv (Q)</term>
+           <listitem>
+             <para>Permanently reserved nicks/channels</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>tresv (q)</term>
+           <listitem>
+             <para>Temporarily reserved nicks/channels</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>unresv (R)</term>
+           <listitem>
+             <para>RESV removals</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>locops (L)</term>
+           <listitem>
+             <para>LOCOPS messages (sharing this with * makes LOCOPS rather
+             similar to OPERWALL which is not useful)</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>all</term>
+           <listitem>
+             <para>All of the above</para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+      </sect2>
+      <sect2>
+       <title>shared {} block</title>
+       <synopsis>
+shared {
+       oper = "<replaceable>user@host</replaceable>", "<replaceable>server</replaceable>";
+       flags = <replaceable>list</replaceable>;
+};</synopsis>
+       <para>
+         The shared block specifies opers allowed to perform certain actions
+         on our server remotely.
+         These are ordered top down. The first one matching will determine
+         the oper's access.
+         If access is denied, the command will be silently ignored.
+       </para>
+       <para>
+         The letters in parentheses denote the flags in /stats U.
+       </para>
+       <variablelist>
+         <title>shared {} variables</title>
+         <varlistentry>
+           <term>oper</term>
+           <listitem>
+             <para>The user@host the oper must have, and the server they must
+             be on. This may contain wildcards.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>flags</term>
+           <listitem>
+             <para>The list of what to allow, all the oper lines above this
+             (up to another flags entry) will receive these flags.
+             They are listed below.</para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+       <note><para>
+         While they have the same names, the flags have subtly different
+         meanings from those in the cluster{} block.
+       </para></note>
+       <variablelist>
+         <title>shared {} flags</title>
+         <varlistentry>
+           <term>kline (K)</term>
+           <listitem>
+             <para>Permanent and temporary K:lines</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>tkline (k)</term>
+           <listitem>
+             <para>Temporary K:lines</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>unkline (U)</term>
+           <listitem>
+             <para>K:line removals</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>xline (X)</term>
+           <listitem>
+             <para>Permanent and temporary X:lines</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>txline (x)</term>
+           <listitem>
+             <para>Temporary X:lines</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>unxline (Y)</term>
+           <listitem>
+             <para>X:line removals</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>resv (Q)</term>
+           <listitem>
+             <para>Permanently and temporarily reserved nicks/channels</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>tresv (q)</term>
+           <listitem>
+             <para>Temporarily reserved nicks/channels</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>unresv (R)</term>
+           <listitem>
+             <para>RESV removals</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>all</term>
+           <listitem>
+             <para>All of the above; this does not include locops or rehash</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>locops (L)</term>
+           <listitem>
+             <para>LOCOPS messages (accepting this from * makes LOCOPS rather
+             similar to OPERWALL which is not useful); unlike the other flags,
+             this can only be accepted from *@* although it can be
+             restricted based on source server.</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>rehash (H)</term>
+           <listitem>
+             <para>REHASH commands; all options can be used</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>none</term>
+           <listitem>
+             <para>Allow nothing to be done</para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+      </sect2>
+      <sect2>
+       <title>service {} block</title>
+       <synopsis>
+service {
+       name = "<replaceable>text</replaceable>";
+};</synopsis>
+       <para>
+         The service block specifies privileged servers (services). These
+         servers have extra privileges such as setting login names on users
+         and introducing clients with umode +S (unkickable, hide channels, etc).
+         This does not allow them to set bans, you need a separate shared{}
+         block for that.
+       </para>
+       <para>
+         Do not place normal servers here.
+       </para>
+       <para>
+         Multiple names may be specified but there may be only one service{}
+         block.
+       </para>
+       <variablelist>
+         <title>service {} variables</title>
+         <varlistentry>
+           <term>name</term>
+           <listitem>
+             <para>The server name to grant special privileges. This may not
+             contain wildcards.</para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+      </sect2>
+    </sect1>
+  </chapter>
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-namecase-general:t
+sgml-general-insert-case:lower
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document: ("dancer-oper-guide.sgml" "book")
+sgml-exposed-tags:nil
+fill-column:105
+sgml-validate-command: "nsgmls -e -g -s -u dancer-oper-guide.sgml"
+End:
+-->
diff --git a/doc/sgml/oper-guide/intro.sgml b/doc/sgml/oper-guide/intro.sgml
new file mode 100644 (file)
index 0000000..1f90c69
--- /dev/null
@@ -0,0 +1,41 @@
+  <chapter id="intro">
+    <title>Introduction</title>
+    <sect1>
+      <title>Scope of this document</title>
+      <para>
+       This document describes the commands and functions available to operators in
+       the charybdis ircd, as used on <ulink url="http://www.atheme.net">AthemeNet</ulink>.
+      </para>
+      <para>
+        This document, and various ideas for features of charybdis, have
+       been taken from dancer-ircd/hyperion, the ircd used on freenode,
+       mainly written by Andrew Suffield and Jilles Tjoelker.
+      </para>
+      <para>
+       While this document may be of some interest to the users of charybdis servers,
+       it is intended as a reference for network staff.
+      </para>
+      <para>
+       Charybdis is based on ircd-ratbox 2.1.4, although much has changed.
+       <ulink url="http://www.ircd-ratbox.org">ircd-ratbox</ulink> is commonly used
+       on efnet, and some other networks.
+      </para>
+    </sect1>
+  </chapter>
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-namecase-general:t
+sgml-general-insert-case:lower
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document: ("charybdis-oper-guide.sgml" "book")
+sgml-exposed-tags:nil
+fill-column:105
+sgml-validate-command: "nsgmls -e -g -s -u charybdis-oper-guide.sgml"
+End:
+-->
diff --git a/doc/sgml/oper-guide/oprivs.sgml b/doc/sgml/oper-guide/oprivs.sgml
new file mode 100644 (file)
index 0000000..c5d5d72
--- /dev/null
@@ -0,0 +1,169 @@
+  <chapter id="oprivs">
+    <title>Oper privileges</title>
+    <sect1 id="oprivlist">
+      <title>Meanings of oper privileges</title>
+      <para>
+        These are flags in operator{}.
+        The letter appears after opering up and in /stats o; an uppercase
+        letter means the privilege is possessed, lowercase means it is not.
+      </para>
+      <sect2>
+       <title>admin (A), server administrator</title>
+       <para>
+         Various privileges intended for server administrators.
+         Among other things, this automatically sets umode +a and allows
+         loading modules.
+       </para>
+      </sect2>
+      <sect2>
+       <title>remoteban (B), set remote bans</title>
+       <para>
+         This grants the ability to use the ON argument on KLINE/XLINE/RESV
+         and UNKLINE/UNXLINE/UNRESV to set and unset bans on other servers,
+         and the server argument on REHASH.
+         This is only allowed if the oper may perform the action locally,
+         and if the remote server has a shared{} block.
+       </para>
+       <note><para>
+         If a cluster{} block is present, bans are sent remotely even
+         if the oper does not have remoteban privilege.
+       </para></note>
+      </sect2>
+      <sect2>
+       <title>local_kill (C), kill local users</title>
+       <para>
+         This grants permission to use KILL on users on the same server,
+         disconnecting them from the network.
+       </para>
+      </sect2>
+      <sect2>
+       <title>die (D), die and restart</title>
+       <para>
+         This grants permission to use DIE and RESTART, shutting down
+         or restarting the server.
+       </para>
+      </sect2>
+      <sect2>
+       <title>gline (G), gline</title>
+       <para>
+         This allows using GLINE (network wide temp bans if 3 opers agree).
+         If unkline privilege is also possessed, allow UNGLINE (remove gline
+         locally).
+       </para>
+      </sect2>
+      <sect2>
+       <title>rehash (H), rehash</title>
+       <para>
+         Allows using the REHASH command, to rehash various configuration
+         files or clear certain lists.
+       </para>
+      </sect2>
+      <sect2>
+       <title>kline (K), kline and dline</title>
+       <para>
+         Allows using KLINE and DLINE, to ban users by user@host mask
+         or IP address.
+       </para>
+      </sect2>
+      <sect2>
+       <title>operwall (L), send/receive operwall</title>
+       <para>
+         Allows using the OPERWALL command and umode +z to send and
+         receive operwalls.
+       </para>
+      </sect2>
+      <sect2>
+       <title>nick_changes (N), see nick changes</title>
+       <para>
+         Allows using snomask +n to see local client nick changes.
+         This is designed for monitor bots.
+       </para>
+      </sect2>
+      <sect2>
+       <title>global_kill (O), global kill</title>
+       <para>
+         Allows using KILL on users on any server.
+       </para>
+      </sect2>
+      <sect2>
+       <title>hidden_oper (P), hide from /stats p</title>
+       <para>
+         This privilege currently does nothing, but was designed
+         to hide bots from /stats p so users will not message them
+         for help.
+       </para>
+      </sect2>
+      <sect2>
+       <title>remote (R), remote routing</title>
+       <para>
+         This allows using the third argument of the CONNECT command, to
+         instruct another server to connect somewhere, and using SQUIT
+         with an argument that is not locally connected.
+         (In both cases all opers with +w set will be notified.)
+       </para>
+      </sect2>
+      <sect2>
+       <title>oper_spy (S), use operspy</title>
+       <para>
+         This allows using /mode !#channel, /whois !nick, /who !#channel,
+         /chantrace !#channel, /who !mask, /masktrace !user@host :gecos
+         and /scan umodes +modes-modes global list to see through secret
+         channels, invisible users, etc.
+       </para>
+       <para>
+         All operspy usage is broadcasted to opers with snomask +Z set
+         (on the entire network) and optionally logged.
+         If you grant this to anyone, it is a good idea to establish 
+         concrete policies describing what it is to be used for, and
+         what not.
+       </para>
+       <para>
+         If operspy_dont_care_user_info is enabled, /who mask is operspy
+         also, and /who !mask, /who mask, /masktrace !user@host :gecos
+         and /scan umodes +modes-modes global list do not generate +Z notices
+         or logs.
+       </para>
+      </sect2>
+      <sect2>
+       <title>unkline (U), unkline</title>
+       <para>
+         Allows using UNKLINE and UNDLINE, and if gline privilege is also
+         possessed, UNGLINE.
+       </para>
+      </sect2>
+      <sect2>
+       <title>xline (X), xline and unxline</title>
+       <para>
+         Allows using XLINE and UNXLINE, to ban/unban users by realname.
+       </para>
+      </sect2>
+      <sect2>
+       <title>hidden_admin, hidden administrator</title>
+       <para>
+         This grants everything granted to the admin privilege,
+         except the ability to set umode +a. If both admin and hidden_admin
+         are possessed, umode +a can still not be used.
+       </para>
+       <note><para>
+         This privilege does not appear in /stats o or oper up notices.
+       </para></note>
+      </sect2>
+    </sect1>
+  </chapter>
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-namecase-general:t
+sgml-general-insert-case:lower
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document: ("charybdis-oper-guide.sgml" "book")
+sgml-exposed-tags:nil
+fill-column: 105
+sgml-validate-command: "nsgmls -e -g -s -u charybdis-oper-guide.sgml"
+End:
+-->
diff --git a/doc/sgml/oper-guide/stylesheet.dsl b/doc/sgml/oper-guide/stylesheet.dsl
new file mode 100644 (file)
index 0000000..b3e084b
--- /dev/null
@@ -0,0 +1,33 @@
+<!DOCTYPE style-sheet PUBLIC "-//James Clark//DTD DSSSL Style Sheet//EN" [
+<!ENTITY docbook-html.dsl PUBLIC "-//Norman Walsh//DOCUMENT DocBook HTML Stylesheet//EN" CDATA DSSSL>
+<!ENTITY docbook-print.dsl PUBLIC "-//Norman Walsh//DOCUMENT DocBook Print Stylesheet//EN" CDATA DSSSL>
+]>
+
+<style-sheet>
+<style-specification id="print" use="print-stylesheet">
+<style-specification-body> 
+
+(define %generate-book-titlepage% #t)
+(define %generate-book-titlepage-on-separate-page% #t)
+(define %generate-book-toc% #t)
+(define %generate-book-toc-on-titlepage% #f)
+
+</style-specification-body>
+</style-specification>
+
+<style-specification id="html" use="html-stylesheet">
+<style-specification-body> 
+
+(define %header-navigation% #t)
+(define %section-autolabel% #t)
+(define %root-filename% "index")
+(define %use-id-as-filename% #t)
+(define %css-decoration% #t)
+(define %example-rules% #t)
+
+</style-specification-body>
+</style-specification>
+
+<external-specification id="print-stylesheet" document="docbook-print.dsl">
+<external-specification id="html-stylesheet"  document="docbook-html.dsl">
+</style-sheet>
diff --git a/doc/sgml/oper-guide/ucommands.sgml b/doc/sgml/oper-guide/ucommands.sgml
new file mode 100644 (file)
index 0000000..5a08263
--- /dev/null
@@ -0,0 +1,188 @@
+  <chapter id="ucommands">
+    <title>User Commands</title>
+    <sect1>
+      <title>User commands</title>
+      <para>
+       Standard IRC commands are not listed here.
+       Several of the commands in the operator commands chapter
+       can also be used by normal users.
+      </para>
+      <sect2>
+       <title>ACCEPT</title>
+       <cmdsynopsis><command>ACCEPT</command>
+         <arg choice=plain><replaceable>nick</replaceable>,</arg>
+         <arg choice=plain>-<replaceable>nick</replaceable>,</arg>
+         <arg choice=plain><replaceable>...</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         Adds or removes users from your accept list for umode +g and +R.
+         Users are automatically removed when they quit, split or change
+         nick.
+       </para>
+       <cmdsynopsis><command>ACCEPT</command>
+         <arg choice=plain>*</arg>
+       </cmdsynopsis>
+       <para>
+         Lists all users on your accept list.
+       </para>
+       <para>
+         Support of this command is indicated by the CALLERID token in
+         RPL_ISUPPORT (005); the optional parameter indicates the letter
+         of the <quote>only allow accept users to send private messages</quote>
+         umode, otherwise +g. In charybdis this is always +g.
+       </para>
+      </sect2>
+      <sect2>
+       <title>CNOTICE</title>
+       <cmdsynopsis><command>CNOTICE</command>
+         <arg choice=plain><replaceable>nick</replaceable></arg>
+         <arg choice=plain><replaceable>channel</replaceable></arg>
+         <arg choice=plain>:<replaceable>text</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         Providing you are opped (+o) or voiced (+v) in
+         <replaceable>channel</replaceable>, and <replaceable>nick</replaceable>
+         is a member of <replaceable>channel</replaceable>, CNOTICE generates a NOTICE towards
+         <replaceable>nick</replaceable>.
+       </para>
+       <para>
+         CNOTICE bypasses any anti-spam measures in place.
+         If you get <quote>Targets changing too fast, message dropped</quote>,
+         you should probably use this command, for example sending a
+         notice to every user joining a certain channel.
+       </para>
+       <para>
+         Support of this command is indicated by the CNOTICE token in
+         RPL_ISUPPORT (005).
+       </para>
+      </sect2>
+      <sect2>
+       <title>CPRIVMSG</title>
+       <cmdsynopsis><command>CPRIVMSG</command>
+         <arg choice=plain><replaceable>nick</replaceable></arg>
+         <arg choice=plain><replaceable>channel</replaceable></arg>
+         <arg choice=plain>:<replaceable>text</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         Providing you are opped (+o) or voiced (+v) in
+         <replaceable>channel</replaceable>, and <replaceable>nick</replaceable>
+         is a member of <replaceable>channel</replaceable>, CPRIVMSG generates a PRIVMSG towards
+         <replaceable>nick</replaceable>.
+       </para>
+       <para>
+         CPRIVMSG bypasses any anti-spam measures in place.
+         If you get <quote>Targets changing too fast, message dropped</quote>,
+         you should probably use this command.
+       </para>
+       <para>
+         Support of this command is indicated by the CPRIVMSG token in
+         RPL_ISUPPORT (005).
+       </para>
+      </sect2>
+      <sect2>
+       <title>HELP</title>
+       <cmdsynopsis><command>HELP</command>
+         <arg><replaceable>topic</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         Displays help information. <replaceable>topic</replaceable> can
+         be INDEX, CREDITS, UMODE, CMODE, SNOMASK or a command name.
+       </para>
+       <para>
+         There are separate help files for users and opers. Opers can use
+         UHELP to query the user help files.
+       </para>
+      </sect2>
+      <sect2>
+       <title>KNOCK</title>
+       <cmdsynopsis><command>KNOCK</command>
+         <arg choice=plain><replaceable>channel</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         Requests an invite to the given channel. The channel must be
+         locked somehow (+ikl), must not be +p and you may not be banned
+         or quieted. Also, this command is rate limited.
+       </para>
+       <para>
+         If successful, all channel operators will receive a 710 numeric.
+         The recipient field of this numeric is the channel.
+       </para>
+       <para>
+         Support of this command is indicated by the KNOCK token in
+         RPL_ISUPPORT (005).
+       </para>
+      </sect2>
+      <sect2>
+       <title>MONITOR</title>
+       <para>
+         Server side notify list. This list contains nicks. When a user
+         connects, quits with a listed nick or changes to or from a listed
+         nick, you will receive a 730 numeric if the nick went online and
+         a 731 numeric if the nick went offline.
+       </para>
+       <para>
+         Support of this command is indicated by the MONITOR token in
+         RPL_ISUPPORT (005); the parameter indicates the maximum number
+         of nicknames you may have in your monitor list.
+       </para>
+       <para>
+         You may only use this command once per second.
+       </para>
+       <para>
+         More details can be found in <filename>doc/monitor.txt</filename>
+         in the source distribution.
+       </para>
+       <cmdsynopsis><command>MONITOR +</command>
+         <arg choice=plain><replaceable>nick</replaceable>,</arg>
+         <arg choice=plain><replaceable>...</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         Adds nicks to your monitor list. You will receive 730 and 731
+         numerics for the nicks.
+       </para>
+       <cmdsynopsis><command>MONITOR -</command>
+         <arg choice=plain><replaceable>nick</replaceable>,</arg>
+         <arg choice=plain><replaceable>...</replaceable></arg>
+       </cmdsynopsis>
+       <para>
+         Removes nicks from your monitor list. No output is generated for
+         this command.
+       </para>
+       <cmdsynopsis><command>MONITOR C</command>
+       </cmdsynopsis>
+       <para>
+         Clears your monitor list. No output is generated for
+         this command.
+       </para>
+       <cmdsynopsis><command>MONITOR L</command>
+       </cmdsynopsis>
+       <para>
+         Lists all nicks on your monitor list, using 732 numerics and
+         ending with a 733 numeric.
+       </para>
+       <cmdsynopsis><command>MONITOR S</command>
+       </cmdsynopsis>
+       <para>
+         Shows status for all nicks on your monitor list, using 730 and 731
+         numerics.
+       </para>
+      </sect2>
+    </sect1>
+  </chapter>
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-namecase-general:t
+sgml-general-insert-case:lower
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document: ("charybdis-oper-guide.sgml" "book")
+sgml-exposed-tags:nil
+sgml-local-ecat-files:nil
+fill-column:105
+End:
+-->
diff --git a/doc/sgml/oper-guide/umodes.sgml b/doc/sgml/oper-guide/umodes.sgml
new file mode 100644 (file)
index 0000000..bcf858c
--- /dev/null
@@ -0,0 +1,333 @@
+  <chapter id="umodes">
+    <title>Umodes</title>
+    <sect1 id="umodelist">
+      <title>Meanings of user modes</title>
+      <sect2>
+       <title>+a, server administrator</title>
+       <para>
+         This vanity usermode is used to denote a server administrator in WHOIS output.
+         All local <quote>admin</quote> privileges are independent of it, though services
+         packages may grant extra privileges to +a users.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+D, deaf</title>
+       <para>
+         <note>
+           <para>
+             This is a user umode, which anybody can set. It is not specific to operators.
+           </para>
+         </note>
+         Users with the +D umode set will not receive messages sent to
+         channels. Joins, parts, topic changes, mode changes, etc are
+         received as normal, as are private messages.
+       </para>
+       <para>
+         Support of this umode is indicated by the DEAF token in
+         RPL_ISUPPORT (005); the parameter indicates the letter
+         of the umode. Note that several common IRCD implementations have
+         an umode like this (typically +d) but do not have the token in 005.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+g, Caller ID</title>
+       <para>
+         <note>
+           <para>
+             This is a user umode, which anybody can set. It is not specific to operators.
+           </para>
+         </note>
+         Users with the +g umode set will only receive private messages from users on a
+         session-defined whitelist, defined by the /accept command. If a user who is not
+         on the whitelist attempts to send a private message, the target user will receive a rate-limited notice saying that the user
+         wishes to speak to them.
+       </para>
+       <para>
+         Network operators are not affected by the callerid whitelist system in the event
+         that they need to speak to users who have it enabled.
+       </para>
+       <para>
+         Support of this umode is indicated by the CALLERID token in
+         RPL_ISUPPORT (005); the optional parameter indicates the letter
+         of the umode, otherwise +g.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+i, invisible</title>
+       <para>
+         <note>
+           <para>
+             This is a user umode, which anybody can set. It is not specific to operators.
+           </para>
+         </note>
+         Invisible users do not show up in WHO and NAMES unless you can see them.
+       </para>
+      </sect2>
+      <!-- not planned (jilles)
+      <sect2>
+       <title>+I, refuse invite</title>
+       <para>
+         <note>
+           <para>
+             This is a user umode, which anybody can set. It is not specific to operators.
+           </para>
+         </note>
+         If you have the +I umode set, nobody will be able to issue an INVITE to let you
+         in to a channel.
+       </para>
+       <para>
+         This mode is not yet implemented. It will be implemented in Charybdis 1.1.
+       </para>
+      </sect2>
+      -->
+      <sect2>
+       <title>+l, receive locops</title>
+       <para>
+         LOCOPS is a version of OPERWALL that is sent to opers on a single
+         server only. With cluster{} and shared{} blocks they can optionally
+         be propagated further.
+       </para>
+       <para>
+         Unlike OPERWALL, any oper can send and receive LOCOPS.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+o, operator</title>
+       <para>
+         This indicates global operator status.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+Q, disable forwarding</title>
+       <para>
+         <note>
+           <para>
+             This is a user umode, which anybody can set. It is not specific to operators.
+           </para>
+         </note>
+          This umode prevents you from being affected by any of the channel forwarding mechanisms. In
+          any event where you would normally be forwarded, instead you will get the usual error message
+          as if no forwarding was in effect.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+R, reject messages from unauthenticated users</title>
+       <para>
+         <note>
+           <para>
+             This is a user umode, which anybody can set. It is not specific to operators.
+           </para>
+         </note>
+         If a user has the +R umode set, then any users who are not authenticated
+         will receive an error message if they attempt to send a private
+         message or notice to the +R user.
+       </para>
+       <para>
+         Opers and accepted users (like in +g) are exempt.
+         Unlike +g, the target user is not notified of failed messages.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+s, receive server notices</title>
+       <para>
+         This umode allows an oper to receive server notices.
+         The requested types of server notices are specified as a
+         parameter (<quote>snomask</quote>) to this umode.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+S, network service</title>
+       <para>
+         <note>
+           <para>
+             This umode can only be set by servers named in a service{}
+             block.
+           </para>
+         </note>
+         This umode grants various features useful for services. For example,
+         clients with this umode cannot be kicked or deopped on channels,
+         do not show channels the querying user is not on in WHOIS,
+         and do not appear in /stats p.
+       </para>
+       <para>
+         The exact effects of this umode are variable; no user or oper on
+         an actual charybdis server can set it.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+w, receive wallops</title>
+       <para>
+         <note>
+           <para>
+             This is a user umode, which anybody can set. It is not specific to operators.
+           </para>
+         </note>
+         Users with the +w umode set will receive WALLOPS messages sent by opers.
+         Opers with +w additionally receive WALLOPS sent by servers (e.g.
+         remote CONNECT, remote SQUIT, many services packages).
+       </para>
+      </sect2>
+      <sect2>
+       <title>+z, receive operwall</title>
+       <para>
+         OPERWALL differs from WALLOPS in that the ability to receive such messages is
+         restricted. Opers with +z set will receive OPERWALL messages.
+       </para>
+      </sect2>
+    </sect1>
+    <sect1 id="snomaskusage">
+      <title>Snomask usage</title>
+      <para>
+       Usage is as follows:
+      </para>
+      <cmdsynopsis><command>MODE</command> 
+       <arg choice=plain><replaceable>nick</replaceable></arg> 
+       <arg choice=plain>+s</arg>
+       <arg choice=plain><replaceable>+/-flags</replaceable></arg>
+      </cmdsynopsis>
+      <para>
+       To set snomasks.
+      </para>
+      <cmdsynopsis><command>MODE</command> 
+       <arg choice=plain><replaceable>nick</replaceable></arg> 
+       <arg choice=plain>-s</arg>
+      </cmdsynopsis>
+      <para>
+       To clear all snomasks.
+      </para>
+      <para>
+       Umode +s will be set if at least one snomask is set.
+      </para>
+      <para>
+       Umode +s is oper only by default, but even if you allow nonopers to
+       set it, they will not get any server notices.
+      </para>
+    </sect1>
+    <sect1 id="snomasklist">
+      <title>Meanings of server notice masks</title>
+      <sect2>
+       <title>+b, bot warnings</title>
+       <para>
+         Opers with the +b snomask set will receive warning messages from the server when potential
+         flooders and spambots are detected.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+c, client connections</title>
+       <para>
+         Opers who have the +c snomask set will receive server notices when clients attach to the
+         local server.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+C, extended client connection notices</title>
+       <para>
+         Opers who have the +C snomask set will receive server notices when clients attach to the
+         local server. Unlike the +c snomask, the information is displayed in a format intended
+         to be parsed by scripts, and includes the two unused fields of the USER command.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+d, debug</title>
+       <para>
+         The +d snomask provides opers extra information which may be of interest to debuggers.
+         It will also cause the user to receive server notices if certain assertions fail inside the
+         server. Its precise meaning is variable. Do not depend on the
+         effects of this snomask as they can and will change without notice in later revisions.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+f, full warning</title>
+       <para>
+         Opers with the +f snomask set will receive notices when a user
+         connection is denied because a connection limit is exceeded
+         (one of the limits in a class{} block, or the total per-server
+         limit settable with /quote set max).
+       </para>
+      </sect2>
+      <sect2>
+       <title>+k, server kill notices</title>
+       <para>
+         Opers with the +k snomask set will receive server notices when
+         services kill users and when
+         other servers kill and save (forced nick change to UID) users.
+         Kills and saves by this server are on +d or +s.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+n, nick change notices</title>
+       <para>
+         An oper with +n set will receive a server notice every time a local user changes their nick,
+         giving the old and new nicks.
+         This is mostly useful for bots that track all users on a single server.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+r, notices on name rejections</title>
+       <para>
+         Opers with this snomask set will receive a server notice when somebody tries to use an
+         invalid username, or if a dumb HTTP proxy tries to connect.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+s, generic server notices</title>
+       <para>
+         This snomask allows an oper to receive generic server notices.
+         This includes kills from opers (except services).
+       </para>
+      </sect2>
+      <sect2>
+       <title>+u, unauthorized connections</title>
+       <para>
+         This snomask allows an oper to see when users try to connect who do not have an
+         available auth{} block.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+x, extra routing notices</title>
+       <para>
+         Opers who have the +x snomask set will get notices about servers
+         connecting and disconnecting on the whole network. This includes
+         all servers connected behind the affected link. This can get
+         rather noisy but is useful for keeping track of all linked
+         servers.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+y, spy</title>
+       <para>
+         Opers with +y receive notices when users try to join RESV'ed (<quote>juped</quote>) channels. 
+         Additionally, if certain extension modules are loaded, they will
+         receive notices when special commands are used and/or when they
+         are whoised.
+       </para>
+      </sect2>
+      <sect2>
+       <title>+Z, operspy notices</title>
+       <para>
+         Opers with +Z receive notices whenever an oper anywhere on the
+         network uses operspy.
+       </para>
+       <para>
+         This snomask can be configured to be only effective for admins.
+       </para>
+      </sect2>
+    </sect1>
+  </chapter>
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-namecase-general:t
+sgml-general-insert-case:lower
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document: ("charybdis-oper-guide.sgml" "book")
+sgml-exposed-tags:nil
+fill-column: 105
+sgml-validate-command: "nsgmls -e -g -s -u charybdis-oper-guide.sgml"
+End:
+-->
diff --git a/doc/technical/README.TSora b/doc/technical/README.TSora
new file mode 100644 (file)
index 0000000..c99dc05
--- /dev/null
@@ -0,0 +1,330 @@
+                       Protocol changes for +TSora
+                       ---------------------------
+
+
+Note: 
+
+The protocols described here implement TimeStamps on IRC channels and 
+nicks. The idea of IRC TimeStamps was started on Undernet, and first 
+implemented by Run <carlo@runaway.xs4all.nl>. The protocols used here 
+are not exactly the same as the ones used on Undernet; the nick-kill 
+handling is very similar and must be credited to Run, while the 
+"TimeStamped channel description" protocol is quite different.
+
+
+
+TSora servers keep track of which version of the TS protocol (if any) 
+their neighboring servers are using, and take it into account when 
+sending messages to them. This allows for seamless integration of TS 
+servers into a non-TS net, and for upgrades of the protocol.
+
+Each server knows which is the lowest and the highest version of the
+TS protocol it can interact with; currently both of these are set to 1:
+
+#define TS_CURRENT 1           /* the highest TS ver we can do */
+#define TS_MIN 1               /* the lowest TS ver we can do  */
+
+
+Timings and TS versions:
+========================
+
+. Keep a 'delta' value to be added to the result of all calls to time(),
+  initially 0.
+
+. Send a second argument to the PASS command, ending in the 'TS' string.
+
+. Send a
+
+  SVINFO <TS_CURRENT> <TS_MIN> <STANDALONE> :<UTC-TIME>
+  
+  just after "SERVER", where <STANDALONE> is 1 if we're connected to 
+  more TSora servers, and 0 if not, and <UTC-TIME> is our idea of the 
+  current UTC time, fixed with the delta.
+
+. When we receive a "SVINFO <x> <y> <z> :<t>" line from a connecting 
+  server, we ignore it if TS_CURRENT<y or x<TS_MIN, otherwise we
+  set a flag remembering that that server is TS-aware, remember the TS 
+  version to use with it (min(TS_CURRENT, x)). Additionally, if this is 
+  our first connected TS server, we set our delta to t-<OUR_UTC> if
+  z==0, and to (t-<OUR_UTC>)/2 if z!=0. The SVINFO data is kept around
+  until the server has effectively registered with SERVER, and used
+  *after* sending our own SVINFO to that server.
+
+
+Explanations:
+
+  Servers will always know which of their directly-linked servers can do 
+  TS, and will use the TS protocol only with servers that do understand 
+  it. This makes it possible to switch to full TS in just one 
+  code-replacement step, without incompatibilities.
+
+  As long as not all servers are TS-aware, the net will be divided into 
+  "zones" of linked TS-aware servers. Channel modes will be kept 
+  synchronized at least within the zone in which the channel was 
+  created, and nick collisions between servers in the same zone will 
+  result in only one client being killed.
+
+  Time synchronization ensures that servers have the same idea of the 
+  current time, and achieves this purpose as long as TS servers are 
+  introduced one by one within the same 'zone'. The merging of two zones 
+  cannot synchronize them completely, but it is to be expected that 
+  within each zone the effective time will be very close to the real 
+  time. 
+
+  By sending TSINFO after SERVER rather than before, we avoid the extra 
+  lag created by the identd check on the server. To be able to send 
+  immediately a connect burst of either type (TS or not), we need to 
+  know before that if the server does TS or not, so we send that 
+  information with PASS as an extra argument. And to avoid being 
+  incompatible with 2.9 servers, which check that this second argument 
+  begins with "2.9", we check that it *ends* with "TS".
+
+  The current time is only used when setting a TS on a new channel or 
+  nick, and once such a TS is set, it is never modified because of 
+  synchronization, as it is much more important that the TS for a 
+  channel or nick stays the same across all servers than that it is 
+  accurate to the second.
+
+  Note that Undernet's 2.8.x servers have no time synchronization at 
+  all, and have had no problems because of it - all of this is more to 
+  catch the occasional server with a way-off clock than anything.
+
+
+NICK handling patches (anti-nick-collide + shorter connect burst):
+==================================================================
+
+. For each nick, store a TS value = the TS value received if any, or our 
+  UTC+delta at the time we first heard of the nick. TS's are propagated 
+  to TS-aware servers whenever sending a NICK command.
+
+. Nick changes reset the TS to the current time.
+
+. When sending a connect burst to another TS server, replace the 
+  NICK/USER pair with only one NICK command containing the nick, the 
+  hopcount, the TS, the umode, and all the USER information.
+
+  The format for a full NICK line is:
+  NICK <nick> <hops> <TS> <umode> <user> <host> <server> :<ircname>
+
+  The umode is a + followed by any applying usermodes.
+
+  The format for a nick-change NICK line is:
+  :<oldnick> NICK <newnick> :<TS>
+
+. When a NICK is received from a TS server, that conflicts with an 
+  existing nick:
+  + if the userhosts differ or one is not known:
+    * if the timestamps are equal, kill ours and the old one if it
+      was a nick change
+    * if the incoming timestamp is older than ours, kill ours and 
+      propagate the new one
+    * if the incoming timestamp is younger, ignore the line, but kill 
+      the old nick if it was a nick change
+  + if the userhosts are the same:
+    * if the timestamps are equal, kill ours and the old one if it
+      was a nick change
+    * if the incoming timestamp is younger, kill ours and propagate
+      the new one
+    * if the incoming timestamp is older, ignore the line but kill
+      the old nick if it was a nick change
+
+. When a NICK is received from a non-TS server that conflicts with
+  an existing nick, kill both.
+
+. Do not send "Fake Prefix" kills in response to lines coming from TS 
+  servers; the sanitization works anyway, and this allows the "newer
+  nick overruled" case to work.
+
+Explanations:
+
+  The modified nick-introduction syntax allows for a slightly shorter 
+  connect-burst, and most importantly lets the server compare 
+  user@host's when determining which nick to kill:  if the user@host
+  is the same, then the older nick must be killed rather than the
+  newer.
+
+  When talking to a non-TS server, we need to behave exactly like one
+  because it expects us to. When talkign to a TS server, we don't kill
+  the nicks it's introducing, as we know it'll be smart enough to do it
+  itself when seeing our own introduced nick.
+
+  When we see a nick arriving from a non-TS server, it won't have a TS, 
+  but it's safe enough to give it the current time rather than keeping 
+  it 0; such TS's won't be the same all across the network (as long as 
+  there is more than one TS zone), and when there's a collision, the TS 
+  used will be the one in the zone the collision occurs in.
+
+  Also, it is important to note that by the time a server sees (and 
+  chooses to ignore) a nick introduction, the introducing server has 
+  also had the time to put umode changes for that nick on its queue, so 
+  we must ignore them too... so we need to ignore fake-prefix lines 
+  rather than sending kills for them. This is safe enough, as the rest 
+  of the protocol ensures that they'll get killed anyway (and the 
+  Undernet does it too, so it's been more than enough tested). Just for 
+  an extra bit of compatibility, we still kill fake prefixes coming from 
+  non-TS servers.
+
+  This part of the TS protocol is almost exactly the same as the 
+  Undernet's .anc (anti-nick-collide) patches, except that Undernet 
+  servers don't add usermodes to the NICK line.
+
+
+TimeStamped channel descriptions (avoiding hacked ops and desynchs):
+====================================================================
+
+. For each channel, keep a timestamp, set to the current time when the
+  channel is created by a client on the local server, or to the received 
+  value if the channel has been propagated from a TS server, or to 0 
+  otherwise. This value will have the semantics of "the time of creation 
+  of the current ops on the channel", and 0 will mean that the channel 
+  is in non-TS mode.
+
+  A new server protocol command is introduced, SJOIN, which introduces 
+  a full channel description: a timestamp, all the modes (except bans),
+  and the list of channel members with their ops and voices. This 
+  command will be used instead of JOIN and of (most) MODEs both in 
+  connect bursts and when propagating channel creations among TS 
+  servers. SJOIN will never be accepted from or sent to users.
+
+  The syntax for the command is:
+
+  SJOIN <TS> #<channel> <modes> :[@][+]<nick_1> ...  [@][+]<nick_n>
+
+  The fields have the following meanings:
+
+  * <TS> is the timestamp for the channel
+
+  * <modes> is the list of global channel modes, starting with a +
+    and a letter for each of the active modes (spmntkil), followed
+    by an argument for +l if there is a limit, and an argument for
+    +k if there's a key (in the same order they were mentioned in
+    the string of letters).
+
+    A channel with no modes will have a "+" in that field.
+
+    A special value of "0" means that the server does not specify the 
+    modes, and will be used when more than one SJOIN line is needed
+    to completely describe a channel, or when propagating a SJOIN
+    the modes of which were rejected.
+
+  * Each nick is preceded by a "@" if the user has ops, and a "+" if
+    the user has a voice. For mode +ov, both flags are used.
+
+  SJOINs will be propagated (when appropriate) to neighboring TS 
+  servers, and converted to JOINs and MODEs for neighboring non-TS 
+  servers.
+  
+  To propagate channels for which not all users fit in one 
+  SJOIN line, several SJOINs will be sent consecutively, only the first
+  one including actual information in the <mode> field.
+  
+  An extra ad-hoc restriction is imposed on SJOIN messages, to simplify 
+  processing: if a channel has ops, then the first <nick> of the first 
+  SJOIN sent to propagate that channel must be one of the ops.
+
+  Servers will never attempt to reconstruct a SJOIN from JOIN/MODE 
+  information being received at the moment from other servers.
+
+. For each user on a channel, keep an extra flag (like ops and voice)
+  that is set when the user has received channel ops from another 
+  server (in a SJOIN channel description), which we rejected (ignored). 
+  Mode changes (but NOT kicks) coming from a TS server and from someone 
+  with this flag set will be ignored. The flag will be reset when the 
+  user gets ops from another user or server.
+
+. On deops done by non-local users, coming from TS servers, on channels 
+  with a non-zero TS, do not check that the user has ops but check that 
+  their 'deopped' flag is not set. For kicks coming from a TS server, do 
+  not check either. This will avoid desynchs, and 'bad' modechanges are 
+  avoided anyway. Other mode changes will still only be taken into 
+  account and propagated when done by users that are seen as having ops.
+
+. When a MODE change that ops someone is received from a server for a 
+  channel, that channel's TS is set to 0, and the mode change is 
+  propagated. 
+
+. When a SJOIN is received for a channel, deal with it in this way:
+  * received-TS = 0: 
+    + if we have ops or the SJOIN doesn't op anyone, SJOIN propagated
+      with our own TS.
+    + otherwise, TS set to 0 and SJOIN propagated with 0.
+  * received-TS > 0, own-TS = 0: 
+    + if the SJOIN ops someone or we don't have ops, set our TS to the
+      received TS and propagate.
+    + otherwise, propagate with TS = 0.
+  * received-TS = own-TS: propagate.
+  * received-TS < own-TS: 
+    + if the SJOIN ops someone, remove *all* modes (except bans) from 
+      the channel and propagate these mode changes to all neighboring
+      non-TS servers, and copy the received TS and propagate the SJOIN.
+    + if the SJOIN does not op anyone and we have ops, propagate
+      with our own TS.
+    + otherwise, copy the received TS and propagate the SJOIN.
+  * received-TS > own-TS: 
+    + if the SJOIN does not introduce any ops, process and propagate
+      with our own TS.
+    + if we have ops: for each person the mode change would op, set the 
+      'deopped' flag; process all the JOINs ignoring the '@' and '+' 
+      flags; propagate without the flags and with our TS.
+    + if we don't have ops: set our TS to the received one, propagate
+      with the flags.
+
+
+Explanations:
+
+  This part of the protocol is the one that is most different (and 
+  incompatible) with the Undernet's: we never timestamp MODE changes, 
+  but instead we introduce the concept of time-stamped channel 
+  descriptions. This way each server can determine, based on its state 
+  and the received description, what the correct modes for a channel 
+  are, and deop its own users if necessary. With this protocol, there is 
+  *never* the need to reverse and bounce back a mode change. This is
+  both faster and more bandwith-effective.
+
+  The end goal is to have a protocol will eventually protect channels 
+  against hacked ops, while minimizing the impact on a mixed-server net. 
+  In order to do this, whenever there is a conflict between a TS server 
+  and a non-TS one, the non-TS one's idea of the whole situation 
+  prevails. This means that channels will only have a TS when they have 
+  been created on a TS-aware server, and will lose it whenever a server 
+  op comes from a non-TS server. Also, at most one 'zone' will have a TS 
+  for any given channel at any given time, ensuring that there won't be 
+  any deops when zones are merged. However, when TS zones are merged, if 
+  the side that has a TS also has ops, then the TS is kept across the 
+  whole new zone. Effective protection will only be ensured once all 
+  servers run TS patches and channels have been re-created, as there is 
+  no way servers can assign a TS to a channel they are not creating 
+  (like they do with nicks) without having unwanted deops later.
+
+  The visible effects of this timestamped channel-description protocol 
+  are that when a split rejoins, and one side has hacked ops, the other 
+  side doesn't see any server mode changes (just like with Undernet's
+  TS), but the side that has hacked ops sees:
+
+  * first the first server on the other side deopping and devoicing 
+    everyone, and fixing the +spmntkli modes
+  * then other users joining, and getting server ops and voices
+
+  The less obvious part of this protocol is its behavior in the case 
+  that the younger side of a rejoin has servers that are lagged with 
+  each other. In such a situation, a SJOIN that clears all modes and 
+  sets the legitimate ones is being propagated from one server, and 
+  lagged illegitimate mode changes and kicks are being propagated in the 
+  opposite direction. In this case, a kick done by someone who is being 
+  deopped by the SJOIN must be taken into account to keep the name list 
+  in sync (and since it can only be kicking someone who also was on the 
+  younger side), while a deop does not matter (and will be ignored by 
+  the first server on the other side), and an opping *needs* to be 
+  discareded to avoid hacked ops.
+
+  The main property of timestamped channel descriptions that makes them 
+  a very stable protocol even with lag and splits, is that they leave a 
+  server in the same final state, independently of the order in which 
+  channel descriptions coming from different servers are received. Even 
+  when SJOINs and MODEs for the same channel are being propagated in 
+  different direction because of several splits rejoining, the final 
+  state will be the same, independently of the exact order in which each 
+  server received the SJOINs, and will be the same across all the 
+  servers in the same zone.
+
+
diff --git a/doc/technical/capab.txt b/doc/technical/capab.txt
new file mode 100644 (file)
index 0000000..bfe52ac
--- /dev/null
@@ -0,0 +1,34 @@
+Server capabilities
+William Pitcock <nenolod -at- nenolod.net>
+-------------------
+
+Not all TSora IRCd's support these.
+
+QS          - supports Quit Storm (SQUIT does not have to send recursive quits)
+EX          - supports ban exceptions (+e)
+CHW         - supports messages directed to channel operators only i.e. @#channel
+IE          - supports invite exceptions (+I)
+EOB         - supports end of burst notification (EOB token)
+KLN         - supports remote KLINE
+UNKLN       - supports remote UNKLINE
+GLN         - supports hybrid7-style GLINE (:oper GLINE user host :reason)
+HOPS        - supports halfops (+h -- %<nick>)
+HUB         - denotes that the target server is a HUB
+AOPS        - supports anonymous ops (+a, op hiding/op status hiding)
+KNOCK       - supports KNOCK extension (request invite to +ikl channel)
+TBURST      - supports old TBURST command [broken, don't use.]
+TB          - supports new TB command [do use.]
+PARA        - supports sending invite notices via INVITE from server
+ENCAP       - supports message encapsulation
+SERVICES    - supports ratbox's services extensions
+SAVE        - supports SAVE extension (friendlier alternative to KILL on nick collide)
+RSFNC       - supports RSFNC extension (forcenick)
+CLUSTER     - supports remote XLINE, UNXLINE, RESV, UNRESV and LOCOPS
+EUID        - supports EUID, non-ENCAP CHGHOST and NICKDELAY
+ZIP         - supports ziplinks
+ENC         - supports encryption (cryptlinks)
+
+The KLN, UNKLN and CLUSTER capabilities do not apply to klines, xlines
+and resvs sent over ENCAP.
+
+Disabling ban/invite exceptions in ircd.conf does not remove the EX/IE capabs.
diff --git a/doc/technical/cluster.txt b/doc/technical/cluster.txt
new file mode 100644 (file)
index 0000000..0d28447
--- /dev/null
@@ -0,0 +1,26 @@
+$Id: cluster.txt 6 2005-09-10 01:02:21Z nenolod $
+
+Short description of how remote kline and friends are propagated under
+the old hyb7 style (CAP_KLN etc) and under the new style over ENCAP.
+
+CAP_KLN:
+:<source> KLINE <target> <time> <user> <host> :<reason>
+:<source> ENCAP <target> KLINE <time> <user> <host> :<reason>
+
+CAP_UNKLN:
+:<source> UNKLINE <target> <user> <host>
+:<source> ENCAP <target> UNKLINE <user> <host>
+
+CAP_CLUSTER:
+:<source> XLINE <target> <gecos> <type> :<reason>
+:<source> ENCAP <target> XLINE <time> <gecos> <type> :<reason>
+
+:<source> UNXLINE <target> <gecos>
+:<source> ENCAP <target> UNXLINE <gecos>
+
+:<source> RESV <target> <name> :<reason>
+:<source> ENCAP <target> RESV <time> <name> 0 :<reason>
+
+:<source> UNRESV <target> <name>
+:<source> ENCAP <target> UNRESV <name>
+
diff --git a/doc/technical/euid.txt b/doc/technical/euid.txt
new file mode 100644 (file)
index 0000000..d141095
--- /dev/null
@@ -0,0 +1,71 @@
+$Id: euid.txt 1863 2006-08-27 13:40:37Z jilles $
+
+Extended UID command proposal
+Jilles Tjoelker <jilles@stack.nl>
+
+Introduction
+------------
+
+The current protocol to deal with real and visible hosts, with UID, ENCAP
+REALHOST and ENCAP CHGHOST commands has several problems.
+
+In some cases (MONITOR) real hosts are used inappropriately because the UID
+command contains the real host for new users. In other cases (atheme
+akills), the visible host is used inappropriately because the UID command
+contains the visible host for burst users. In both cases nothing is sent
+after the UID command if real and visible hosts are equal. In the latter
+case this problem can be worked around with end-of-burst detection but in
+the former case that is not possible.
+
+This can be fixed by sending both real and visible host in the same command.
+
+This command can also include the data that is currently sent with ENCAP
+LOGIN.
+
+Another problem is that CHGHOST is an ENCAP command although it is important
+for synchronization. One of the problems is that the target often remains
+a UID even if sent to a TS5 server (various old services packages).
+
+This can be fixed by making it a regular command.
+
+Current commands
+----------------
+
+(TS6 form only)
+
+:<SID> UID <NICK> <HOPS> <TS> +<UMODE> <USERNAME> <HOSTNAME> <IP> <UID> :<GECOS>
+
+Introduces a user, see Lee Hardy's ts6.txt.
+
+:<UID> ENCAP * REALHOST <REALHOST>
+
+Sets the real host of a user (the hostname in UID is the visible host).
+
+:<SID> ENCAP * CHGHOST <UID> <VHOST>
+
+Sets/changes the visible host of a user (the hostname in UID is the real host).
+
+:<UID> ENCAP * LOGIN <ACCOUNT>
+
+Sets the login name of a user.
+
+New commands
+------------
+
+:<SID> EUID <NICK> <HOPS> <TS> +<UMODE> <USERNAME> <VHOST> <IP> <UID> <REALHOST> <ACCOUNT> :<GECOS>
+
+Introduces a user. The hostname field is now always the visible host.
+The realhost field is * if the real host is equal to the visible host.
+The account field is * if the login is not set.
+Note that even if both new fields are *, an EUID command still carries more
+information than a UID command (namely that real host is visible host and the
+user is not logged in with services). Hence a NICK or UID command received
+from a remote server should not be sent in EUID form to other servers.
+
+:<SID> CHGHOST <UID> <VHOST>
+
+Changes the visible host of a user.
+
+A new server capab named EUID will be sent if these commands are supported.
+If the capab is not present, the old commands must be used.
+EUID can (in principle) also be used with TS5.
diff --git a/doc/technical/event.txt b/doc/technical/event.txt
new file mode 100644 (file)
index 0000000..e8ffa2f
--- /dev/null
@@ -0,0 +1,84 @@
+Overview of the event subsystem
+Adrian Chadd <adrian@creative.net.au>
+
+$Id: event.txt 6 2005-09-10 01:02:21Z nenolod $
+
+
+One of the things that immediately struck me whilst first looking at the
+code was that the ircd periodically scheduled things in io_loop() but
+it did them manually. This is very wasteful and very tedious.
+
+Therefore, an event system was added to hybrid. src/event.c contains an
+event system ported from the squid web cache. It is pretty self contained,
+and only a few things (debugging, time resolution) needed changing.
+
+An event is scheduled through eventAdd() or eventAddIsh() :
+
+eventAdd(const char *name, EVH * func, void *arg, time_t when, int weight)
+eventAddIsh(const char *name, EVH * func, void *arg, time_t delta_ish,
+  int weight)
+
+after 'when' (or delta_ish) seconds has elapsed from the time the above
+functions are called, the 'func' is called with the given data 'arg'. The
+event is then deleted.
+
+To delete an event, use eventDelete() :
+
+eventDelete(EVH * func, void *arg)
+
+An event is identified by its callback function and data pair.
+
+Events are run through eventRun(). This is designed to be called *BEFORE*
+your IO handlers, to let events scheduled immediately (ie a time of 0)
+to initiate IO before the IO handlers are called.
+
+(Believe me, its useful.)
+
+
+
+Example:
+
+Say you have something which must be called every 15 seconds.
+
+* You would first define the callback in your module:
+
+static EVH foo_periodic_event;
+static int initialised = 0;
+
+* You would then add the event in your initialization function:
+
+void foo_init(void)
+{
+    if (!initialised) {
+        eventAdd("foo_periodic_event", foo_periodic_event, NULL, 0, 0);
+        initialised = 1;
+    }
+}
+
+  This will force the event to be called the next time eventRun() is called,
+  rather than waiting 15 seconds.
+
+* You then define your event callback:
+
+static void
+foo_periodic_event(void *data)
+{
+    /* We'd do our work here */
+
+    /* Then we'd finish */
+    eventAdd("foo_periodic_event", foo_periodic_event, NULL, 15, 0);
+}
+
+
+Notes:
+
+* I really should change the timeout value to be in milliseconds. Squid used
+  a double, but Dianora had something against floating point code in the main
+  loop (which is understandable). If someone wants a fun task .. :-)
+
+* Note that the 'name' parameter to eventAdd() / eventAddIsh() is a const
+  char *, and is *not copied* but *referenced*. Therefore, it is in your
+  best interest to use string constants.
+
+* /stats E for an oper shows pending events. Thanks Diane!
+
diff --git a/doc/technical/fd-management.txt b/doc/technical/fd-management.txt
new file mode 100644 (file)
index 0000000..02c3f58
--- /dev/null
@@ -0,0 +1,81 @@
+Overview of the filedescriptor subsystem
+Adrian Chadd <adrian@creative.net.au>
+
+$Id: fd-management.txt 6 2005-09-10 01:02:21Z nenolod $
+
+
+Filedescriptor lists
+--------------------
+
+The filedescriptor list is managed through the routines in fdlist.c .
+These include:
+
+fd_open() - tag an FD as "open" and active
+fd_close() - tag an FD as "closed" and close() the filedescriptor
+fd_note() - update the filedescriptor tag
+
+You can get the current list of open filedescriptors through /stats F as
+an oper.
+
+
+
+FD lists
+--------
+
+The FD list support is very alpha. There are a few lists defined:
+
+typedef enum fdlist_t {
+    FDLIST_NONE,
+    FDLIST_SERVICE,
+    FDLIST_SERVER,
+    FDLIST_IDLECLIENT,
+    FDLIST_BUSYCLIENT,
+    FDLIST_MAX
+} fdlist_t;
+
+FDLIST_NONE            Not on any list (ie close()d)
+FDLIST_SERVICE         A service - listen() sockets, resolver, etc
+FDLIST_SERVER          Server connections
+FDLIST_IDLECLIENT      An idle client
+FDLIST_BUSYCLIENT      A busy client
+FDLIST_MAX             Used for bounds checking
+
+The idea is that the SERVICE sockets need polling frequently, the SERVER
+sockets also need polling frequently, BUSYCLIENT is for busy clients
+which need frequent polling (eg we're trying to write to them), and
+IDLECLIENT is for clients which we don't need to poll frequently.
+THIS hasn't been decided upon yet.
+
+
+
+File operations
+---------------
+
+The file operations are also wrapped through file_open() and file_close()
+which handle calling fd_open() / fd_close() and tracking the filedescriptors
+correctly. fbopen() / fbclose() use file_open() / file_close() too.
+
+fileio.c defines the functions:
+
+int
+file_open(const char *filename, int mode, int fmode)
+
+A wrapper around open(filename, flags, mode). Read the open manpage for
+information. file_open() enforces filedescriptor limits and tags the FD
+through fd_open().
+
+void
+file_close(int fd)
+
+A wrapper around close() for files. close() handles fd_close()ing the fd.
+
+
+FBFILE *
+fbopen(const char *filename, const char *mode)
+
+void
+fbclose(FBFILE *fb)
+
+These are the 'buffered disk IO' routines. You can read the code yourself.
+Note that these routines use file_open() and file_close().
+
diff --git a/doc/technical/file-management.txt b/doc/technical/file-management.txt
new file mode 100644 (file)
index 0000000..d5e103a
--- /dev/null
@@ -0,0 +1,37 @@
+Overview of the file management subsystem
+Adrian Chadd <adrian@creative.net.au>
+
+$Id: file-management.txt 6 2005-09-10 01:02:21Z nenolod $
+
+
+File operations
+---------------
+
+The file operations are also wrapped through file_open() and file_close()
+which handle calling fd_open() / fd_close() and tracking the filedescriptors
+correctly. fbopen() / fbclose() use file_open() / file_close() too.
+
+fileio.c defines the functions:
+
+int
+file_open(const char *filename, int mode, int fmode)
+
+A wrapper around open(filename, flags, mode). Read the open manpage for
+information. file_open() enforces filedescriptor limits and tags the FD
+through fd_open().
+
+void
+file_close(int fd)
+
+A wrapper around close() for files. close() handles fd_close()ing the fd.
+
+
+FBFILE *
+fbopen(const char *filename, const char *mode)
+
+void
+fbclose(FBFILE *fb)
+
+These are the 'buffered disk IO' routines. You can read the code yourself.
+Note that these routines use file_open() and file_close().
+
diff --git a/doc/technical/hostmask.txt b/doc/technical/hostmask.txt
new file mode 100644 (file)
index 0000000..d70c114
--- /dev/null
@@ -0,0 +1,115 @@
+The hostmask/netmask system.
+Copyright(C) 2001 by Andrew Miller(A1kmm)<a1kmm@mware.virtualave.net>
+$Id: hostmask.txt 6 2005-09-10 01:02:21Z nenolod $
+
+Contents
+========
+* Section 1: Motivation
+* Section 2: Underlying mechanism
+  - 2.1: General overview.
+  - 2.2: IPv4 netmasks.
+  - 2.3: IPv6 netmasks.
+  - 2.4: Hostmasks.
+* Section 3: Exposed abstraction layer
+  - 3.1: Parsing masks.
+  - 3.2: Adding configuration items.
+  - 3.3: Initialising or rehashing.
+  - 3.4: Finding IP/host confs.
+  - 3.5: Deleting entries.
+  - 3.6: Reporting entries.
+
+Section 1: Motivation
+=====================
+Looking up config hostnames and IP addresses(such as for I-lines and
+K-lines) needs to be implemented efficiently. It turns out a hash
+based algorithm like that employed here performs well on the average
+case, which is what we should be the most concerned about. A profiling
+comparison with the mtrie code using data from a real network confirmed
+that this algorithm performs much better.
+
+Section 2: Underlying mechanism
+===============================
+2.1: General overview
+---------------------
+In short, a hash-table with linked lists for buckets is used to locate
+the correct hostname/netmask entries. In order to support CIDR IPs and
+wildcard masks, the entire key cannot be hashed, and there is a need to
+rehash. The means for deciding how much to hash differs between hostmasks
+and IPv4/6 netmasks.
+
+2.2: IPv4 netmasks
+------------------
+In order to hash IPv4 netmasks for addition to the hash, the mask is first
+processed to a 32 bit address and a number of bits used. All unused bits
+are set to 0. The mask could be in the forms:
+1.2.3.4     => 1.2.3.4  32
+1.2.3.*     => 1.2.3.0  24
+1.2         => 1.2.0.0  16
+1.2.3.64/26 => 1.2.3.64 26
+The number of whole bytes is then calculated, and only those bytes are
+hashed. (e.g. 1.2.3.64/26 and 1.2.3.0/24 hash the same).
+When a complete IPv4 address is given so that an IPv4 match can be found,
+the entire IP address is first hashed, and looked up in the table. Then
+the most significant three bytes are hashed, followed by the most
+significant two, the most significant one, and finally the 'identity hash'
+bucket is searched(to match masks like 192/7).
+
+2.3: IPv6 netmasks
+------------------
+As per IPv4 netmasks, except that instead of rehashing with a one byte
+granularity, a 16 bit(two byte) granularity is used, as 16 rehashes is
+considered too great a fixed offset to be justified for a (possible)
+slight reduction in hash collisions.
+
+2.4: Hostmasks
+--------------
+On adding a hostmask to the hash, all of the hostmask right of the next
+dot after the last wildcard character in the string is hashed, or in the
+case that there are no wildcards in the hostmask, the entire string is
+hashed.
+On searching for a hostmask match, the entire hostname is hashed, followed
+by the entire hostmask after the first dot, followed by the entire
+hostmask after the second dot, and so on. Finally, the 'identity' hash
+bucket is checked, to catch hostnames like *test*.
+
+Section 3: Exposed abstraction layer
+====================================
+Section 3.1: Parsing masks
+--------------------------
+Call "parse_netmask()" with the netmask and a pointer to an irc_inaddr
+structure to be filled in, as well as a pointer to an integer where the
+number of bits will be placed.
+Always check the return value. If it returns HM_HOST, it means that the
+mask is probably a hostname mask. If it returns HM_IPV4, it means it was
+an IPv4 address. If it returns HM_IPV6, it means it was an IPv6 address.
+If parse_netmask returns HM_HOST, no change is made to the irc_inaddr
+structure or the number of bits.
+
+Section 3.2: Adding configuration items
+---------------------------------------
+Call "add_conf_by_address" with the hostname or IP mask, the username,
+and the ConfItem* to associate with this mask.
+
+Section 3.3: Initialising and rehashing
+----------------------------------------
+To initialise, call init_host_hash(). This only needs to be done once on
+startup.
+On rehash, to wipe out the old unwanted conf, and free them if there are
+no references to them, call clear_out_address_conf(). 
+
+Section 3.4: Finding IP/host confs
+----------------------------------
+Call find_address_conf() with the hostname, the username, the address,
+and the address family.
+To find a d-line, call find_dline() with the address and address family.
+
+Section 3.5: Deletiing entries
+------------------------------
+Call delete_one_address_conf() with the hostname and the ConfItem*.
+
+Section 3.6: Reporting entries
+------------------------------
+Call report_dlines, report_exemptlines, report_Klines() or report_Ilines()
+with the client pointer to report to. Note these walk the hash, which is
+inefficient, but these are not called often enough to justify the memory
+and maintenance clockcycles to for more efficient data structure.
diff --git a/doc/technical/index.txt b/doc/technical/index.txt
new file mode 100644 (file)
index 0000000..0f66856
--- /dev/null
@@ -0,0 +1,19 @@
+Technical Documentation for ircd-hybrid-7
+
+Persistent_Clients.txt    - A global UID and Persistent client (with cookies)
+                            proposal
+README.TSora              - Description of the TS3 protocol
+README.openssl            - Information for users who have problems with
+                            Hybrid, OpenSSL, and their operating system
+cryptlink.txt             - Outline of CRYPTLINK protocol
+event.txt                 - Outline of the event system
+fd-management.txt         - Outline of the file descriptor management system
+file-management.txt       - Outline of the disk file management system
+hostmask.txt              - Outline of hostmask handling
+linebuf.txt               - Outline of the linebuf system (dbuf replacement)
+network.txt               - Outline of the network traffic subsystem
+rfc1459.txt               - The IRC RFC
+send.txt                  - Document on all of the send_to functions
+whats-new-code.txt        - Whats changed in the code
+
+# $Id: index.txt 6 2005-09-10 01:02:21Z nenolod $
diff --git a/doc/technical/linebuf.txt b/doc/technical/linebuf.txt
new file mode 100644 (file)
index 0000000..556597e
--- /dev/null
@@ -0,0 +1,139 @@
+
+linebuf - a dbuf replacement for the New World Order(tm)
+
+By Adrian Chadd <adrian@creative.net.au>
+
+$Id: linebuf.txt 6 2005-09-10 01:02:21Z nenolod $
+
+
+History
+-------
+
+I could probably learn the dbuf history, but basically its evil. The
+general idea is that a dbuf holds incoming and outgoing data streams.
+The trouble is that well.. it was evil. You can check it out by getting
+the old src/dbuf.c and include/dbuf.h files if you really want.
+
+
+Replacement
+-----------
+
+The linebuf system is a replacement for the dbuf code. The general idea here
+is that the data should be buffered in "lines" rather than just linearly
+like in the dbuf code. This lends to easier manipulation at a later date
+(think flushing data lines to a socket, and even "sharing" linebufs to
+reduce the copying required for one to many delivery.)
+
+The linebuf system is broken into two structures, the buf_head and buf_line .
+buf_head contains the buffer information (queue head/tail, length, allocated
+length and the write offset for flushing), and buf_line contains the
+line buffer information (buffer and various flags.)
+
+linebuf->terminated is *only* set when a CR/LF combination is received.
+
+linebuf->overflow is set if we get more data than we should, and we simply
+  truncate the incoming data.
+
+linebuf->flushing is set when we are currently writing the buffer. We should
+  _NEVER_ be appending to a buffer which we're flushing!
+
+When you get a buffer through linebuf_get() or write one through
+linebuf_flush(), it will *always* be terminated with a CR/LF (and a NUL if
+its a linebuf_get()).
+
+
+Linebuf manipulation
+--------------------
+
+To use a linebuf, you simply stick a buf_head_t in your structure somewhere.
+You then use the following routines:
+
+int
+linebuf_parse(buf_head_t *bufhead, char *buf, int len)
+
+Parse the given buf. This routine does some complex manipulation:
+
+- if there is an incomplete buffer at the tail, buf is parsed to try and
+  fill that incomplete buffer
+- a buffer is completed by a CR/LF/CRLF/LFCR. It accepts everything purely
+  because I wanted to be "liberal in what you accept" .. 
+- If a buffer is terminated, the linebuf is flagged terminated
+- If more data is trying to be squeezed into the buffer than space LEFT
+  in the buffer, we skip to the next "CRLF", and tag the buffer terminated
+  _and_ overflowed.
+- We treat multiple runs of CR/LF/CRLF/LFCR as a single CRLF. This is just
+  a little extra goody to stop people sending hundreds of "CRLF"s and creating
+  unnecessary buffers.
+- The number of lines parsed is returned (so you can implement per-line flood
+  protection ..)
+
+
+void
+linebuf_put(buf_head_t *bufhead, char *buf, int len)
+
+Parse the given buf, ASSUMING it is a single buffer line. This is useful
+for server-generated messages where you know you have a single line, and
+you don't want to go through the overhead of parsing the data just for
+this.
+
+
+int
+linebuf_get(buf_head_t *bufhead, char *buf, int maxlen)
+
+Get a single line from the buffer. This removes data from the head of the
+buffer. If the first buffer is empty or is not terminated, 0 is returned
+which indicates that there is no data to parse. Terminated buffers are
+returned (CR/LF/NUL), and the length INCLUDING the CR/LF/NUL is returned.
+The buffer is copied and the linebuf is then deallocated.
+
+
+int
+linebuf_flush(int fd, buf_head_t *bufhead)
+
+Attempt to flush some data to the given socket. bufhead->writeofs tracks
+where in the head buffer we currently are. If the buffer is not terminated,
+-1 is returned with errno == EWOULDBLOCK to simulate a "retry me" condition.
+(See TODO..)
+
+linebuf_flush() returns whatever write() returns, and sets (ie doesn't touch
+after write()) errno accordingly.
+
+
+int
+linebuf_len(buf_head_t *bufhead)
+
+Return the length of the buffer, in bytes. This should be used when calculating
+how big a buffer is for statistics.
+
+
+int
+linebuf_alloclen(buf_head_t *bufhead)
+
+Return how big the *allocated* space is. This is much more suitable for
+anti-flood checking, as someone might be sending a whole bunch of 1-byte
+linebufs which might not trigger a recvq / sendq limit but might chew up
+way too much memory.
+
+
+
+Notes
+-----
+
+* Remember that the trailing NUL isn't covered in the string length.
+
+
+Limitations
+-----------
+
+* all the buffers are a fixed size - here they are current 513 bytes
+  (510 bytes + CR/LF/NUL)
+
+
+TODO
+----
+
+* linebuf_flush() should be changed a little so if the buffer isn't
+  terminated, we *dont* retry flushing a buffer until we get more data.
+
+* Implement a reference-friendly linebuf to reduce copies ..
+
diff --git a/doc/technical/network.txt b/doc/technical/network.txt
new file mode 100644 (file)
index 0000000..3d7afe5
--- /dev/null
@@ -0,0 +1,105 @@
+Overview of the network subsystem
+Adrian Chadd <adrian@creative.net.au>
+
+$Id: network.txt 6 2005-09-10 01:02:21Z nenolod $
+
+
+This document is an overview of the new and hopefully improved network
+subsystem.
+
+The code is based loosely upon the network core found in the Squid web cache
+server, with some optimizations for ircd-specific IO patterns.
+
+
+
+Filedescriptor IO
+-----------------
+
+Filedescriptor IO is initiated using comm_setselect(). comm_setselect()
+registers interest in reading from or writing to a file descriptor.
+When a filedescriptor is ready for the required IO a callback is called
+from the IO loop.
+
+The comm_setselect() usage is:
+
+void
+comm_setselect(int fd, fdlist_t list, int type, PF *callback, void *cbdata,
+    int timeout)
+
+where:
+  fd           filedescriptor
+  list         Which list the FD should be put on
+  type         IO type. Can currently include:
+                       COMM_SELECT_READ  - register for read
+                       COMM_SELECT_WRITE - register for write
+  callback     Function to call when the FD is ready
+  cbdata       Data to be passed to above function
+  timeout      Update the timeout value. 0 is "don't update".
+
+
+A typical use is:
+
+..
+
+/* Register interest in the FD for a read event */
+comm_setselect(fd, FDLIST_SERVICE, COMM_SELECT_READ, read_callback, read_data,
+    0);
+
+..
+
+(FD becomes ready for read in the IO loop)
+
+void
+read_callback(int fd, void *data)
+{
+    /* called when the FD becomes ready for read */
+    retval = read(fd, buf, len);
+
+    ..
+    /* Ok, we need to read some more when its ready */
+    comm_setselect(fd, FDLIST_SERVICE, COMM_SELECT_READ, read_callback, data,
+        0);
+}
+
+
+
+
+Socket timeouts
+---------------
+
+A "socket timeout" is a callback registered to be called when a certain
+amount of time has elapsed. Think of it as an event, but against a FD.
+
+A good example of socket timeouts is in the comm_connect_tcp() code.
+When the connect() begins, comm_settimeout() is called to call
+comm_connect_timeout() if the timeout occurs. Once the connect() completes,
+comm_settimeout() is called with a timeout of 0 and callback of NULL 
+to deregister the timeout. If the timeout occurs, comm_connect_timeout()
+is called and the connection attempt is aborted.
+
+
+
+
+Functions
+---------
+
+comm_open() - a socket() wrapper, enforcing fd limitations and tagging the
+  file descriptor with a note
+
+comm_accept() - an accept() wrapper, enforcing fd limitations and tagging
+  the file descriptor with a note
+
+comm_connect_tcp() - attempt an async connect(). Handles DNS lookups if
+  required, and will call the given callback at completion or error
+
+comm_settimeout() - set a callback to be called after a given time period.
+  This is good to implement things like PING checks and connect() timeouts.
+
+Notes:
+
+* All socket creation should go through comm_open() / comm_accept().
+* All socket closing should go through fd_close(). comm_close() isn't
+  implemented yet.
+* comm_connect_tcp() is your best friend. :-)
+* *ALL* network sockets should be non-blocking. If your OS doesn't support
+  non-blocking sockets, you shouldn't be here.
diff --git a/doc/technical/rfc1459.txt b/doc/technical/rfc1459.txt
new file mode 100644 (file)
index 0000000..09fbf34
--- /dev/null
@@ -0,0 +1,3643 @@
+
+
+
+
+
+
+Network Working Group                                      J. Oikarinen
+Request for Comments: 1459                                      D. Reed
+                                                               May 1993
+
+
+                      Internet Relay Chat Protocol
+
+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:
+
+
+<message>  ::= [':' <prefix> <SPACE> ] <command> <params> <crlf>
+<prefix>   ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
+<command>  ::= <letter> { <letter> } | <number> <number> <number>
+<SPACE>    ::= ' ' { ' ' }
+<params>   ::= <SPACE> [ ':' <trailing> | <middle> <params> ]
+
+<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>       ::= ('#' | '$') <chstring>
+   <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> <hostname> <servername> <realname>
+
+   The USER message is used at the beginning of connection to specify
+   the username, hostname, servername and realname of s new user.  It is
+   also used in communication between servers to indicate new user
+   arriving on IRC, since only after both USER and NICK have been
+   received from a client does a user become registered.
+
+   Between servers USER must to be prefixed with client's NICKname.
+   Note that hostname and servername are normally ignored by the IRC
+   server when the USER command comes from a directly connected client
+   (for security reasons), but they are used in server to server
+   communication.  This means that a NICK must always be sent to a
+   remote server when a new user is being introduced to the rest of the
+   network before the accompanying USER is sent.
+
+   It must be noted that realname 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.
+
+   Numeric Replies:
+
+           ERR_NEEDMOREPARAMS              ERR_NOTONCHANNEL
+           RPL_NOTOPIC                     RPL_TOPIC
+           ERR_CHANOPRIVSNEEDED
+
+
+
+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.
+
+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
+
+   Examples:
+
+   NAMES #twilight_zone,#42        ; list visible users on #twilight_zone
+                                   and #42 if the channels are visible to
+                                   you.
+
+   NAMES                           ; list all visible channels and users
+
+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>]]
+
+   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>.
+
+   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.
+
+   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.
+
+5.4 Summon message
+
+      Command: SUMMON
+   Parameters: <user> [<server>]
+
+   The SUMMON command can be used to give users who are on a host
+   running an IRC server a message asking them to please join IRC.  This
+   message is only sent if the target server (a) has SUMMON enabled, (b)
+   the user is logged in and (c) the server process can write to the
+   user's tty (or similar).
+
+   If no <server> parameter is given it tries to summon <user> from the
+   server the client is connected to is assumed as the target.
+
+   If summon is not enabled in a server, it must return the
+   ERR_SUMMONDISABLED numeric and pass the summon message onwards.
+
+   Numeric Replies:
+
+           ERR_NORECIPIENT                 ERR_FILEERROR
+           ERR_NOLOGIN                     ERR_NOSUCHSERVER
+           RPL_SUMMONING
+
+   Examples:
+
+   SUMMON jto                      ; summon user jto on the server's host
+
+   SUMMON jto tolsun.oulu.fi       ; summon user jto on the host which a
+                                   server named "tolsun.oulu.fi" is
+                                   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.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
\ No newline at end of file
diff --git a/doc/technical/send.txt b/doc/technical/send.txt
new file mode 100644 (file)
index 0000000..7c92f10
--- /dev/null
@@ -0,0 +1,253 @@
+
+send.c re-work
+
+PREFIXES
+========
+
+  Server prefixes are the ":%s" strings at the beginning of messages.
+They are used by servers to route the message properly and by servers to
+local clients to update their idea of who is whom.
+
+":nick!user@host" is a prefix ":name" where name is either a nick
+or name of a server is another valid prefix.
+
+Typical prefix for a local client to a channel:
+
+":Dianora!db@irc.db.net"
+
+for a prefix to a remote server:
+":Dianora"
+
+e.g. as seen locally on a channel:
+
+":Dianora!db@irc.db.net PRIVMSG #us-opers :ON TOP OF ...\r\n"
+
+e.g. as seen sent to a remote server:
+":Dianora PRIVMSG #us-opers :ON TOP OF ...\r\n"
+
+  It has been argued that full prefixes sent locally are a waste of bandwidth
+(Isomer from Undernet has argued this). i.e. instead of sending:
+":nick!user@host" for a local prefix, one could just send ":nick"..
+Unfortunately, this breaks many clients badly. Personally I feel that
+until clients are updated to understand that a full prefix isn't always
+going to be sent, that this should be held off on.
+
+  As much as possible, prefix generation is now moved "upstairs" as
+much as possible. i.e. if its known its a local client only, then the
+onus of the prefix generation, is the users, not hidden in send.c
+This allows somewhat faster code to be written, as the prefix doesn't
+have to be regenerated over and over again.
+
+  Prefixes aren't sent in all cases, such as a new user using NICK
+A prefix is needed when it must be routed.
+
+i.e.
+
+NICK newnick
+
+  There is obviously no prefix needed from a locally connected client.
+
+
+
+FUNCTIONS
+=========
+
+sendto_one()    - Should be used for _local_ clients only
+                  it expects the prefix to be pre-built by user.
+                 
+                  usage - sendto_one(struct Client *to, char *pattern, ...);
+
+                  typical use:
+
+                  sendto_one(acptr,":%s NOTICE %s :I'm tired", me.name,
+                            acptr->name);
+                  Note: This was from a server "me" hence only one
+                  name in prefix.
+
+                  This would be an example of a client sptr, noticing
+                  acptr IF acptr is known to be a local client:
+
+                  sendto_one(acptr,":%s!%s@%s NOTICE %s :You there?",
+                             sptr->name,
+                             sptr->username,
+                             sptr->host,
+                             acptr->name);
+
+sendto_one_prefix()
+                - Sends a message to a remote client, with proper
+                 prefix and target (name or UID).
+                  usage - sendto_one_prefix(struct Client *target_p,
+                                           struct Client *source_p,
+                                           const char *command,
+                                           const char *pattern, ...)
+
+                 typical use:
+
+                 sendto_one_prefix(target_p, source_p, "INVITE", ":%s",
+                                   chptr->chname);
+
+
+sendto_one_notice()
+                - Sends a notice from this server to target. Target may
+                 be a local or remote client.
+                 Prefix and target are chosen based on TS6 capability.
+
+                 typical use:
+
+                 sendto_one_notice(source_p, ":You suck. Yes, really.");
+
+sendto_one_numeric()
+                - Sends a numeric from this server to target. Target may
+                 be a local or remote client.
+                 Prefix and target are chosen based on TS6 capability.
+
+                 typical use:
+
+                 sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                                    "p :%u staff members", count);
+
+sendto_channel_flags()
+                - This function sends a var args message to a channel globally,
+                  except to the client specified as "one", the prefix
+                  is built by this function on the fly as it has to
+                  be sent both to local clients on this server and to
+                  remote servers.
+                 For type use one of:
+                  ONLY_SERVERS ALL_MEMBERS ONLY_CHANOPS ONLY_CHANOPSVOICED
+                 If type is not ALL_MEMBERS it's not sent to not-CHW-capable
+                 servers.
+                 Deaf (umode +D) clients are always skipped.
+
+                  usage - sendto_channel_flags(struct Client *one,
+                                               int type,
+                                               struct Client *from,
+                                               struct Channel *chptr,
+                                               const char *pattern, ... );
+
+                  sendto_channel_butone(cptr, ALL_MEMBERS, sptr, chptr
+                                        "PRIVMSG %s :HI!",
+                                        chptr->chname);
+
+                  e.g. if channel message is coming from "cptr"
+                  it must not be sent back to cptr.
+
+
+sendto_server()
+                - This function sends specified var args message
+                  to all connected servers except the client "one"
+                  which have all of "caps" capabilities but none
+                 of "nocaps" capabilities.
+
+                 If "chptr" is not NULL and is a local channel,
+                 nothing is sent.
+
+                  usage - sendto_server(struct Client *one,
+                                        struct Channel *chptr,
+                                       unsigned long caps,
+                                       unsigned long nocaps,
+                                        const char *format, ... );  
+
+sendto_common_channels_local()
+                - This function is used only by m_nick and exit_one_client
+                  its used to propagate nick changes to all channels user
+                  is in, and QUIT messages to all channels user is in.
+                  As it only sends to local clients, prefix generation
+                  is left to the user. It also sends the message to the
+                  user if the user isn't on any channels.
+
+                  usage - sendto_common_channels_local(struct Client *user,
+                                                       const char *pattern,
+                                                       ...);
+
+sendto_channel_local()
+                - This function is used to send only locally, never
+                  to remote servers. This is useful when removing
+                  local chanops, or adding a local chanop. MODE/SJOIN
+                  sent to remote server allows that server to propagate
+                  mode changes to its clients locally.
+                 The message is also sent to deaf (umode +D) clients.
+
+                  usage - sendto_channel_local(int type,
+                                               struct Channel *chptr,
+                                               const char *pattern, ... );
+
+                  prefix must be pre-built. type is a flag
+                  denoting ONE of 
+                  ALL_MEMBERS          - all members locally are sent to
+                  ONLY_CHANOPS_VOICED  - only chanops and voiced see this
+                  ONLY_CHANOPS         - only chanops see this
+
+
+sendto_match_butone()
+                - only used for the old style oper masking
+                  i.e. /msg #hostmask which in hyb7 is /msg $#hostmask
+                  or  /msg $servermask in hyb7 /msg $$servermask
+
+                  usage - sendto_match_butone(struct Client *one,
+                                              struct Client *source_p,
+                                              char *mask,
+                                              int what,
+                                              const char *pattern, ... );
+
+                  one is the client not to send to
+                  mask is the actual mask
+                  what is either MATCH_HOST or MATCH_SERVER
+
+sendto_match_servs()
+                - Allows sending a message to servers whose names match
+                 the given mask. A message is also sent to non-matching
+                 servers which have matching servers behind them.
+                 Used for ENCAP, remote kline, etc.
+                 No message is sent to source_p->from.
+
+                 usage - sendto_match_servs(struct Client *source_p,
+                                            const char *mask,
+                                            int cap, int nocap,
+                                            const char *pattern, ...);
+
+sendto_anywhere()
+                - Allows the sending of a message to any client on the net
+                  without knowing whether its local or remote. The penalty
+                  is the calculation of a run-time prefix.
+                  It is less efficient then sendto_one()
+
+                  usage - sendto_anywhere(struct Client *to,
+                                          struct Client *from,
+                                          const char *command,
+                                          const char *pattern, ...);
+
+                  e.g.
+                  sendto_anywhere(target_p, source_p,
+                                  "PRIVMSG", ":Hi, Where ever you are");
+
+sendto_realops_flags()
+                - combines old sendto_realops and sendto_realops_flags
+                  sends specified message to opers locally only
+                  depending on umodes. UMODE_ALL is UMODE_SERVNOTICE.
+                  the message is sent as a server notice, prefixed with
+                 "*** Notice -- ".
+
+                  usage - sendto_realops_flags(int flags,
+                                               const char *pattern, ... );
+
+                  e.g.
+                  sendto_realops_flags(UMODE_ALL,
+                                 "Don't eat the yellow snow");
+
+sendto_wallops_flags()
+                - sends specified message to opers/users locally, 
+                  depending on umodes.  used for messages that need
+                  to be in wallops form
+                - some policy decisions about who gets what live in here
+
+                  usage - sendto_wallops_flags(int flags,
+                                    struct Client *, const char *patterm ...);
+
+                  e.g.
+                  sendto_wallops_flags(UMODE_LOCOPS,
+                                      sptr, "Message");
+
+-- Diane Bruce 
+Updated Jan 2006 by jilles with ratbox and late hybrid7 changes
+
+$Id: send.txt 587 2006-01-27 19:45:11Z jilles $
diff --git a/doc/technical/ts5.txt b/doc/technical/ts5.txt
new file mode 100644 (file)
index 0000000..0a6ad26
--- /dev/null
@@ -0,0 +1,151 @@
+  Overview of the TS5 system
+  Lee H <lee@leeh.co.uk>
+
+$Id: ts5.txt 6 2005-09-10 01:02:21Z nenolod $
+
+For the purposes of this document, ircd versions:
+  hybrid6.0
+  ircd-comstud-1.12
+  CSr31pl4
+
+and prior, are TS3.
+
+ircd-hybrid-6.2 and later support TS5.
+
+
+Whats TS5?
+----------
+
+The difference between TS5 and TS3 is what happened on opless channels.  TS
+works by establishing which server has the oldest version of the channel,
+the version that is oldest, keeps its modes and ops, the version that is
+youngest, removes their modes and ops, and accepts the older version.
+
+There was an exception to this rule with opless channels, if a channel was
+opless, TS3 would allow anybody to keep their ops and modes on the channel.
+TS5 aims to stop this, by removing this exception.
+
+Example1: 
+
+An irc network, with server A (every server is ts3)
+
+UserA is on ServerA, in channel #broken.  This channel is opless, and has a
+TS of 800000000.  ServerA splits, and whilst it is split, UserA cycles
+channel #broken, recreates the channel and is given ops.  On ServerA #broken
+now has a TS of 900000000 and has ops.  ServerA rejoins with the network,
+via HubB.  HubB realises #broken is opless, so allows UserA to retain ops.
+The TS is moved forward to 900000000.
+
+The network now sees #broken as having a TS of 900000000, with UserA being
+opped.
+
+Example2:
+
+An irc network, with server C (every server is ts5)
+
+Same scenario as above.  ServerC splits and UserC cycles channel #broken,
+recreating it with a TS of 900000000.  ServerC rejoins with the network via
+HubD.  HubD realises #broken has a TS of 800000000 locally, and ServerC is
+showing a TS of 900000000, it ignores ServerC's modes and ops.  The channel
+remains opless.  ServerC receives HubD's modes, and it notices HubD has a
+lower TS of channel #broken.  It removes UserC's ops, removes the channel
+modes on #broken, and accepts HubD's status.
+
+The network version of #broken hasnt changed.  It is still opless, with a TS
+of 800000000.
+
+
+As you can see, TS5 makes splitting a server to regain ops useless, as it
+cannot be abused to give ops after a netsplit.
+
+The problem with TS5 however, is what happens on a mixed TS5/TS3 network.
+Channels where the older TS has ops will behave the same way on TS5 and TS3,
+however an opless channel will behave differently, as you can see above.
+
+The result of TS5/TS3 mixed can be a desync:
+
+Example1:
+
+As per Example1 above, except the rest of the network is TS5, ServerA is
+TS3.  ServerA would keep its modes and ops, whilst the rest of the network
+would remove them.  This means only ServerA would see UserA as opped.  The
+desync can be abused, as UserA can send modes.  Hybrid6.0 servers will
+accept these modes from the unopped client, so if UserA ops UserB, who then
+ops UserA, the channel will be the same across all Hybrid6.0 and Hybrid6.1
+servers.
+
+Example2:
+
+As per Example2 above, except the rest of the network is TS3.  ServerC is
+TS5.  ServerC would remove its modes and ops, therefore UserC would not be
+opped on ServerC, therefore it could not send any mode changes to the
+channel.  Although it is opped elsewhere, it isnt opped locally, so the
+desync cannot be abused.
+
+As you can see, the desync's that can occur can either be resynced, or are
+useless to the user, so a mixed TS5/TS3 network is not a huge problem,
+although a desync is NOT a good thing to have.
+
+
+Why TS5?
+--------
+
+We have jumped to TS5 from TS3, because there was a version of ircd that was
+TS4, so it was thought better to avoid a clash with an existing version.
+
+
+Advantages
+----------
+
+Its a realistic event that a server will be attacked so it splits off a
+network, then used to regain ops in a channel.  TS5 makes this pointless,
+the server will never give ops on a netsplit.  TS5 is network wide, so it
+leaves individual servers free to choose options like NO_JOIN_ON_SPLIT,
+whilst keeping splits useless to users.
+
+
+Disadvantages
+-------------
+
+Its virtually impossible for a user to actively regain ops themselves (some
+regard this as an advantage..) because on a large sized channel, its
+impossible to get people to leave so it can be recreated, therefore if a
+network did not have some form of services, it could possibly end up
+requiring oper intervention, as you cant get everybody to leave, and you
+cant use splits to regain ops, therefore if the channel is open (an
+invite-only channel would gradually destroy itself as noone new can join) it
+could be impossible for a user to regain ops.
+
+On a network that has some form of services, The effect of TS5 would be
+minimal, however the services must be of sufficient quality to fix opless
+channels, as TS5 renders netsplits for ops worthless.
+
+
+Recommendations
+---------------
+
+If your network has good stable services, we recommend TS5 is enabled, as
+people have no reason to abuse netsplits anyway.
+
+If your network has no services at all, then TS5 may cause problems with
+users being left with a permanently opless channel.
+
+If your network occupies the middle ground, then its a choice between users
+needing to be able to use splits to regain ops, or making netsplits that are
+caused to regain ops worthless.
+
+If TS5 is chosen, the FULL network must upgrade and this should be done in a
+relatively short space of time to minimise the possible desync effects.
+
+
+Alternatives
+------------
+
+There is also NO_JOIN_ON_SPLIT and NO_OP_ON_SPLIT, however these use the
+configuration of minimum servers and users, and sometimes a split that is
+above these limits is enough to be abused to regain ops, whereas if the
+limits are too high, clients will never be able to join anything or be opped
+when they create a channel.
+
+
+EOF
diff --git a/doc/technical/ts6.txt b/doc/technical/ts6.txt
new file mode 100644 (file)
index 0000000..516d373
--- /dev/null
@@ -0,0 +1,269 @@
+$Id: ts6.txt 6 2005-09-10 01:02:21Z nenolod $
+
+TS6 Proposal (v7)
+Written by Lee H <lee@leeh.co.uk>
+Ideas borrowed heavily from ircnet (Beeth, jv, Q)
+
+Introduction
+------------
+
+This document aims to fix some of the flaws that are still present in the
+current TS system.
+
+Whilst only one person may use a nickname at any one time, they are not
+a reliable method of directing commands between servers.  Clients can change
+their nicknames, which can create desyncs.  A reliable method of directing
+messages between servers is required so that a message will always reach the
+intended destination, even if the client changes nicks in between.
+
+UID solves this problem by ensuring that a client has a unique ID for the
+duration of his connection.
+
+This document also aims to solve the lack of TS rules to channel 'bans' on
+a netburst.  Bans from both sides of a TS war (losing/winning) are kept.
+Bursting the bans with a TS solves this problem.
+
+There is also a race condition in the current TS system, where a user can
+issue a mode during a netburst and the mode will be set on the server 
+we are bursting to.
+
+
+Definitions
+-----------
+
+Throughout this document, the following terms are used:
+
+SID    - A servers unique ID.  This is three characters long and must be in
+          the form [0-9][A-Z0-9][A-Z0-9]
+ID      - A clients unique ID.  This is six characters long and must be in
+          the form [A-Z][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9].  The
+          numbers [0-9] at the beginning of an ID are legal characters, but
+          reserved for future use.
+UID     - An ID concateneted to a SID.  This forms the clients UID.
+TS6     - The TS version 6.
+
+
+Support
+-------
+
+Support for this document is given by the TS version 6.
+
+Wherever a destination parameter or source parameter is used, it must use
+the SID or UID if the server/client has one.  A TS6 capable server must
+translate any SIDs/UIDs back into the server/clients name when communicating
+with a server that does not support TS6.
+
+A TS6 server must also support the QS (quitstorm) system, and the encap
+specification found here:
+http://www.leeh.co.uk/ircd/encap.txt
+
+The TS6 protocol does not supports masked entities.
+
+
+Nick TS rules
+-------------
+
+A server receiving a command that requires nick TS rules must check for a
+collision between an existing user, and the nick in the received message.
+(the "new user").  The collisions must obey the rules specified in Nick TS
+collisions.
+
+If the TS received is lower than the TS of the existing user the server will
+collide the existing user if the clients user@host are different, if the
+clients user@hosts are identical it will collide the new user.
+
+If the TS received is equal to the TS of the existing user both clients are
+collided.
+
+If the TS received is higher than the TS of the existing user, the server
+will collide the existing user if the user@hosts are identical, if the
+clients user@host are different it will collide the new user and drop the 
+message.
+
+
+Nick TS collisions
+------------------
+
+If both users are to be collided, we must issue a KILL for the existing 
+user to all servers.  If the new user has a UID then we must also issue a 
+KILL for that UID back to the server sending us data causing the collision.
+
+If only the existing user is being collided, we must issue a KILL for the
+existing user to all servers except the server sending us data.  If the 
+existing user has a UID and the server sending us data supports TS6 then 
+we must also issue a KILL for the existing users UID to the server sending 
+us data.
+
+If only the new user is being collided, we must issue a KILL for the new user 
+back to the server sending us data if the new user has a UID.
+
+
+Channel TS rules
+----------------
+
+A server receiving a command that requires normal channel TS rules must 
+apply the following rules to the command.
+
+If the TS received is lower than our TS of the channel a TS6 server must
+remove status modes (+ov etc) and channel modes (+nt etc).  If the 
+originating server is TS6 capable (ie, it has a SID), the server must
+also remove any ban modes (+b etc).  The new modes and statuses are then
+accepted.
+
+If any bans are removed, the server must send to non-TS6, directly connected 
+servers mode changes removing the bans after the command is propagated.
+This prevents desync with banlists, and has to be sent after as clients are
+still able to send mode changes before the triggering command arrives.
+
+If the TS received is equal to our TS of the channel the server should keep
+its current modes and accept the received modes and statuses.
+
+If the TS received is higher than our TS of the channel the server should keep
+its current modes and ignore the received modes and statuses.  Any statuses
+given in the received message will be removed.  A server must mark clients 
+losing their op (+o) status who do not have a UID as 'deopped'.  A server must 
+ignore any "MODE" commands from a user marked as 'deopped'.
+
+
+Simple channel TS rules
+-----------------------
+
+A server receiving a command that requires simple channel TS rules must
+apply the following rules to the command.
+
+If the TS received is lower, or equal to our TS of the channel the modes are
+accepted.  If the TS received is higher than our TS of the channel the modes
+are ignored and dropped.
+
+Simple channel TS rules do not affect current modes in the channel except
+for the modes we are accepting.
+
+
+The following commands are defined here as the TS6 protocol
+-----------------------------------------------------------
+
+PASS:
+PASS <PASSWORD> TS <TS_CURRENT> :<SID>
+
+This command is used for password verification with the server we are
+connecting to.
+
+Due to the burst being sent on verification of the "SERVER" command, and
+"SVINFO" being sent after "SERVER", we need to be aware of the TS version
+earlier to decide whether to send a TS6 burst or not.
+
+The <PASSWORD> field is the password we have stored for this server,
+<TS_CURRENT> is our current TS version.  If this field is not present then
+the server does not support TS6.  <SID> is the SID of the server.
+
+UID:
+:<SID> UID <NICK> <HOPS> <TS> +<UMODE> <USERNAME> <HOSTNAME> <IP> <UID> :<GECOS>
+
+This command is used for introducing clients to the network.
+
+The <SID> field is the SID of the server the client is connected to.
+The <NICK> field is the nick of the client being introduced.  The <HOPS>
+field is the amount of server hops between the server being burst to and
+the server the client is on.  The <TS> field is the TS of the client, either
+the time they connected or the time they last changed nick.  The <UMODE>
+field contains the clients usermodes that need to be transmitted between
+servers.  The <USERNAME> field contains the clients username/ident.  The
+<HOSTNAME> field contains the clients host.
+
+The <IP> field contains the clients IP.  If the IP is not to be sent
+(due to a spoof etc), the field must be sent as "0".  The <UID> field is the 
+clients UID.  The <GECOS> field is the clients gecos.
+
+A server receiving a UID command must apply nick TS rules to the nick.
+
+SID:
+:<SID> SID <SERVERNAME> <HOPS> <SID> :<GECOS>
+
+This command is used for introducing servers to the network.
+
+The first <SID> field is the SID of the new servers uplink.  The
+<SERVERNAME> field is the new servers name.  The <HOPS> field is the hops
+between the server being introduced nd the server being burst to.
+
+The second <SID> field is the SID of the new server.  The <GECOS> field i
+is the new servers gecos.
+
+Upon receiving the SID command servers must check for a SID collision.  
+Two servers must not be allowed to link to the network with the same SID.  
+If a server detects a SID collision it must drop the link to the directly 
+connected server through which the command was received.
+
+Client and servers which do not have a UID/SID must be introduced by old
+methods.
+
+SJOIN:
+:<SID> SJOIN <TS> <CHANNAME> +<CHANMODES> :<UIDS>
+
+This command is used for introducing users to channels.
+
+The <SID> field is the SID of the server introducing users to the channel.
+The <TS> field is the channels current TS, <CHANNAME> is the channels
+current name, <CHANMODES> are the channels current modes.  <UIDS> is a
+space delimited list of clients UIDs to join to the channel.  Each clients
+UID is prefixed with their status on the channel, ie "@UID" for an opped
+user.  Multiple prefixes are allowed, "peons" (clients without a status) are
+not prefixed.
+
+A server receiving an SJOIN must apply normal channel TS rules to the SJOIN.  
+
+A TS6 server must not use the SJOIN command outside of a netburst
+to introduce a single user to an existing channel.  It must instead
+use the "JOIN" command defined in this specification.  A TS6 server must
+still use SJOIN for creating channels.
+
+JOIN:
+:<UID> JOIN <TS> <CHANNAME> +<CHANMODES>
+
+This command is used for introducing one user unopped to an existing channel.
+
+The <UID> field is the UID of the client joining the channel.  The
+<TS> field is the channels current TS, <CHANNAME> is the channels
+current name, <CHANMODES> are the channels current modes.
+
+A server receiving a JOIN must apply normal channel TS rules to the JOIN.
+
+It should be noted that whilst JOIN would not normally create a 
+channel, during specific race conditions it can.  This can create
+a ban desync that this specification does not rectify.
+
+BMASK:
+:<SID> BMASK <TS> <CHANNAME> <TYPE> :<MASKS>
+
+This command is used for bursting channel bans to a network.
+
+The <SID> field is the SID of the server bursting the bans.  The
+<TS> field is the channels current TS, <CHANNAME> is the channels
+name.  <TYPE> is a single character identifying the mode type (ie,
+for a ban 'b').  <MASKS> is a space delimited list of masks of the 
+given mode,limited only in length to the size of the buffer as defined 
+by RFC1459.
+
+A server receiving a BMASK must apply simple channel TS rules to the BMASK.
+
+A TS6 server must translate BMASKs into raw modes for non-TS6 
+capable servers.  This command must be used only after SJOIN has
+been sent for the given channel.
+
+It should be noted however, that a BMASK with a lower TS should
+not be possible without a desync, due to it being sent after
+SJOIN.
+
+TMODE:
+:<UID> TMODE <TS> <CHANNAME> <MODESTRING>
+
+This command is used for clients issuing modes on a channel.
+
+<UID> is the UID of the client setting the mode.  <TS> is the
+current TS of the channel, <CHANNAME> is the channels name.
+<MODESTRING> is the raw mode the client is setting.
+
+A server receiving a TMODE must apply simple channel TS rules to the TMODE.
+
+A TS6 server must translate MODEs issued by a local client into TMODE 
+to send to other TS6 capable servers.
+
diff --git a/doc/tgchange.txt b/doc/tgchange.txt
new file mode 100644 (file)
index 0000000..0669d67
--- /dev/null
@@ -0,0 +1,38 @@
+Target Change for Messages
+Lee H <lee -at- leeh.co.uk>
+---------------------------
+
+If the server you are using uses the target change mechanism, then
+restrictions are placed on how many different users you can message in a set
+timeframe.
+
+Target change does not apply to channels, ctcp replies or messages to
+yourself.
+
+You will have a set number of 'slots', each different client you message
+will take up one slot.  A client doing a nick change will not use a new slot,
+however a client leaving the network and reconnecting will.  You will
+receive 1 new slot roughly every minute.
+
+When all slots are filled, messages to new clients will not be accepted.
+Messages to clients already filling a slot will be accepted.  If all slots
+are full, you will receive the ERR_TARGCHANGE numeric, number 707 in the
+form:
+:<server> 707 <yournick> <targetnick> :Targets changing too fast, message dropped
+
+The slots are operated as a FIFO (first in, first out), so the first person
+you message will be the first person removed from a slot, even if you are
+still talking to this person.
+
+The number of slots in use will be kept through a reconnection, though the
+information in those slots will be dropped.  However, you will always
+receive one free slot on a reconnection.  Other servers using this mechanism
+will also be made aware of details about slots.
+
+Target change can be avoided via the CNOTICE and CPRIVMSG commands, when you 
+are opped or voiced in a channel, and you are messaging a client within that 
+channel.  See /quote help cnotice and /quote help cprivmsg for more
+information.
+
+-- 
+$Id: tgchange.txt 6 2005-09-10 01:02:21Z nenolod $
diff --git a/doc/whats-new-2.0.txt b/doc/whats-new-2.0.txt
new file mode 100644 (file)
index 0000000..96b0d55
--- /dev/null
@@ -0,0 +1,113 @@
+$Id: whats-new-2.0.txt 6 2005-09-10 01:02:21Z nenolod $
+
+The following is a list of major changes between ircd-ratbox-1.x and
+ircd-ratbox-2.0
+
+Config File
+-----------
+- name="foo"; is no longer supported in connect {}; operator {}; and
+  class {};.  You must now use connect "irc.foo.com" { ... }; etc.
+- operator {}; no longer contains a class
+- kline_with_connection_closed is gone, replaced with 
+  kline_reason = "Connection closed";
+- logging {}; is gone, replaced with more advanced log system - see
+  example.conf log {}; for more info.  Note, by default only very basic
+  information will be logged.
+- support for a specific opers initial umodes on /oper, by umodes = ...;
+  in operator {};
+- added stats_e_disabled = yes|no; to general {};, controlling whether stats
+  e (which can contain server ips) is never shown to anyone
+- support for compressed|encrypted|topicburst|autoconn = yes|no; is gone,
+  replaced with flags = compressed, encrypted, topicburst, autoconn;
+- support for individual auth flags "kline_exempt = yes"; etc removed, now
+  must use flags = ...; method
+- support for individual oper flags "kline = yes;" etc removed, now must use
+  flags = ...; method.
+- extended flags = ...; method to allow negation, so you may prefix a flag
+  with '~' to negate it.  Default oper flags are operwall, remoteban and
+  encrypted (indicates password is encrypted with mkpasswd)
+- new flags in shared {};, tkline, txline and tresv, allowing temp only of
+  kline, xline and resv respectively.
+- new flags in cluster {}; tkline, txline and tresv which will cluster
+  only the temp of each type.  kline, xline and resv will now only
+  cluster the permanent ones of each type.
+- cluster {}; no longer allows a server to place klines etc locally, it
+  simply dictates who we send to.
+- shared {}; is now ordered top-down and the first one that matches the
+  user@host and server will be used, and the flags taken from this.  This
+  means if a remote oper matches a shared block without kline privs, even
+  though there is a shared {}; block they match under it with kline privs 
+  they will not be able to place klines.
+- added invite_ops_only to channel {}; which will restrict the use of INVITE
+  to chanops on that channel always, rather than just to +i chans.
+
+Client
+------
+- /help is now available for all users, as its now cached in memory.
+  removes config option use_help from general {};
+- default CHANNELLEN for local clients is now 50
+- AWAYLEN added to 005, default is 90
+- kick/part/quit now use REASONLEN (120) rather than TOPICLEN
+- umode +g now exempts users messaging themselves
+
+Oper
+----
+- kline/dline <nick> is no longer supported
+- oper reasons are now more fully supported
+- opers can now be hidden from stats p, by flag "invisible"
+- XLINEs no longer contain a type field, theyll now all just silently reject
+- xlines are now 'tracked' - stats X shows how many times each xline has
+  rejected a client
+- temp xlines and resvs
+- klines set against spoofed users will now take effect when the user
+  connects as well, if the user is not kline_exempt
+- trace spy now contains target param if its against a single user
+- the old "you need xline=yes;" notices have been replaced by ERR_NOPRIVS
+  (numeric 723)
+- umode +C, machine parsable client connect/exit notices which includes the
+  two unused fields sent in the USER command
+
+Channels
+--------
+- persistent channels have been removed
+- quiet_on_ban now uses a cache, which should speed it up
+
+Server <-> Server Protocol
+--------------------------
+- support for bursting away messages on connect, controlled by
+  burst_away = yes|no; in general {};
+- TS6, the new server <-> server protocol.  As part of this you *must*
+  specify a "sid" in serverinfo {}; that is three alphanumeric characters,
+  and must start with a digit.  use_ts6 = yes|no; in general controls
+  whether it is actually used or not.  For more information, see:
+  http://www.ircd-ratbox.org/TS6.txt 
+- fakename in connect {}; is gone, you can no longer mask servers.
+- support for encrypted links are gone
+- global capabilities.  The server will now inform the rest of the network
+  over ENCAP about the capabilities of other servers.
+
+Misc
+----
+- support for message translation has been removed.  If you want these,
+  modify messages.tab and distribute that.
+- most of server hiding is gone, only thing that is left is flattened links
+- flattened links cache is now stored in memory instead of a file
+- nick delay.  any client which splits will have their nick 'locked', until
+  a remote client uses this nick, or until it expires after the time nick_delay 
+  in general {}.  This prevents the masses of kills from clients 'regaining'
+  nicknames on a short split.
+- support for disabling bold chars etc in channel names for local users, to
+  prevent faking channels.  disable_fake_channels = <yes|no>; in general {};
+
+Code cleanups
+-------------
+- remove mapped ipv4 in ipv6 sockets, the correct native socket will now be
+  used for each.
+- module API has been rewritten, 1.x modules will no longer work.
+- hook API has been rewritten
+- proper handlers for ENCAP commands
+- support for vms ast i/o
+- connect {}; and operator {}; are now in their own structs, saving memory
+  in ConfItem
+- shared/cluster now use the same struct and flags
+- various other code cleanups thatd take all year to list ;)
diff --git a/doc/whats-new-2.1.txt b/doc/whats-new-2.1.txt
new file mode 100644 (file)
index 0000000..29b8325
--- /dev/null
@@ -0,0 +1,69 @@
+# $Id: whats-new-2.1.txt 6 2005-09-10 01:02:21Z nenolod $
+
+The following is a list of the major changes between ircd-ratbox-2.0 and
+ircd-ratbox-2.1.
+
+Config file
+-----------
+- IP entries within exempt {}; can now be stacked, eg:
+  exempt { ip = "127.0.0.1"; ip = "192.168.0.0/24"; };
+- shared {}; has been completely reworked so that it allows stacking.
+  shared {}; blocks for 2.0 and earlier will no longer work.  
+  See example.conf for the new format.
+- cluster {}; has been reworked to allow stacking.
+  cluster {}; blocks for 2.0 and earlier will no longer work.
+  See example.conf for the new format.
+- New auth flag, jupe_exempt.  When set on a client, that client will not
+  generate jupe warning notices when they try to join juped channels.
+- You may no longer specify klines, dlines, xlines and resvs in ircd.conf.
+  Instead, there is no support for banconfigs with a ".perm" extension,
+  eg kline.conf.perm.  Anything within a .perm file will be read, but
+  cannot be removed via the ircd.  The format of these files is the same
+  format as their normal non-permanent counterpart.  So kline.conf.perm
+  takes the same format as kline.conf, and so on.
+- rehash and kill -HUP no longer reread the ban configs kline.conf etc.
+  You must now use /rehash bans, or kill -USR2
+- New config option to general {};, dline_with_reason = yes|no;.  Default no.
+  Traditionally, when a client connects and is dlined, the reason is never
+  shown.  Enabling this will output the reason to clients.
+
+
+Client
+------
+- Support for "deaf", umode +D.  When a client is 'deaf', they will not
+  receive any messages sent towards channels.  They will still receive joins
+  etc, but normal channel chat will not be sent.  Any private messages
+  will still be sent.
+- Target change anti-spam system.  Restrictions are now placed upon how many
+  different clients (not channels) can be messaged within a specific time
+  period.
+- Server-side notify lists.  These allow a client to request a server
+  notifies them when a nickname comes online or goesoffline.  See 
+  doc/monitor.txt for more information.
+- Client capabilities.  These allow clients to negotiate capabilities with
+  the server.  Currently supports:
+    - multi-prefix: A +ov client will have "@+" shown in names/who replies.
+
+Oper
+----
+- RESVs are now tracked.  Stats q/Q have been modified so that the first
+  field of the output is now a number indicating how many times the RESV
+  has been hit.
+
+ratbox-services support (non-efnet)
+-----------------------------------
+- For those of you using ratbox-services, there is now compatibility code
+  within ircd, enabled by passing '--enable-services' to configure.
+  See doc/services.txt for more information.
+
+Code cleanups
+-------------
+- Removed the custom file implementation, use the system one instead.
+- The hook system has been redesigned, theres now a more thorough set of
+  hooks that may be used.  See docs/hooks.txt
+- Removed support for VMS.  It hasnt worked for a long time.
+- Cleanups to the expiry of temp klines/dlines.
+- Various other things ;-).
+- Better splitcode, it now works on how many servers have notified
+  us of burst finishing, rather than how many servers are linked to the
+  network.
diff --git a/extensions/.cvsignore b/extensions/.cvsignore
new file mode 100644 (file)
index 0000000..f3c7a7c
--- /dev/null
@@ -0,0 +1 @@
+Makefile
diff --git a/extensions/.indent.pro b/extensions/.indent.pro
new file mode 100644 (file)
index 0000000..ed83a1b
--- /dev/null
@@ -0,0 +1 @@
+-i8 -bli0 -cs -ut -nsai -nsaw -nsaf -npcs -nprs -l100
diff --git a/extensions/Makefile.in b/extensions/Makefile.in
new file mode 100644 (file)
index 0000000..503e3b3
--- /dev/null
@@ -0,0 +1,101 @@
+#
+# Makefile.in for ircd/contrib
+#
+# $Id: Makefile.in 1849 2006-08-23 12:40:21Z jilles $
+#
+CC             = @CC@
+RM             = @RM@
+SED             = @SED@
+LEX            = @LEX@
+LEXLIB         = @LEXLIB@
+CFLAGS         = @IRC_CFLAGS@ -DIRCD_PREFIX=\"@prefix@\"
+PICFLAGS       = @PICFLAGS@
+MKDEP          = @MKDEP@
+INSTALL                = @INSTALL@
+INSTALL_PROGRAM        = @INSTALL_PROGRAM@
+INSTALL_DATA   = @INSTALL_DATA@
+INSTALL_SUID    = @INSTALL_PROGRAM@ -o root -m 4755
+SHELL          = /bin/sh
+AUTOMODULEDIR  = @moduledir@/extensions
+
+SSL_LIBS       = @SSL_LIBS@
+SSL_INCLUDES   = @SSL_INCLUDES@
+
+IRCDLIBS       = @LIBS@ $(SSL_LIBS)
+
+INCLUDES       = -I. -I../include -I../libcharybdis -I../adns $(SSL_INCLUDES)
+CPPFLAGS       = ${INCLUDES} @CPPFLAGS@
+
+SRCS =                          \
+  createauthonly.c             \
+  extb_account.c               \
+  extb_canjoin.c               \
+  extb_channel.c               \
+  extb_oper.c                  \
+  extb_server.c                        \
+  extb_realname.c              \
+  extb_extgecos.c              \
+  hurt.c                       \
+  ip_cloaking.c                        \
+  sno_farconnect.c             \
+  sno_globalkline.c            \
+  sno_globaloper.c             \
+  m_42.c                       \
+  m_findforwards.c             \
+  m_identify.c                 \
+  m_mkpasswd.c                  \
+  m_ojoin.c                    \
+  m_olist.c                    \
+  m_okick.c                    \
+  m_omode.c                    \
+  m_opme.c                     \
+  m_webirc.c                   \
+  no_oper_invis.c              \
+  spy_admin_notice.c           \
+  spy_info_notice.c            \
+  spy_links_notice.c           \
+  spy_motd_notice.c            \
+  spy_stats_notice.c            \
+  spy_stats_p_notice.c         \
+  spy_trace_notice.c           \
+  spy_whois_notice.c            \
+  spy_whois_notice_global.c    \
+  example_module.c
+
+OBJS = ${SRCS:.c=.so}
+
+default:       build
+build: all
+all: $(OBJS)
+
+install: all
+       -@if test ! -d $(DESTDIR)$(AUTOMODULEDIR); then \
+                mkdir $(DESTDIR)$(AUTOMODULEDIR); \
+        fi
+       @echo "Installing modules into $(DESTDIR)$(AUTOMODULEDIR) .."
+       @for file in $(OBJS); do \
+               $(INSTALL_DATA) $$file $(DESTDIR)$(AUTOMODULEDIR); \
+       done
+
+.SUFFIXES: .so
+
+.c.so:
+       ${CC} ${PICFLAGS}  ${CPPFLAGS} ${CFLAGS} $< -o $@
+
+.PHONY: depend clean distclean
+depend:
+       @${MKDEP} ${CPPFLAGS} ${SRCS} > .depend
+       @sed s/\\\.o/\\\.so/ < .depend > .depend.tmp
+       @sed -e '/^# DO NOT DELETE THIS LINE/,$$d' <Makefile >Makefile.depend
+       @echo '# DO NOT DELETE THIS LINE!!!' >>Makefile.depend
+       @echo '# make depend needs it.' >>Makefile.depend
+       @cat .depend.tmp >>Makefile.depend
+       @mv Makefile.depend Makefile
+       @rm -f .depend.tmp .depend
+
+clean:
+       ${RM} -f *.so *~ 
+
+distclean: clean
+       ${RM} -f Makefile
+
diff --git a/extensions/README b/extensions/README
new file mode 100644 (file)
index 0000000..51bd10c
--- /dev/null
@@ -0,0 +1,68 @@
+$Id: README 1622 2006-06-04 03:01:05Z beu $
+
+This directory contains extensions (modules) to charybdis ircd that
+have been contributed by other people, or written by our development
+team.  Unsupported extensions live under unsupported/.
+
+
+Modules
+-------
+
+createauthonly.c - Only allow authenticated (identified) users to create
+                   channels.
+
+ip_cloaking.c  - Cloak (spoof) the host for users that have umode +h.
+
+m_42.c         - The Answer to Life, the Universe, and Everything.
+                 Syntax: 42
+
+m_findforwards.c - Find channels that forward (+f) to a given channel.
+                   Syntax: FINDFORWARDS <channel>
+
+m_mkpasswd.c   - MKPASSWD - generate a DES or MD5 encryption of a password
+                 Syntax:  MKPASSWD <plaintext> [MD5|DES]
+
+m_ojoin.c      - OJOIN - Join a channel through any modes or limits with 
+                         an optional status (@%+)
+                 Syntax: OJOIN [status]<channel>
+
+m_olist.c      - OLIST - Lists channels like LIST, but shows hidden
+                         channels. Oper only of course.
+
+m_opme.c       - OPME - Allows an admin to op themselves in an opless channel
+                 Syntax: OPME <channel>
+
+m_omode.c      - OMODE - Allows an admin to do all sorts of evil upon a
+                        channel, sets modes with extreme prejudice
+
+no_oper_invis.c - Disallow opers setting marking themselves as invisible
+                  (+i) unless they have the hidden_oper flag.
+
+example_module.c - An example module to be used for creating your own.
+                   Syntax: TEST
+
+
+Spy Modules
+-----------
+
+The following are the 'spy' parts, accessible via the +y usermode
+
+spy_admin_notice.c   - Spy on clients doing ADMIN
+spy_info_notice.c    - Spy on clients doing INFO
+spy_links_notice.c   - Spy on clients doing LINKS
+spy_motd_notice.c    - Spy on clients doing MOTD
+spy_stats_notice.c   - Spy on clients doing all STATS
+spy_stats_p_notice.c - Spy on clients doing STATS p only
+spy_trace_notice.c   - Spy on clients doing TRACE/LTRACE
+spy_whois_notice.c   - Spy on local clients who WHOIS you.
+spy_whois_notice_global.c - Spy on remote clients who WHOIS you.
+
+Note: if you have both spy_stats_notice.c and spy_stats_p_notice.c loaded
+you will get two messages.
+
+Snomask Modules
+---------------
+
+sno_farconnect.c  - Remote client connect/exit notices (snomask +F)
+sno_globalkline.c - Global K/D/X-line activation notices
+sno_globaloper.c  - Global oper-up notices
diff --git a/extensions/createauthonly.c b/extensions/createauthonly.c
new file mode 100644 (file)
index 0000000..4f7477a
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * This module restricts channel creation to authenticated users
+ * only. This module could be useful for running private chat
+ * systems, or if a network gets droneflood problems. It will
+ * return ERR_NEEDREGGEDNICK on failure.
+ *    -- nenolod
+ *
+ * $Id: createauthonly.c 833 2006-02-15 00:27:59Z jilles $
+ */
+
+#include "stdinc.h"
+#include "modules.h"
+#include "client.h"
+#include "hook.h"
+#include "ircd.h"
+#include "send.h"
+#include "s_conf.h"
+#include "snomask.h"
+#include "numeric.h"
+
+static void h_can_create_channel_authenticated(hook_data_client_approval *);
+
+mapi_hfn_list_av1 restrict_hfnlist[] = {
+       { "can_create_channel", (hookfn) h_can_create_channel_authenticated },
+       { NULL, NULL }
+};
+
+DECLARE_MODULE_AV1(createauthonly, NULL, NULL, NULL, NULL, restrict_hfnlist, "$Revision: 833 $");
+
+static void
+h_can_create_channel_authenticated(hook_data_client_approval *data)
+{
+       struct Client *source_p = data->client;
+
+       if (*source_p->user->suser == '\0')
+               data->approved = ERR_NEEDREGGEDNICK;
+}
diff --git a/extensions/example_module.c b/extensions/example_module.c
new file mode 100644 (file)
index 0000000..32e1509
--- /dev/null
@@ -0,0 +1,280 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, doc/example_module.c
+ *   Copyright (C) 2001 Hybrid Development 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 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: example_module.c 494 2006-01-15 16:08:28Z jilles $
+ */
+
+/* List of ircd includes from ../include/ */
+#include "stdinc.h"
+#include "modules.h"
+#include "hook.h"
+#include "client.h"
+#include "ircd.h"
+#include "send.h"
+
+/* Declare the void's initially up here, as modules dont have an
+ * include file, we will normally have client_p, source_p, parc
+ * and parv[] where:
+ *
+ * client_p == client issuing command
+ * source_p == where the command came from
+ * parc     == the number of parameters
+ * parv     == an array of the parameters
+ */
+
+static int munreg_test(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
+static int mclient_test(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
+static int mserver_test(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
+static int mrclient_test(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
+static int moper_test(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
+
+/* Show the commands this module can handle in a msgtab
+ * and give the msgtab a name, here its test_msgtab
+ */
+
+struct Message test_msgtab = {
+  "TEST",               /* the /COMMAND you want */
+  0,                    /* SET TO ZERO -- number of times command used by clients */
+  0,                    /* SET TO ZERO -- number of times command used by clients */
+  0,                    /* SET TO ZERO -- number of times command used by clients */
+  MFLG_SLOW,            /* ALWAYS SET TO MFLG_SLOW */
+
+  /* the functions to call for each handler.  If not using the generic
+   * handlers, the first param is the function to call, the second is the
+   * required number of parameters.  NOTE: If you specify a min para of 2,
+   * then parv[1] must *also* be non-empty.
+   */
+  {
+    {munreg_test, 0},   /* function call for unregistered clients, 0 parms required */
+    {mclient_test, 0},  /* function call for local clients, 0 parms required */
+    {mrclient_test, 0}, /* function call for remote clients, 0 parms required */
+    {mserver_test, 0},  /* function call for servers, 0 parms required */
+    mg_ignore,          /* function call for ENCAP, unused in this test */
+    {moper_test, 0}     /* function call for operators, 0 parms required */
+  }
+};
+/*
+ * There are also some macros for the above function calls and parameter counts.
+ * Here's a list:
+ *
+ * mg_ignore:       ignore the command when it comes from certain types
+ * mg_not_oper:     tell the client it requires being an operator
+ * mg_reg:          prevent the client using this if registered
+ * mg_unreg:        prevent the client using this if unregistered
+ *
+ * These macros assume a parameter count of zero; you do not set it.
+ * For further details, see include/msg.h
+ */
+
+
+/* The mapi_clist_av1 indicates which commands (struct Message)
+ * should be loaded from the module. The list should be terminated
+ * by a NULL.
+ */
+mapi_clist_av1 test_clist[] = { &test_msgtab, NULL };
+
+/* The mapi_hlist_av1 indicates which hook functions we need to be able to
+ * call.  We need to declare an integer, then add the name of the hook
+ * function to call and a pointer to this integer.  The list should be
+ * terminated with NULLs.
+ */
+int doing_example_hook;
+mapi_hlist_av1 test_hlist[] = { 
+       { "doing_example_hook", &doing_example_hook, },
+       { NULL, NULL }
+};
+
+/* The mapi_hfn_list_av1 declares the hook functions which other modules can
+ * call.  The first parameter is the name of the hook, the second is a void
+ * returning function, with arbitrary parameters casted to (hookfn).  This
+ * list must be terminated with NULLs.
+ */
+static void show_example_hook(void *unused);
+
+mapi_hfn_list_av1 test_hfnlist[] = {
+       { "doing_example_hook", (hookfn) show_example_hook },
+       { NULL, NULL }
+};
+
+/* Here we tell it what to do when the module is loaded */
+static int
+modinit(void)
+{
+       /* Nothing to do for the example module. */
+       /* The init function should return -1 on failure,
+          which will cause the module to be unloaded,
+          otherwise 0 to indicate success. */
+       return 0;
+}
+
+/* here we tell it what to do when the module is unloaded */
+static void
+moddeinit(void)
+{
+       /* Again, nothing to do. */
+}
+
+/* DECLARE_MODULE_AV1() actually declare the MAPI header. */
+DECLARE_MODULE_AV1(
+                         /* The first argument is the name */
+                         example,
+                         /* The second argument is the function to call on load */
+                         modinit,
+                         /* And the function to call on unload */
+                         moddeinit,
+                         /* Then the MAPI command list */
+                         test_clist,
+                         /* Next the hook list, if we have one. */
+                         test_hlist,
+                         /* Then the hook function list, if we have one */
+                         test_hfnlist,
+                         /* And finally the version number of this module. */
+                         "$Revision: 494 $");
+
+/* Any of the above arguments can be NULL to indicate they aren't used. */
+
+
+/*
+ * mr_test
+ *      parv[0] = sender prefix
+ *      parv[1] = parameter
+ */
+
+/* Here we have the functions themselves that we declared above,
+ * and the fairly normal C coding
+ */
+static int
+munreg_test(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       if(parc < 2)
+       {
+               sendto_one(source_p, ":%s NOTICE %s :You are unregistered and sent no parameters",
+                          me.name, source_p->name);
+       }
+       else
+       {
+               sendto_one(source_p, ":%s NOTICE %s :You are unregistered and sent parameter: %s",
+                          me.name, source_p->name, parv[1]);
+       }
+
+       /* illustration of how to call a hook function */
+       call_hook(doing_example_hook, NULL);
+
+       return 0;
+}
+
+/*
+ * mclient_test
+ *      parv[0] = sender prefix
+ *      parv[1] = parameter
+ */
+static int
+mclient_test(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       if(parc < 2)
+       {
+               sendto_one(source_p, ":%s NOTICE %s :You are a normal user, and sent no parameters",
+                          me.name, source_p->name);
+       }
+       else
+       {
+               sendto_one(source_p,
+                          ":%s NOTICE %s :You are a normal user, and send parameters: %s", me.name,
+                          source_p->name, parv[1]);
+       }
+
+       /* illustration of how to call a hook function */
+       call_hook(doing_example_hook, NULL);
+
+       return 0;
+}
+
+/*
+ * mrclient_test
+ *      parv[0] = sender prefix
+ *      parv[1] = parameter
+ */
+static int
+mrclient_test(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       if(parc < 2)
+       {
+               sendto_one(source_p,
+                          ":%s NOTICE %s :You are a remote client, and sent no parameters",
+                          me.name, source_p->name);
+       }
+       else
+       {
+               sendto_one(source_p,
+                          ":%s NOTICE %s :You are a remote client, and sent parameters: %s",
+                          me.name, source_p->name, parv[1]);
+       }
+       return 0;
+}
+
+/*
+ * mserver_test
+ *      parv[0] = sender prefix
+ *      parv[1] = parameter
+ */
+static int
+mserver_test(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       if(parc < 2)
+       {
+               sendto_one(source_p,
+                          ":%s NOTICE %s :You are a server, and sent no parameters",
+                          me.name, source_p->name);
+       }
+       else
+       {
+               sendto_one(source_p,
+                          ":%s NOTICE %s :You are a server, and sent parameters: %s",
+                          me.name, source_p->name, parv[1]);
+       }
+       return 0;
+}
+
+/*
+ * moper_test
+ *      parv[0] = sender prefix
+ *      parv[1] = parameter
+ */
+static int
+moper_test(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       if(parc < 2)
+       {
+               sendto_one(source_p, ":%s NOTICE %s :You are an operator, and sent no parameters",
+                          me.name, source_p->name);
+       }
+       else
+       {
+               sendto_one(source_p, ":%s NOTICE %s :You are an operator, and sent parameters: %s",
+                          me.name, source_p->name, parv[1]);
+       }
+       return 0;
+}
+
+static void
+show_example_hook(void *unused)
+{
+       sendto_realops_snomask(SNO_GENERAL, L_ALL, "Called example hook!");
+}
+
+/* END OF EXAMPLE MODULE */
diff --git a/extensions/extb_account.c b/extensions/extb_account.c
new file mode 100644 (file)
index 0000000..69dcda1
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Account extban type: bans all users with any/matching account
+ * -- jilles
+ *
+ * $Id: extb_account.c 1299 2006-05-11 15:43:03Z jilles $
+ */
+
+#include "stdinc.h"
+#include "modules.h"
+#include "client.h"
+#include "ircd.h"
+
+static int _modinit(void);
+static void _moddeinit(void);
+static int eb_account(const char *data, struct Client *client_p, struct Channel *chptr, long mode_type);
+
+DECLARE_MODULE_AV1(extb_account, _modinit, _moddeinit, NULL, NULL, NULL, "$Revision: 1299 $");
+
+static int
+_modinit(void)
+{
+       extban_table['a'] = eb_account;
+
+       return 0;
+}
+
+static void
+_moddeinit(void)
+{
+       extban_table['a'] = NULL;
+}
+
+static int eb_account(const char *data, struct Client *client_p,
+               struct Channel *chptr, long mode_type)
+{
+
+       (void)chptr;
+       /* $a alone matches any logged in user */
+       if (data == NULL)
+               return EmptyString(client_p->user->suser) ? EXTBAN_NOMATCH : EXTBAN_MATCH;
+       /* $a:MASK matches users logged in under matching account */
+       return match(data, client_p->user->suser) ? EXTBAN_MATCH : EXTBAN_NOMATCH;
+}
diff --git a/extensions/extb_canjoin.c b/extensions/extb_canjoin.c
new file mode 100644 (file)
index 0000000..a45c0d3
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Canjoin extban type: matches users who are or are not banned from a
+ * specified channel.
+ *    -- nenolod/jilles
+ *
+ * $Id: extb_canjoin.c 1841 2006-08-22 17:30:03Z jilles $
+ */
+
+#include "stdinc.h"
+#include "modules.h"
+#include "client.h"
+#include "channel.h"
+#include "hash.h"
+#include "ircd.h"
+
+static int _modinit(void);
+static void _moddeinit(void);
+static int eb_canjoin(const char *data, struct Client *client_p, struct Channel *chptr, long mode_type);
+
+DECLARE_MODULE_AV1(extb_canjoin, _modinit, _moddeinit, NULL, NULL, NULL, "$Revision: 1841 $");
+
+static int
+_modinit(void)
+{
+       extban_table['j'] = eb_canjoin;
+
+       return 0;
+}
+
+static void
+_moddeinit(void)
+{
+       extban_table['j'] = NULL;
+}
+
+static int eb_canjoin(const char *data, struct Client *client_p,
+               struct Channel *chptr, long mode_type)
+{
+       struct Channel *chptr2;
+       int ret;
+       static int recurse = 0;
+
+       (void)mode_type;
+       /* don't process a $j in a $j'ed list */
+       if (recurse)
+               return EXTBAN_INVALID;
+       if (data == NULL)
+               return EXTBAN_INVALID;
+       chptr2 = find_channel(data);
+       /* must exist, and no point doing this with the same channel */
+       if (chptr2 == NULL || chptr2 == chptr)
+               return EXTBAN_INVALID;
+       /* require consistent target */
+       if (chptr->chname[0] == '#' && data[0] == '&')
+               return EXTBAN_INVALID;
+       /* this allows getting some information about ban exceptions
+        * but +s/+p doesn't seem the right criterion */
+#if 0
+       /* privacy! don't allow +s/+p channels to influence another channel */
+       if (!PubChannel(chptr2))
+               return EXTBAN_INVALID;
+#endif
+       recurse = 1;
+       ret = is_banned(chptr2, client_p, NULL, NULL, NULL) == CHFL_BAN ? EXTBAN_MATCH : EXTBAN_NOMATCH;
+       recurse = 0;
+       return ret;
+}
diff --git a/extensions/extb_channel.c b/extensions/extb_channel.c
new file mode 100644 (file)
index 0000000..9bf09b3
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Channel extban type: matches users who are in a certain public channel
+ * -- jilles
+ *
+ * $Id: extb_channel.c 1723 2006-07-06 15:23:58Z jilles $
+ */
+
+#include "stdinc.h"
+#include "modules.h"
+#include "client.h"
+#include "channel.h"
+#include "hash.h"
+#include "ircd.h"
+
+static int _modinit(void);
+static void _moddeinit(void);
+static int eb_channel(const char *data, struct Client *client_p, struct Channel *chptr, long mode_type);
+
+DECLARE_MODULE_AV1(extb_channel, _modinit, _moddeinit, NULL, NULL, NULL, "$Revision: 1723 $");
+
+static int
+_modinit(void)
+{
+       extban_table['c'] = eb_channel;
+
+       return 0;
+}
+
+static void
+_moddeinit(void)
+{
+       extban_table['c'] = NULL;
+}
+
+static int eb_channel(const char *data, struct Client *client_p,
+               struct Channel *chptr, long mode_type)
+{
+       struct Channel *chptr2;
+
+       (void)chptr;
+       (void)mode_type;
+       if (data == NULL)
+               return EXTBAN_INVALID;
+       chptr2 = find_channel(data);
+       if (chptr2 == NULL)
+               return EXTBAN_INVALID;
+       /* require consistent target */
+       if (chptr->chname[0] == '#' && data[0] == '&')
+               return EXTBAN_INVALID;
+       /* privacy! don't allow +s/+p channels to influence another channel */
+       if (!PubChannel(chptr2))
+               return EXTBAN_INVALID;
+       return IsMember(client_p, chptr2) ? EXTBAN_MATCH : EXTBAN_NOMATCH;
+}
diff --git a/extensions/extb_extgecos.c b/extensions/extb_extgecos.c
new file mode 100644 (file)
index 0000000..b4023cb
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Extended extban type: bans all users with matching nick!user@host#gecos.
+ * Requested by Lockwood.
+ *  - nenolod
+ *
+ * $Id: extb_realname.c 1339 2006-05-17 00:45:40Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "modules.h"
+#include "client.h"
+#include "ircd.h"
+
+static int _modinit(void);
+static void _moddeinit(void);
+static int eb_extended(const char *data, struct Client *client_p, struct Channel *chptr, long mode_type);
+
+DECLARE_MODULE_AV1(extb_extended, _modinit, _moddeinit, NULL, NULL, NULL, "$Revision: 1339 $");
+
+static int
+_modinit(void)
+{
+       extban_table['x'] = eb_extended;
+
+       return 0;
+}
+
+static void
+_moddeinit(void)
+{
+       extban_table['x'] = NULL;
+}
+
+static int eb_extended(const char *data, struct Client *client_p,
+               struct Channel *chptr, long mode_type)
+{
+       char buf[BUFSIZE];
+       int ret;
+
+       (void)chptr;
+
+       if (data == NULL)
+               return EXTBAN_INVALID;
+
+       ircsnprintf(buf, BUFSIZE, "%s!%s@%s#%s",
+               client_p->name, client_p->username, client_p->host, client_p->info);
+
+       ret = match(data, buf) ? EXTBAN_MATCH : EXTBAN_NOMATCH;
+
+       if (ret == EXTBAN_NOMATCH && IsDynSpoof(client_p))
+       {
+               ircsnprintf(buf, BUFSIZE, "%s!%s@%s#%s",
+                       client_p->name, client_p->username, client_p->orighost, client_p->info);
+
+               ret = match(data, buf) ? EXTBAN_MATCH : EXTBAN_NOMATCH;
+       }
+
+       return ret;
+}
diff --git a/extensions/extb_oper.c b/extensions/extb_oper.c
new file mode 100644 (file)
index 0000000..e34d022
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Oper extban type: matches opers
+ * -- jilles
+ *
+ * $Id: extb_oper.c 1299 2006-05-11 15:43:03Z jilles $
+ */
+
+#include "stdinc.h"
+#include "modules.h"
+#include "client.h"
+#include "ircd.h"
+
+static int _modinit(void);
+static void _moddeinit(void);
+static int eb_oper(const char *data, struct Client *client_p, struct Channel *chptr, long mode_type);
+
+DECLARE_MODULE_AV1(extb_oper, _modinit, _moddeinit, NULL, NULL, NULL, "$Revision: 1299 $");
+
+static int
+_modinit(void)
+{
+       extban_table['o'] = eb_oper;
+
+       return 0;
+}
+
+static void
+_moddeinit(void)
+{
+       extban_table['o'] = NULL;
+}
+
+static int eb_oper(const char *data, struct Client *client_p,
+               struct Channel *chptr, long mode_type)
+{
+
+       (void)chptr;
+       (void)data;
+       (void)mode_type;
+       /* perhaps use data somehow? (opernick/flags?) */
+       return IsOper(client_p) ? EXTBAN_MATCH : EXTBAN_NOMATCH;
+}
diff --git a/extensions/extb_realname.c b/extensions/extb_realname.c
new file mode 100644 (file)
index 0000000..9d22109
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Realname extban type: bans all users with matching gecos
+ * -- jilles
+ *
+ * $Id: extb_realname.c 1299 2006-05-11 15:43:03Z jilles $
+ */
+
+#include "stdinc.h"
+#include "modules.h"
+#include "client.h"
+#include "ircd.h"
+
+static int _modinit(void);
+static void _moddeinit(void);
+static int eb_realname(const char *data, struct Client *client_p, struct Channel *chptr, long mode_type);
+
+DECLARE_MODULE_AV1(extb_realname, _modinit, _moddeinit, NULL, NULL, NULL, "$Revision: 1299 $");
+
+static int
+_modinit(void)
+{
+       extban_table['r'] = eb_realname;
+
+       return 0;
+}
+
+static void
+_moddeinit(void)
+{
+       extban_table['r'] = NULL;
+}
+
+static int eb_realname(const char *data, struct Client *client_p,
+               struct Channel *chptr, long mode_type)
+{
+
+       (void)chptr;
+       /* This type is not safe for exceptions */
+       if (mode_type == CHFL_EXCEPTION || mode_type == CHFL_INVEX)
+               return EXTBAN_INVALID;
+       if (data == NULL)
+               return EXTBAN_INVALID;
+       return match(data, client_p->info) ? EXTBAN_MATCH : EXTBAN_NOMATCH;
+}
diff --git a/extensions/extb_server.c b/extensions/extb_server.c
new file mode 100644 (file)
index 0000000..b42f41e
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Server name extban type: bans all users using a certain server
+ * -- jilles
+ *
+ * $Id: extb_server.c 1299 2006-05-11 15:43:03Z jilles $
+ */
+
+#include "stdinc.h"
+#include "modules.h"
+#include "client.h"
+#include "ircd.h"
+
+static int _modinit(void);
+static void _moddeinit(void);
+static int eb_server(const char *data, struct Client *client_p, struct Channel *chptr, long mode_type);
+
+DECLARE_MODULE_AV1(extb_server, _modinit, _moddeinit, NULL, NULL, NULL, "$Revision: 1299 $");
+
+static int
+_modinit(void)
+{
+       extban_table['s'] = eb_server;
+
+       return 0;
+}
+
+static void
+_moddeinit(void)
+{
+       extban_table['s'] = NULL;
+}
+
+static int eb_server(const char *data, struct Client *client_p,
+               struct Channel *chptr, long mode_type)
+{
+
+       (void)chptr;
+       /* This type is not safe for exceptions */
+       if (mode_type == CHFL_EXCEPTION || mode_type == CHFL_INVEX)
+               return EXTBAN_INVALID;
+       if (data == NULL)
+               return EXTBAN_INVALID;
+       return match(data, me.name) ? EXTBAN_MATCH : EXTBAN_NOMATCH;
+}
diff --git a/extensions/hurt.c b/extensions/hurt.c
new file mode 100644 (file)
index 0000000..0708fab
--- /dev/null
@@ -0,0 +1,669 @@
+/*
+ * charybdis: an advanced Internet Relay Chat Daemon(ircd).
+ *
+ * Copyright (C) 2006 charybdis development team
+ * All rights reserved
+ *
+ * $Id: hurt.c 1905 2006-08-29 14:51:31Z jilles $
+ */
+#include "stdinc.h"
+#include "modules.h"
+#include "hook.h"
+#include "client.h"
+#include "ircd.h"
+#include "send.h"
+#include "numeric.h"
+#include "hostmask.h"
+#include "event.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "hash.h"
+
+/* {{{ Structures */
+#define HURT_CUTOFF             (10)            /* protocol messages. */
+#define HURT_DEFAULT_EXPIRE     (7 * 24 * 60)   /* minutes. */
+#define HURT_EXIT_REASON        "Hurt: Failed to identify to services"
+
+enum {
+        HEAL_NICK = 0,
+        HEAL_IP
+};
+
+typedef struct _hurt_state {
+        time_t start_time;
+        uint32_t n_hurts;
+        dlink_list hurt_clients;
+        uint16_t cutoff;
+        time_t default_expire;
+        const char *exit_reason;
+} hurt_state_t;
+
+typedef struct _hurt {
+        const char *ip;
+        struct sockaddr *saddr;
+        int saddr_bits;
+        const char *reason;
+        time_t expire;
+} hurt_t;
+/* }}} */
+
+/* {{{ Prototypes */
+static int mo_hurt(struct Client *, struct Client *, int, const char **);
+static int me_hurt(struct Client *, struct Client *, int, const char **);
+static int mo_heal(struct Client *, struct Client *, int, const char **);
+static int me_heal(struct Client *, struct Client *, int, const char **);
+
+static int modinit(void);
+static void modfini(void);
+
+static void client_exit_hook(hook_data_client_exit *);
+static void new_local_user_hook(struct Client *);
+static void doing_stats_hook(hook_data_int *hdata);
+
+static void hurt_check_event(void *);
+static void hurt_expire_event(void *);
+
+static hurt_t *hurt_new(time_t, const char *, const char *);
+static void hurt_add(hurt_t *);
+static void hurt_propagate(struct Client *, struct Client *, hurt_t *);
+static hurt_t *hurt_find(const char *ip);
+static hurt_t *hurt_find_exact(const char *ip);
+static void hurt_remove(const char *ip);
+static void hurt_destroy(void *hurt);
+
+static int heal_nick(struct Client *, struct Client *);
+
+static int nick_is_valid(const char *);
+/* }}} */
+
+/* {{{ State containers */
+
+dlink_list hurt_confs = { NULL, NULL, 0 };
+
+/* }}} */
+
+/* {{{ Messages */
+struct Message hurt_msgtab = {
+       "HURT", 0, 0, 0, MFLG_SLOW, {
+               mg_ignore, mg_ignore, mg_ignore,
+               mg_ignore, {me_hurt, 0}, {mo_hurt, 3}
+       }
+};
+
+struct Message heal_msgtab = {
+       "HEAL", 0, 0, 0, MFLG_SLOW, {
+               mg_ignore, mg_ignore, mg_ignore,
+               mg_ignore, {me_heal, 0}, {mo_heal, 2}
+       }
+};
+/* }}} */
+
+/* {{{ Misc module stuff */
+mapi_hfn_list_av1 hurt_hfnlist[] = {
+       {"client_exit",         (hookfn) client_exit_hook},
+       {"new_local_user",      (hookfn) new_local_user_hook},
+       {"doing_stats",         (hookfn) doing_stats_hook},
+       {NULL,                  NULL},
+};
+
+mapi_clist_av1 hurt_clist[] = { &hurt_msgtab, &heal_msgtab, NULL };
+
+DECLARE_MODULE_AV1(
+       hurt,
+       modinit,
+       modfini,
+       hurt_clist,
+       NULL,
+       hurt_hfnlist,
+       "$Revision: 1905 $"
+);
+/* }}} */
+
+hurt_state_t hurt_state = {
+       .cutoff = HURT_CUTOFF,
+       .default_expire = HURT_DEFAULT_EXPIRE,
+       .exit_reason = HURT_EXIT_REASON,
+};
+
+/*
+ * Module constructor/destructor.
+ */
+
+/* {{{ static int modinit() */
+static int
+modinit(void)
+{
+       /* set-up hurt_state. */
+       hurt_state.start_time = CurrentTime;
+
+       /* add our event handlers. */
+       eventAdd("hurt_expire", hurt_expire_event, NULL, 60);
+       eventAdd("hurt_check", hurt_check_event, NULL, 5);
+
+       return 0;
+}
+/* }}} */
+
+/* {{{ static void modfini() */
+static void
+modfini(void)
+{
+       dlink_node      *ptr, *next_ptr;
+
+       /* and delete our events. */
+       eventDelete(hurt_expire_event, NULL);
+       eventDelete(hurt_check_event, NULL);
+
+       DLINK_FOREACH_SAFE (ptr, next_ptr, hurt_state.hurt_clients.head)
+       {
+               dlinkDestroy(ptr, &hurt_state.hurt_clients);
+       }
+}
+/* }}} */
+
+/*
+ * Message handlers.
+ */
+
+/* {{{ static int mo_hurt()
+ *
+ * HURT [<expire>] <ip> <reason>
+ * 
+ * parv[1] - expire or ip
+ * parv[2] - ip or reason
+ * parv[3] - reason or NULL
+ */
+static int
+mo_hurt(struct Client *client_p, struct Client *source_p,
+               int parc, const char **parv)
+{
+       const char                      *ip, *expire, *reason;
+       int                             expire_time;
+       hurt_t                          *hurt;
+       struct Client                   *target_p;
+
+       if (!IsOperK(source_p)) {
+               sendto_one(source_p, form_str(ERR_NOPRIVS), me.name,
+                               source_p->name, "kline");
+               return 0;
+       }
+
+       if (parc == 3)
+               expire = NULL, ip = parv[1], reason = parv[2];
+       else
+               expire = parv[1], ip = parv[2], reason = parv[3];
+
+       if (!expire)
+               expire_time = HURT_DEFAULT_EXPIRE;
+       if (expire && (expire_time = valid_temp_time(expire)) < 1) {
+               sendto_one(source_p,
+                               ":%s NOTICE %s :Permanent HURTs are not supported",
+                               me.name, source_p->name);
+               return 0;
+       }
+       if (EmptyString(reason)) {
+               sendto_one(source_p,
+                               ":%s NOTICE %s :Empty HURT reasons are bad for business",
+                               me.name, source_p->name);
+               return 0;
+       }
+
+       /* Is this a client? */
+       if (strchr(ip, '.') == NULL && strchr(ip, ':') == NULL)
+       {
+               target_p = find_named_person(ip);
+               if (target_p == NULL)
+               {
+                       sendto_one_numeric(source_p, ERR_NOSUCHNICK,
+                                          form_str(ERR_NOSUCHNICK), ip);
+                       return 0;
+               }
+               ip = target_p->orighost;
+       }
+       else
+       {
+               if (!strncmp(ip, "*@", 2))
+                       ip += 2;
+               if (strchr(ip, '!') || strchr(ip, '@'))
+               {
+                       sendto_one_notice(source_p, ":Invalid HURT mask [%s]",
+                                       ip);
+                       return 0;
+               }
+       }
+
+       if (hurt_find(ip) != NULL) {
+               sendto_one(source_p,
+                               ":%s NOTICE %s :[%s] already HURT",
+                               me.name, source_p->name, ip);
+               return 0;
+       }
+
+       /*
+        * okay, we've got this far, now it's time to add the the HURT locally
+        * and propagate it to other servers on the network.
+        */
+       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                       "%s added HURT on [%s] for %ld minutes with reason [%s]",
+                       get_oper_name(source_p), ip, (long) expire_time / 60, reason);
+
+       hurt = hurt_new(expire_time, ip, reason);
+       hurt_add(hurt);
+       hurt_propagate(NULL, source_p, hurt);
+
+       return 0;
+}
+/* }}} */
+
+/* {{{ static int me_hurt()
+ *
+ * [ENCAP mask] HURT <target> <expire> <ip> <reason>
+ *
+ * parv[1] - expire
+ * parv[2] - ip
+ * parv[3] - reason
+ */
+static int
+me_hurt(struct Client *client_p, struct Client *source_p,
+               int parc, const char **parv)
+{
+       time_t                          expire_time;
+       hurt_t                          *hurt;
+
+       /*
+        * right... if we don't get enough arguments, or if we get any invalid
+        * arguments, just ignore this request - shit happens, and it's not worth
+        * dropping a server over.
+        */
+       if (parc < 4 || !IsPerson(source_p))
+               return 0;
+       if ((expire_time = atoi(parv[1])) < 1)
+               return 0;
+       if (hurt_find(parv[2]) != NULL)
+               return 0;
+       if (EmptyString(parv[3]))
+               return 0;
+
+       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                       "%s added HURT on [%s] for %ld minutes with reason [%s]",
+                       get_oper_name(source_p), parv[2], (long) expire_time / 60, parv[3]);
+       hurt = hurt_new(expire_time, parv[2], parv[3]);
+       hurt_add(hurt);
+
+       return 0;
+}
+/* }}} */
+
+/* {{{ static int mo_heal()
+ *
+ * HURT <nick>|<ip>
+ *
+ * parv[1] - nick or ip
+ */
+static int
+mo_heal(struct Client *client_p, struct Client *source_p,
+               int parc, const char **parv)
+{
+       struct Client *target_p;
+
+       if (!IsOperUnkline(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS),
+                               me.name, source_p->name, "unkline");
+               return 0;
+       }
+
+       if (nick_is_valid(parv[1]))
+       {
+               target_p = find_named_person(parv[1]);
+               if (target_p == NULL)
+               {
+                       sendto_one_numeric(source_p, ERR_NOSUCHNICK,
+                                       form_str(ERR_NOSUCHNICK), parv[1]);
+                       return 0;
+               }
+               if (MyConnect(target_p))
+                       heal_nick(source_p, target_p);
+               else
+                       sendto_one(target_p, ":%s ENCAP %s HEAL %s",
+                                       get_id(source_p, target_p),
+                                       target_p->servptr->name,
+                                       get_id(target_p, target_p));
+       }
+       else if (strchr(parv[1], '.'))
+       {
+               if (hurt_find_exact(parv[1]) == NULL)
+               {
+                       sendto_one(source_p, ":%s NOTICE %s :Mask [%s] is not HURT",
+                                       me.name, source_p->name, parv[1]);
+                       return 0;
+               }
+               hurt_remove(parv[1]);
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s removed HURT on %s",
+                               get_oper_name(source_p), parv[1]);
+               sendto_server(NULL, NULL, NOCAPS, NOCAPS, ":%s ENCAP * HEAL %s",
+                       source_p->name, parv[1]);
+       }
+       else
+       {
+               sendto_one(source_p,
+                               ":%s NOTICE %s :[%s] is not a valid IP address/nick",
+                               me.name, source_p->name, parv[1]);
+               return 0;
+       }
+
+       return 0;
+}
+/* }}} */
+
+static int
+me_heal(struct Client *client_p, struct Client *source_p,
+               int parc, const char **parv)
+{
+       struct Client *target_p;
+
+       /* as noted in me_hurt(), if we don't get sufficient arguments...
+        * *poof*, it's dropped...
+        */
+       if (parc < 2)
+               return 0;
+
+       if (nick_is_valid(parv[1]))
+       {
+               target_p = find_person(parv[1]);
+               if (target_p != NULL && MyConnect(target_p))
+                       heal_nick(source_p, target_p);
+       }
+       else if (strchr(parv[1], '.'))  /* host or mask to remove ban for */
+       {
+               if (hurt_find_exact(parv[1]) == NULL)
+                       return 0;
+
+               hurt_remove(parv[1]);
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s removed HURT on %s",
+                               get_oper_name(source_p), parv[1]);
+       }
+       else
+               return 0;
+
+       return 0;
+}
+
+/*
+ * Event handlers.
+ */
+
+/* {{{ static void hurt_check_event() */
+static void
+hurt_check_event(void *arg)
+{
+       dlink_node      *ptr, *next_ptr;
+       struct Client   *client_p;
+
+       DLINK_FOREACH_SAFE (ptr, next_ptr, hurt_state.hurt_clients.head) {
+               client_p = ptr->data;
+               if (!EmptyString(client_p->user->suser))
+               {
+                       dlinkDestroy(ptr, &hurt_state.hurt_clients);
+                       sendto_one_notice(client_p, ":HURT restriction removed for this session");
+                       USED_TARGETS(client_p) = 0;
+                       client_p->localClient->target_last = CurrentTime;               /* don't ask --nenolod */
+               }
+               else if (client_p->localClient->receiveM > hurt_state.cutoff)
+                       exit_client(NULL, client_p, &me, hurt_state.exit_reason);
+       }
+}
+/* }}} */
+
+/* {{{ static void hurt_expire_event() */
+static void
+hurt_expire_event(void *unused)
+{
+       dlink_node      *ptr, *next_ptr;
+       hurt_t          *hurt;
+
+       DLINK_FOREACH_SAFE (ptr, next_ptr, hurt_confs.head)
+       {
+               hurt = (hurt_t *) ptr->data;
+
+               if (hurt->expire <= CurrentTime)
+               {
+                       dlinkFindDestroy(hurt, &hurt_confs);
+                       hurt_destroy(hurt);
+               }
+       }
+}
+/* }}} */
+
+/*
+ * Hook functions.
+ */
+
+/* {{{ static void client_exit_hook() */
+static void
+client_exit_hook(hook_data_client_exit *data)
+{
+       s_assert(data != NULL);
+       s_assert(data->target != NULL);
+
+       dlinkFindDestroy(data->target, &hurt_state.hurt_clients);
+}
+/* }}} */
+
+/* {{{ static void new_local_user_hook() */
+static void
+new_local_user_hook(struct Client *source_p)
+{
+       if (IsAnyDead(source_p) || !EmptyString(source_p->user->suser) ||
+                       IsExemptKline(source_p))
+               return;
+
+       if (hurt_find(source_p->sockhost) || hurt_find(source_p->orighost))
+       {
+               USED_TARGETS(source_p) = 10;
+               source_p->localClient->target_last = CurrentTime + 600;         /* don't ask --nenolod */
+               SetTGChange(source_p);
+               dlinkAddAlloc(source_p, &hurt_state.hurt_clients);
+               sendto_one_notice(source_p, ":You are hurt. Please identify to services immediately, or use /stats p for assistance.");
+       }       
+}
+/* }}} */
+
+/* {{{ static void doing_stats_hook() */
+static void
+doing_stats_hook(hook_data_int *hdata)
+{
+       dlink_node      *ptr;
+       hurt_t          *hurt;
+       struct Client   *source_p;
+
+       s_assert(hdata);
+       s_assert(hdata->client);
+
+       source_p = hdata->client;
+       if(hdata->arg2 != (int) 's')
+               return;
+       if((ConfigFileEntry.stats_k_oper_only == 2) && !IsOper(source_p))
+               return;
+       if ((ConfigFileEntry.stats_k_oper_only == 1) && !IsOper(source_p))
+       {
+               hurt = hurt_find(source_p->sockhost);
+               if (hurt != NULL)
+               {
+                       sendto_one_numeric(source_p, RPL_STATSKLINE,
+                                       form_str(RPL_STATSKLINE), 's',
+                                       "*", hurt->ip, hurt->reason, "", "");
+                       return;
+               }
+
+               hurt = hurt_find(source_p->orighost);
+               if (hurt != NULL)
+               {
+                       sendto_one_numeric(source_p, RPL_STATSKLINE,
+                                       form_str(RPL_STATSKLINE), 's',
+                                       "*", hurt->ip, hurt->reason, "", "");
+                       return;
+               }
+               return;
+       }
+
+       DLINK_FOREACH(ptr, hurt_confs.head)
+       {
+               hurt = (hurt_t *) ptr->data;
+               sendto_one_numeric(source_p, RPL_STATSKLINE,
+                               form_str(RPL_STATSKLINE), 's',
+                               "*", hurt->ip, hurt->reason, "", "");
+       }
+}
+/* }}} */
+
+/* {{{ static void hurt_propagate()
+ *
+ * client_p - specific server to propagate HURT to, or NULL to propagate to all
+ *      servers.
+ * source_p - source (oper who added the HURT)
+ * hurt   - HURT to be propagated
+ */
+static void
+hurt_propagate(struct Client *client_p, struct Client *source_p, hurt_t *hurt)
+{
+       if (client_p)
+               sendto_one(client_p,
+                               ":%s ENCAP %s HURT %ld %s :%s",
+                               source_p->name, client_p->name,
+                               (long)(hurt->expire - CurrentTime),
+                               hurt->ip, hurt->reason);
+       else
+               sendto_server(&me, NULL, NOCAPS, NOCAPS,
+                               ":%s ENCAP * HURT %ld %s :%s",
+                               source_p->name,
+                               (long)(hurt->expire - CurrentTime),
+                               hurt->ip, hurt->reason);
+}
+/* }}} */
+
+/* {{{ static hurt_t *hurt_new() */
+static hurt_t *
+hurt_new(time_t expire, const char *ip, const char *reason)
+{
+       hurt_t *hurt;
+
+       hurt = MyMalloc(sizeof(hurt_t));
+
+       DupString(hurt->ip, ip);
+       DupString(hurt->reason, reason);
+       hurt->expire = CurrentTime + expire;
+
+       return hurt;
+}
+/* }}} */
+
+/* {{{ static void hurt_destroy() */
+static void
+hurt_destroy(void *hurt)
+{
+       hurt_t *h;
+
+       if (!hurt)
+               return;
+
+       h = (hurt_t *) hurt;
+       MyFree((char *) h->ip);
+       MyFree((char *) h->reason);
+       MyFree(h);
+}
+/* }}} */
+
+static void
+hurt_add(hurt_t *hurt)
+{
+       dlinkAddAlloc(hurt, &hurt_confs);
+}
+
+static hurt_t *
+hurt_find_exact(const char *ip)
+{
+       dlink_node *ptr;
+       hurt_t *hurt;
+
+       DLINK_FOREACH(ptr, hurt_confs.head)
+       {
+               hurt = (hurt_t *) ptr->data;
+
+               if (!strcasecmp(ip, hurt->ip))
+                       return hurt;
+       }
+
+       return NULL;
+}
+
+static hurt_t *
+hurt_find(const char *ip)
+{
+       dlink_node *ptr;
+       hurt_t *hurt;
+
+       DLINK_FOREACH(ptr, hurt_confs.head)
+       {
+               hurt = (hurt_t *) ptr->data;
+
+               if (match(hurt->ip, ip))
+                       return hurt;
+       }
+
+       return NULL;
+}
+
+static void
+hurt_remove(const char *ip)
+{
+       hurt_t *hurt = hurt_find_exact(ip);
+
+       dlinkFindDestroy(hurt, &hurt_confs);
+       hurt_destroy(hurt);
+}
+
+/* {{{ static int heal_nick() */
+static int
+heal_nick(struct Client *source_p, struct Client *target_p)
+{
+       if (dlinkFindDestroy(target_p, &hurt_state.hurt_clients))
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s used HEAL on %s",
+                               get_oper_name(source_p), get_client_name(target_p, HIDE_IP));
+               sendto_one_notice(target_p, ":HURT restriction temporarily removed by operator");
+               sendto_one_notice(source_p, ":HURT restriction on %s temporarily removed", target_p->name);
+               USED_TARGETS(target_p) = 0;
+               target_p->localClient->target_last = CurrentTime;               /* don't ask --nenolod */
+               return 1;
+       }
+       else
+       {
+               sendto_one_notice(source_p, ":%s was not hurt", target_p->name);
+               return 0;
+       }
+}
+/* }}} */
+
+/*
+ * Anything else...
+ */
+
+/* {{{ static int nick_is_valid() */
+static int
+nick_is_valid(const char *nick)
+{
+       const char *s = nick;
+
+       for (; *s != '\0'; s++) {
+               if (!IsNickChar(*s))
+                       return 0;
+       }
+
+       return 1;
+}
+/* }}} */
+
+/*
+ * vim: ts=8 sw=8 noet fdm=marker tw=80
+ */
diff --git a/extensions/ip_cloaking.c b/extensions/ip_cloaking.c
new file mode 100644 (file)
index 0000000..f960d0a
--- /dev/null
@@ -0,0 +1,176 @@
+/* $Id: ip_cloaking.c 2805 2006-12-05 12:45:43Z jilles $ */
+
+#include "stdinc.h"
+#include "modules.h"
+#include "hook.h"
+#include "client.h"
+#include "ircd.h"
+#include "send.h"
+#include "s_conf.h"
+#include "s_user.h"
+#include "s_serv.h"
+#include "tools.h"
+#include "numeric.h"
+
+/* if you're modifying this module, you'll probably to change this */
+#define KEY 0x13748cfa
+
+static int
+_modinit(void)
+{
+       /* add the usermode to the available slot */
+       user_modes['h'] = find_umode_slot();
+       construct_umodebuf();
+
+       return 0;
+}
+
+static void
+_moddeinit(void)
+{
+       /* disable the umode and remove it from the available list */
+       user_modes['h'] = 0;
+       construct_umodebuf();
+}
+
+static void check_umode_change(void *data);
+static void check_new_user(void *data);
+mapi_hfn_list_av1 ip_cloaking_hfnlist[] = {
+       { "umode_changed", (hookfn) check_umode_change },
+       { "new_local_user", (hookfn) check_new_user },
+       { NULL, NULL }
+};
+
+DECLARE_MODULE_AV1(ip_cloaking, _modinit, _moddeinit, NULL, NULL,
+                       ip_cloaking_hfnlist, "$Revision: 2805 $");
+
+static void
+distribute_hostchange(struct Client *client)
+{
+       if (irccmp(client->host, client->orighost))
+               sendto_one_numeric(client, RPL_HOSTHIDDEN, "%s :is now your hidden host",
+                       client->host);
+       else
+               sendto_one_numeric(client, RPL_HOSTHIDDEN, "%s :hostname reset",
+                       client->host);
+
+       sendto_server(NULL, NULL,
+               CAP_EUID | CAP_TS6, NOCAPS, ":%s CHGHOST %s :%s",
+               use_id(&me), use_id(client), client->host);
+       sendto_server(NULL, NULL,
+               CAP_TS6, CAP_EUID, ":%s ENCAP * CHGHOST %s :%s",
+               use_id(&me), use_id(client), client->host);
+       sendto_server(NULL, NULL,
+               NOCAPS, CAP_TS6, ":%s ENCAP * CHGHOST %s :%s",
+               me.name, client->name, client->host);
+       if (irccmp(client->host, client->orighost))
+               SetDynSpoof(client);
+       else
+               ClearDynSpoof(client);
+}
+
+static void
+do_host_cloak(const char *inbuf, char *outbuf, int ipmask)
+{
+       int cyc;
+       unsigned int hosthash = 1, hosthash2 = 1;
+       unsigned int maxcycle = strlen(inbuf);  
+       int len1;
+       const char *rest, *next;
+
+       for (cyc = 0; cyc < maxcycle - 2; cyc += 2)
+               hosthash *= (unsigned int) inbuf[cyc];
+
+       /* safety: decrement ourselves two steps back */
+       for (cyc = maxcycle - 1; cyc >= 1; cyc -= 2)
+               hosthash2 *= (unsigned int) inbuf[cyc];
+
+       /* lets do some bitshifting -- this pretty much destroys the IP
+        * sequence, while still providing a checksum. exactly what
+        * we're shooting for. --nenolod
+        */
+       hosthash += (hosthash2 / KEY);
+       hosthash2 += (hosthash / KEY);
+
+       if (ipmask == 0)
+       {
+               ircsnprintf(outbuf, HOSTLEN, "%s-%X%X",
+                       ServerInfo.network_name, hosthash2, hosthash);
+               len1 = strlen(outbuf);
+               rest = strchr(inbuf, '.');
+               if (rest == NULL)
+                       rest = ".";
+               /* try to avoid truncation -- jilles */
+               while (len1 + strlen(rest) >= HOSTLEN && (next = strchr(rest + 1, '.')) != NULL)
+                       rest = next;
+               strlcat(outbuf, rest, HOSTLEN);
+       }
+       else
+               ircsnprintf(outbuf, HOSTLEN, "%X%X.%s",
+                       hosthash2, hosthash, ServerInfo.network_name);
+}
+
+static void
+check_umode_change(void *vdata)
+{
+       hook_data_umode_changed *data = (hook_data_umode_changed *)vdata;
+       struct Client *source_p = data->client;
+
+       if (!MyClient(source_p))
+               return;
+
+       /* didn't change +h umode, we don't need to do anything */
+       if (!((data->oldumodes ^ source_p->umodes) & user_modes['h']))
+               return;
+
+       if (source_p->umodes & user_modes['h'])
+       {
+               if (IsIPSpoof(source_p) || source_p->localClient->mangledhost == NULL || (IsDynSpoof(source_p) && strcmp(source_p->host, source_p->localClient->mangledhost)))
+               {
+                       source_p->umodes &= ~user_modes['h'];
+                       return;
+               }
+               if (strcmp(source_p->host, source_p->localClient->mangledhost))
+               {
+                       strlcpy(source_p->host, source_p->localClient->mangledhost, HOSTLEN);
+                       distribute_hostchange(source_p);
+               }
+               else /* not really nice, but we need to send this numeric here */
+                       sendto_one_numeric(source_p, RPL_HOSTHIDDEN, "%s :is now your hidden host",
+                               source_p->host);
+       }
+       else if (!(source_p->umodes & user_modes['h']))
+       {
+               if (source_p->localClient->mangledhost != NULL &&
+                               !strcmp(source_p->host, source_p->localClient->mangledhost))
+               {
+                       strlcpy(source_p->host, source_p->orighost, HOSTLEN);
+                       distribute_hostchange(source_p);
+               }
+       }
+}
+
+static void
+check_new_user(void *vdata)
+{
+       struct Client *source_p = (void *)vdata;
+
+       if (IsIPSpoof(source_p))
+       {
+               source_p->umodes &= ~user_modes['h'];
+               return;
+       }
+       source_p->localClient->mangledhost = MyMalloc(HOSTLEN);
+       if (!irccmp(source_p->orighost, source_p->sockhost))
+               do_host_cloak(source_p->orighost, source_p->localClient->mangledhost, 1);
+       else
+               do_host_cloak(source_p->orighost, source_p->localClient->mangledhost, 0);
+       if (IsDynSpoof(source_p))
+               source_p->umodes &= ~user_modes['h'];
+       if (source_p->umodes & user_modes['h'])
+       {
+               strlcpy(source_p->host, source_p->localClient->mangledhost, sizeof(source_p->host));
+               if (irccmp(source_p->host, source_p->orighost))
+                       SetDynSpoof(source_p);
+       }
+}
diff --git a/extensions/m_42.c b/extensions/m_42.c
new file mode 100644 (file)
index 0000000..1929478
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ *   Copyright (C) infinity-infinity God <God@Heaven>
+ *
+ *   Bob was here 
+ *   $Id: m_42.c 6 2005-09-10 01:02:21Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "modules.h"
+#include "client.h"
+#include "ircd.h"
+#include "send.h"
+
+static int mclient_42(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
+
+struct Message hgtg_msgtab = {
+  "42", 0, 0, 0, MFLG_SLOW,
+  { mg_ignore, {mclient_42, 0}, mg_ignore, mg_ignore, mg_ignore, {mclient_42, 0}
+  }
+};
+
+mapi_clist_av1 hgtg_clist[] = { &hgtg_msgtab, NULL };
+
+
+DECLARE_MODULE_AV1(42, NULL, NULL, hgtg_clist, NULL, NULL, "Revision 0.42");
+
+
+static int
+mclient_42(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       sendto_one(source_p, ":%s NOTICE %s :The Answer to Life, the Universe, and Everything.",
+                  me.name, source_p->name);
+       return 0;
+}
+
+
diff --git a/extensions/m_findforwards.c b/extensions/m_findforwards.c
new file mode 100644 (file)
index 0000000..488c610
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ *   IRC - Internet Relay Chat, contrib/m_findforwards.c
+ *   Copyright (C) 2002 Hybrid Development Team
+ *   Copyright (C) 2004 ircd-ratbox Development 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 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_findforwards.c 986 2006-03-08 00:10:46Z jilles $
+ */
+#include "stdinc.h"
+#include "tools.h"
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_user.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "packet.h"
+
+static int m_findforwards(struct Client *client_p, struct Client *source_p,
+                       int parc, const char *parv[]);
+
+struct Message findforwards_msgtab = {
+       "FINDFORWARDS", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_findforwards, 2}, mg_ignore, mg_ignore, mg_ignore, {m_findforwards, 2}}
+};
+
+mapi_clist_av1 findforwards_clist[] = { &findforwards_msgtab, NULL };
+
+DECLARE_MODULE_AV1(findforwards, NULL, NULL, findforwards_clist, NULL, NULL, "$Revision: 986 $");
+
+/*
+** mo_findforwards
+**      parv[0] = sender prefix
+**      parv[1] = channel
+*/
+static int
+m_findforwards(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       static time_t last_used = 0;
+       struct Channel *chptr;
+       struct membership *msptr;
+       dlink_node *ptr;
+       char buf[414];
+       char *p = buf, *end = buf + sizeof buf - 1;
+       *p = '\0';
+
+       /* Allow ircops to search for forwards to nonexistent channels */
+       if(!IsOper(source_p))
+       {
+               if((chptr = find_channel(parv[1])) == NULL || (msptr = find_channel_membership(chptr, source_p)) == NULL)
+               {
+                       sendto_one_numeric(source_p, ERR_NOTONCHANNEL,
+                                       form_str(ERR_NOTONCHANNEL), parv[1]);
+                       return 0;
+               }
+
+               if(!is_chanop(msptr))
+               {
+                       sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
+                                       me.name, source_p->name, parv[1]);
+                       return 0;
+               }
+
+               if((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
+               {
+                       sendto_one(source_p, form_str(RPL_LOAD2HI),
+                                       me.name, source_p->name, "FINDFORWARDS");
+                       return 0;
+               }
+               else
+                       last_used = CurrentTime;
+       }
+       
+       DLINK_FOREACH(ptr, global_channel_list.head)
+       {
+               chptr = ptr->data;
+               if(chptr->mode.forward && !irccmp(chptr->mode.forward, parv[1]))
+               {
+                       if(p + strlen(chptr->chname) >= end - 13)
+                       {
+                               strcpy(p, "<truncated> ");
+                               p += 12;
+                               break;
+                       }
+                       strcpy(p, chptr->chname);
+                       p += strlen(chptr->chname);
+                       *p++ = ' ';
+               }
+       }
+
+       if(buf[0])
+               *(--p) = '\0';
+
+       sendto_one_notice(source_p, ":Forwards for %s: %s", parv[1], buf);
+
+       return 0;
+}
diff --git a/extensions/m_identify.c b/extensions/m_identify.c
new file mode 100644 (file)
index 0000000..ece5952
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * m_identify.c: dalnet-style /identify that sends to nickserv or chanserv
+ *
+ * Copyright (C) 2006 Jilles Tjoelker
+ * Copyright (C) 2006 charybdis development team
+ *
+ * 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.The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: m_identify.c 2729 2006-11-09 23:52:06Z jilles $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "common.h"
+#include "ircd.h"
+#include "irc_string.h"
+#include "numeric.h"
+#include "s_conf.h"
+#include "s_log.h"
+#include "s_serv.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+
+#define SVS_chanserv_NICK "ChanServ"
+#define SVS_nickserv_NICK "NickServ"
+
+char *reconstruct_parv(int parc, const char *parv[]);
+
+static int m_identify(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
+
+struct Message identify_msgtab = {
+       "IDENTIFY", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_identify, 0}, mg_ignore, mg_ignore, mg_ignore, {m_identify, 0}}
+};
+
+mapi_clist_av1 identify_clist[] = {
+       &identify_msgtab,
+       NULL
+};
+
+DECLARE_MODULE_AV1(identify, NULL, NULL, identify_clist, NULL, NULL, "$Revision: 2729 $");
+
+char *reconstruct_parv(int parc, const char *parv[])
+{
+       static char tmpbuf[BUFSIZE]; int i;
+
+       strlcpy(tmpbuf, parv[0], BUFSIZE);
+       for (i = 1; i < parc; i++)
+       {
+               strlcat(tmpbuf, " ", BUFSIZE);
+               strlcat(tmpbuf, parv[i], BUFSIZE);
+       }
+       return tmpbuf;
+}
+
+static int m_identify(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       const char *nick;
+       struct Client *target_p;
+
+       if (parc < 2 || EmptyString(parv[1]))
+       {
+               sendto_one(source_p, form_str(ERR_NOTEXTTOSEND), me.name, source_p->name);
+               return 0;
+       }
+
+       nick = parv[1][0] == '#' ? SVS_chanserv_NICK : SVS_nickserv_NICK;
+       if ((target_p = find_named_person(nick)) && IsService(target_p))
+       {
+               sendto_one(target_p, ":%s PRIVMSG %s :IDENTIFY %s", get_id(source_p, target_p), get_id(target_p, target_p), reconstruct_parv(parc - 1, &parv[1]));
+       }
+       else
+       {
+               sendto_one_numeric(source_p, ERR_SERVICESDOWN, form_str(ERR_SERVICESDOWN), nick);
+       }
+       return 0;
+}
diff --git a/extensions/m_mkpasswd.c b/extensions/m_mkpasswd.c
new file mode 100644 (file)
index 0000000..0d54494
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ *  m_mkpasswd.c: Encrypts a password online, DES or MD5.
+ *
+ *  Copyright 2002 W. Campbell and the ircd-ratbox development team
+ *  Based on mkpasswd.c, originally by Nelson Minar (minar@reed.edu)
+ *
+ *  You can use this code in any way as long as these names remain.
+ *
+ *  $Id: m_mkpasswd.c 6 2005-09-10 01:02:21Z nenolod $
+ */
+
+/* List of ircd includes from ../include/ */
+#include "stdinc.h"
+#include "client.h"
+#include "common.h"            /* FALSE bleah */
+#include "ircd.h"
+#include "irc_string.h"
+#include "numeric.h"
+#include "patricia.h"
+#include "s_newconf.h"
+#include "s_conf.h"
+#include "s_log.h"
+#include "s_serv.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+
+#include <string.h>
+
+extern char *crypt();
+
+static int m_mkpasswd(struct Client *client_p, struct Client *source_p,
+                     int parc, const char *parv[]);
+static int mo_mkpasswd(struct Client *client_p, struct Client *source_p,
+                      int parc, const char *parv[]);
+static char *make_salt(void);
+static char *make_md5_salt(void);
+
+static char saltChars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
+
+
+struct Message mkpasswd_msgtab = {
+       "MKPASSWD", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_mkpasswd, 2}, mg_ignore, mg_ignore, mg_ignore, {mo_mkpasswd, 2}}
+};
+
+mapi_clist_av1 mkpasswd_clist[] = { &mkpasswd_msgtab, NULL };
+
+DECLARE_MODULE_AV1(mkpasswd, NULL, NULL, mkpasswd_clist, NULL, NULL, "$Revision: 6 $");
+
+
+static int
+m_mkpasswd(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       static time_t last_used = 0;
+       int is_md5 = 0;
+
+       if((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
+       {
+               /* safe enough to give this on a local connect only */
+               sendto_one(source_p, form_str(RPL_LOAD2HI), me.name, parv[0]);
+               return 0;
+       }
+       else
+       {
+               last_used = CurrentTime;
+       }
+
+       if(parc == 3)
+       {
+               if(!irccmp(parv[2], "MD5"))
+               {
+                       is_md5 = 1;
+               }
+               else if(!irccmp(parv[2], "DES"))
+               {
+                       /* Not really needed, but we may want to have a default encryption
+                        * setting somewhere down the road
+                        */
+                       is_md5 = 0;
+               }
+               else
+               {
+                       sendto_one(source_p,
+                                  ":%s NOTICE %s :MKPASSWD syntax error:  MKPASSWD pass [DES|MD5]",
+                                  me.name, parv[0]);
+                       return 0;
+               }
+       }
+
+       if(parc == 1)
+               sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "MKPASSWD");
+       else
+               sendto_one(source_p, ":%s NOTICE %s :Encryption for [%s]:  %s",
+                          me.name, parv[0], parv[1], crypt(parv[1],
+                                                           is_md5 ? make_md5_salt() :
+                                                           make_salt()));
+
+       return 0;
+}
+
+/*
+** mo_test
+**      parv[0] = sender prefix
+**      parv[1] = parameter
+*/
+static int
+mo_mkpasswd(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       int is_md5 = 0;
+
+       if(parc == 3)
+       {
+               if(!irccmp(parv[2], "MD5"))
+               {
+                       is_md5 = 1;
+               }
+               else if(!irccmp(parv[2], "DES"))
+               {
+                       /* Not really needed, but we may want to have a default encryption
+                        * setting somewhere down the road
+                        */
+                       is_md5 = 0;
+               }
+               else
+               {
+                       sendto_one(source_p,
+                                  ":%s NOTICE %s :MKPASSWD syntax error:  MKPASSWD pass [DES|MD5]",
+                                  me.name, parv[0]);
+                       return 0;
+               }
+       }
+
+       if(parc == 1)
+               sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "MKPASSWD");
+       else
+               sendto_one(source_p, ":%s NOTICE %s :Encryption for [%s]:  %s",
+                          me.name, parv[0], parv[1], crypt(parv[1],
+                                                           is_md5 ? make_md5_salt() :
+                                                           make_salt()));
+
+       return 0;
+}
+
+static char *
+make_salt(void)
+{
+       static char salt[3];
+       salt[0] = saltChars[random() % 64];
+       salt[1] = saltChars[random() % 64];
+       salt[2] = '\0';
+       return salt;
+}
+
+static char *
+make_md5_salt(void)
+{
+       static char salt[13];
+       int i;
+       salt[0] = '$';
+       salt[1] = '1';
+       salt[2] = '$';
+       for(i = 3; i < 11; i++)
+               salt[i] = saltChars[random() % 64];
+       salt[11] = '$';
+       salt[12] = '\0';
+       return salt;
+}
diff --git a/extensions/m_ojoin.c b/extensions/m_ojoin.c
new file mode 100644 (file)
index 0000000..0e401e3
--- /dev/null
@@ -0,0 +1,155 @@
+/*   contrib/m_ojoin.c
+ *   Copyright (C) 2002 Hybrid Development Team
+ *   Copyright (C) 2004 ircd-ratbox Development 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 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_ojoin.c 3121 2007-01-02 13:23:04Z jilles $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "patricia.h"
+#include "channel.h"
+#include "client.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_log.h"
+#include "s_serv.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "send.h"
+#include "whowas.h"
+#include "irc_string.h"
+#include "hash.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+
+
+static int mo_ojoin(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
+
+
+struct Message ojoin_msgtab = {
+       "OJOIN", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_ojoin, 2}}
+};
+
+mapi_clist_av1 ojoin_clist[] = { &ojoin_msgtab, NULL };
+
+DECLARE_MODULE_AV1(ojoin, NULL, NULL, ojoin_clist, NULL, NULL, "$Revision: 3121 $");
+
+/*
+** mo_ojoin
+**      parv[0] = sender prefix
+**      parv[1] = channel
+*/
+static int
+mo_ojoin(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Channel *chptr;
+       int move_me = 0;
+
+       /* admins only */
+       if(!IsOperAdmin(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "ojoin");
+               return 0;
+       }
+
+       if(*parv[1] == '@' || *parv[1] == '%' || *parv[1] == '+')
+       {
+               parv[1]++;
+               move_me = 1;
+       }
+
+       if((chptr = find_channel(parv[1])) == NULL)
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
+                                  form_str(ERR_NOSUCHCHANNEL), parv[1]);
+               return 0;
+       }
+
+       if(IsMember(source_p, chptr))
+       {
+               sendto_one(source_p, ":%s NOTICE %s :Please part %s before using OJOIN",
+                          me.name, source_p->name, parv[1]);
+               return 0;
+       }
+
+       if(move_me == 1)
+               parv[1]--;
+
+       sendto_wallops_flags(UMODE_WALLOP, &me,
+                            "OJOIN called for %s by %s!%s@%s",
+                            parv[1], source_p->name, source_p->username, source_p->host);
+       ilog(L_MAIN, "OJOIN called for %s by %s",
+            parv[1], get_oper_name(source_p));
+       /* only sends stuff for #channels remotely */
+       sendto_server(NULL, chptr, NOCAPS, NOCAPS,
+                       ":%s WALLOPS :OJOIN called for %s by %s!%s@%s",
+                       me.name, parv[1],
+                       source_p->name, source_p->username, source_p->host);
+
+       if(*parv[1] == '@')
+       {
+               add_user_to_channel(chptr, source_p, CHFL_CHANOP);
+               sendto_server(client_p, chptr, NOCAPS, NOCAPS,
+                             ":%s SJOIN %ld %s + :@%s",
+                             me.name, (long) chptr->channelts, chptr->chname, source_p->name);
+               sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s",
+                                    source_p->name,
+                                    source_p->username, source_p->host, chptr->chname);
+               sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +o %s",
+                                    me.name, chptr->chname, source_p->name);
+
+       }
+       else if(*parv[1] == '+')
+       {
+               add_user_to_channel(chptr, source_p, CHFL_VOICE);
+               sendto_server(client_p, chptr, NOCAPS, NOCAPS,
+                             ":%s SJOIN %ld %s + :+%s",
+                             me.name, (long) chptr->channelts, chptr->chname, source_p->name);
+               sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s",
+                                    source_p->name,
+                                    source_p->username, source_p->host, chptr->chname);
+               sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +v %s",
+                                    me.name, chptr->chname, source_p->name);
+       }
+       else
+       {
+               add_user_to_channel(chptr, source_p, CHFL_PEON);
+               sendto_server(client_p, chptr, NOCAPS, NOCAPS,
+                             ":%s SJOIN %ld %s + :%s",
+                             me.name, (long) chptr->channelts, chptr->chname, source_p->name);
+               sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s",
+                                    source_p->name,
+                                    source_p->username, source_p->host, chptr->chname);
+       }
+
+       /* send the topic... */
+       if(chptr->topic != NULL)
+       {
+               sendto_one(source_p, form_str(RPL_TOPIC), me.name,
+                          source_p->name, chptr->chname, chptr->topic);
+               sendto_one(source_p, form_str(RPL_TOPICWHOTIME), me.name,
+                          source_p->name, chptr->chname, chptr->topic_info, chptr->topic_time);
+       }
+
+       source_p->localClient->last_join_time = CurrentTime;
+       channel_member_names(chptr, source_p, 1);
+
+       return 0;
+}
diff --git a/extensions/m_okick.c b/extensions/m_okick.c
new file mode 100644 (file)
index 0000000..8fd7643
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_okick.c: Kicks a user from a channel with much prejudice.
+ *
+ *  Copyright (C) 2002 by the past and present ircd coders, and others.
+ *  Copyright (C) 2004 ircd-ratbox Development 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: m_okick.c 3117 2007-01-02 13:11:04Z jilles $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "channel.h"
+#include "client.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "msg.h"
+#include "modules.h"
+#include "parse.h"
+#include "hash.h"
+#include "packet.h"
+#include "s_conf.h"
+#include "s_serv.h"
+
+static int mo_okick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
+
+
+struct Message okick_msgtab = {
+       "OKICK", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_okick, 4}}
+};
+
+mapi_clist_av1 okick_clist[] = { &okick_msgtab, NULL };
+
+DECLARE_MODULE_AV1(okick, NULL, NULL, okick_clist, NULL, NULL, "$Revision: 3117 $");
+
+/*
+** m_okick
+**      parv[0] = sender prefix
+**      parv[1] = channel
+**      parv[2] = client to kick
+**      parv[3] = kick comment
+*/
+static int
+mo_okick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *who;
+       struct Client *target_p;
+       struct Channel *chptr;
+       struct membership *msptr;
+       int chasing = 0;
+       char *comment;
+       char *name;
+       char *p = NULL;
+       char *user;
+       static char buf[BUFSIZE];
+
+       if(*parv[2] == '\0')
+       {
+               sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "KICK");
+               return 0;
+       }
+
+       if(MyClient(source_p) && !IsFloodDone(source_p))
+               flood_endgrace(source_p);
+
+       comment = (EmptyString(LOCAL_COPY(parv[3]))) ? LOCAL_COPY(parv[2]) : LOCAL_COPY(parv[3]);
+       if(strlen(comment) > (size_t) TOPICLEN)
+               comment[TOPICLEN] = '\0';
+
+       *buf = '\0';
+       if((p = strchr(parv[1], ',')))
+               *p = '\0';
+
+       name = LOCAL_COPY(parv[1]);
+
+       chptr = find_channel(name);
+       if(!chptr)
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name);
+               return 0;
+       }
+
+
+       if((p = strchr(parv[2], ',')))
+               *p = '\0';
+       user = LOCAL_COPY(parv[2]);     // strtoken(&p2, parv[2], ","); 
+       if(!(who = find_chasing(source_p, user, &chasing)))
+       {
+               return 0;
+       }
+
+       if((target_p = find_client(user)) == NULL)
+       {
+               sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name, parv[0], user);
+               return 0;
+       }
+
+       if((msptr = find_channel_membership(chptr, target_p)) == NULL)
+       {
+               sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
+                          me.name, parv[0], parv[1], parv[2]);
+               return 0;
+       }
+
+       sendto_wallops_flags(UMODE_WALLOP, &me,
+                            "OKICK called for %s %s by %s!%s@%s",
+                            chptr->chname, target_p->name,
+                            source_p->name, source_p->username, source_p->host);
+       ilog(L_MAIN, "OKICK called for %s %s by %s",
+            chptr->chname, target_p->name,
+            get_oper_name(source_p));
+       /* only sends stuff for #channels remotely */
+       sendto_server(NULL, chptr, NOCAPS, NOCAPS,
+                       ":%s WALLOPS :OKICK called for %s %s by %s!%s@%s",
+                       me.name, chptr->chname, target_p->name,
+                       source_p->name, source_p->username, source_p->host);
+
+       sendto_channel_local(ALL_MEMBERS, chptr, ":%s KICK %s %s :%s",
+                            me.name, chptr->chname, who->name, comment);
+       sendto_server(&me, chptr, NOCAPS, NOCAPS,
+                     ":%s KICK %s %s :%s", me.name, chptr->chname, who->name, comment);
+       remove_user_from_channel(msptr);
+       return 0;
+}
diff --git a/extensions/m_olist.c b/extensions/m_olist.c
new file mode 100644 (file)
index 0000000..3893917
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_olist.c: List channels.  olist is an oper only command
+ *             that shows channels regardless of modes.  This
+ *             is kinda evil, and might be morally wrong, but
+ *             somebody will likely need it.
+ *
+ *  Copyright (C) 2002 by the past and present ircd coders, and others.
+ *  Copyright (C) 2004 ircd-ratbox Development 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: m_olist.c 6 2005-09-10 01:02:21Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "patricia.h"
+#include "channel.h"
+#include "client.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_log.h"
+#include "s_serv.h"
+#include "send.h"
+#include "whowas.h"
+#include "irc_string.h"
+#include "hash.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_newconf.h"
+#include "sprintf_irc.h"
+
+static int mo_olist(struct Client *, struct Client *, int parc, const char *parv[]);
+
+#ifndef STATIC_MODULES
+
+struct Message olist_msgtab = {
+       "OLIST", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_olist, 1}}
+};
+
+mapi_clist_av1 olist_clist[] = { &olist_msgtab, NULL };
+
+DECLARE_MODULE_AV1(okick, NULL, NULL, olist_clist, NULL, NULL, "$Revision: 6 $");
+
+#endif
+
+static void list_all_channels(struct Client *source_p);
+static void list_named_channel(struct Client *source_p, const char *name);
+
+/*
+** mo_olist
+**      parv[0] = sender prefix
+**      parv[1] = channel
+*/
+static int
+mo_olist(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       if(IsOperSpy(source_p))
+       {
+               /* If no arg, do all channels *whee*, else just one channel */
+               if(parc < 2 || EmptyString(parv[1]))
+               {
+                       report_operspy(source_p, "LIST", NULL);
+                       list_all_channels(source_p);
+               }
+               else
+               {
+                       report_operspy(source_p, "LIST", parv[1]);
+                       list_named_channel(source_p, parv[1]);
+               }
+       }
+
+       sendto_one(source_p, form_str(RPL_LISTEND), me.name, source_p->name);
+       return 0;
+}
+
+
+/*
+ * list_all_channels
+ * inputs      - pointer to client requesting list
+ * output      - 0/1
+ * side effects        - list all channels to source_p
+ */
+static void
+list_all_channels(struct Client *source_p)
+{
+       struct Channel *chptr;
+       dlink_node *ptr;
+       sendto_one(source_p, form_str(RPL_LISTSTART), me.name, source_p->name);
+
+       DLINK_FOREACH(ptr, global_channel_list.head)
+       {
+               chptr = ptr->data;
+
+               sendto_one(source_p, form_str(RPL_LIST),
+                               me.name, source_p->name, chptr->chname,
+                               dlink_list_length(&chptr->members),
+                               chptr->topic == NULL ? "" : chptr->topic);
+       }
+
+       return;
+}
+
+/*
+ * list_named_channel
+ * inputs       - pointer to client requesting list
+ * output       - 0/1
+ * side effects        - list all channels to source_p
+ */
+static void
+list_named_channel(struct Client *source_p, const char *name)
+{
+       struct Channel *chptr;
+       char *p;
+       char *n = LOCAL_COPY(name);
+
+       sendto_one(source_p, form_str(RPL_LISTSTART), me.name, source_p->name);
+
+       if((p = strchr(n, ',')))
+               *p = '\0';
+
+       if(EmptyString(n))
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, 
+                               form_str(ERR_NOSUCHCHANNEL), n);
+               return;
+       }
+
+       if((chptr = find_channel(n)) == NULL)
+               sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
+                               form_str(ERR_NOSUCHCHANNEL), n);
+       else
+               sendto_one(source_p, form_str(RPL_LIST), me.name, source_p->name,
+                       chptr->chname, dlink_list_length(&chptr->members),
+                       chptr->topic ? chptr->topic : "");
+}
diff --git a/extensions/m_omode.c b/extensions/m_omode.c
new file mode 100644 (file)
index 0000000..47a9114
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ *  Charybdis: an advanced Internet Relay Chat Daemon(ircd).
+ *  m_omode.c: allows oper mode hacking
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development team
+ *  Copyright (C) 2006 Charybdis development 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: m_omode.c 3121 2007-01-02 13:23:04Z jilles $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_user.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "s_serv.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "packet.h"
+
+static int mo_omode(struct Client *, struct Client *, int, const char **);
+
+struct Message omode_msgtab = {
+       "OMODE", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_omode, 3}}
+};
+
+mapi_clist_av1 omode_clist[] = { &omode_msgtab, NULL };
+
+DECLARE_MODULE_AV1(omode, NULL, NULL, omode_clist, NULL, NULL, "$Revision: 3121 $");
+
+/*
+ * mo_omode - MODE command handler
+ * parv[0] - sender
+ * parv[1] - channel
+ */
+static int
+mo_omode(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Channel *chptr = NULL;
+       struct membership *msptr;
+       char params[512];
+       int i;
+       int wasonchannel;
+
+       /* admins only */
+       if(!IsOperAdmin(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "admin");
+               return 0;
+       }
+
+       /* Now, try to find the channel in question */
+       if(!IsChanPrefix(parv[1][0]) || !check_channel_name(parv[1]))
+       {
+               sendto_one_numeric(source_p, ERR_BADCHANNAME,
+                               form_str(ERR_BADCHANNAME), parv[1]);
+               return 0;
+       }
+
+       chptr = find_channel(parv[1]);
+
+       if(chptr == NULL)
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
+                               form_str(ERR_NOSUCHCHANNEL), parv[1]);
+               return 0;
+       }
+
+       /* Now know the channel exists */
+       msptr = find_channel_membership(chptr, source_p);
+       wasonchannel = msptr != NULL;
+
+       if (is_chanop(msptr))
+       {
+               sendto_one_notice(source_p, ":Use a normal MODE you idiot");
+               return 0;
+       }
+
+       params[0] = '\0';
+       for (i = 2; i < parc; i++)
+       {
+               if (i != 2)
+                       strlcat(params, " ", sizeof params);
+               strlcat(params, parv[i], sizeof params);
+       }
+
+       sendto_wallops_flags(UMODE_WALLOP, &me, 
+                            "OMODE called for [%s] [%s] by %s!%s@%s",
+                            parv[1], params, source_p->name, source_p->username, source_p->host);
+       ilog(L_MAIN, "OMODE called for [%s] [%s] by %s",
+            parv[1], params, get_oper_name(source_p));
+
+       if(*chptr->chname != '&')
+               sendto_server(NULL, NULL, NOCAPS, NOCAPS, 
+                             ":%s WALLOPS :OMODE called for [%s] [%s] by %s!%s@%s",
+                             me.name, parv[1], params, source_p->name, source_p->username,
+                             source_p->host);
+
+#if 0
+       set_channel_mode(client_p, source_p->servptr, chptr, msptr, 
+                        parc - 2, parv + 2);
+#else
+       if (parc == 4 && !strcmp(parv[2], "+o") && !irccmp(parv[3], source_p->name))
+       {
+               /* Opping themselves */
+               if (!wasonchannel)
+               {
+                       sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,
+                                          form_str(ERR_USERNOTINCHANNEL), parv[3], chptr->chname);
+                       return 0;
+               }
+               sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +o %s",
+                               me.name, parv[1], source_p->name);
+               sendto_server(NULL, chptr, CAP_TS6, NOCAPS,
+                               ":%s TMODE %ld %s +o %s",
+                               me.id, (long) chptr->channelts, parv[1],
+                               source_p->id);
+               sendto_server(NULL, chptr, NOCAPS, CAP_TS6,
+                               ":%s MODE %s +o %s",
+                               me.name, parv[1], source_p->name);
+               msptr->flags |= CHFL_CHANOP;
+       }
+       else
+       {
+               /* Hack it so set_channel_mode() will accept */
+               if (wasonchannel)
+                       msptr->flags |= CHFL_CHANOP;
+               else
+               {
+                       add_user_to_channel(chptr, source_p, CHFL_CHANOP);
+                       msptr = find_channel_membership(chptr, source_p);
+               }
+               set_channel_mode(client_p, source_p, chptr, msptr, 
+                               parc - 2, parv + 2);
+               /* We know they were not opped before and they can't have opped
+                * themselves as set_channel_mode() does not allow that
+                * -- jilles */
+               if (wasonchannel)
+                       msptr->flags &= ~CHFL_CHANOP;
+               else
+                       remove_user_from_channel(msptr);
+       }
+#endif
+       return 0;
+}
diff --git a/extensions/m_opme.c b/extensions/m_opme.c
new file mode 100644 (file)
index 0000000..9798b77
--- /dev/null
@@ -0,0 +1,119 @@
+/*   contrib/m_opme.c
+ *   Copyright (C) 2002 Hybrid Development Team
+ *   Copyright (C) 2004 ircd-ratbox development 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 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_opme.c 3121 2007-01-02 13:23:04Z jilles $
+ */
+#include "stdinc.h"
+#include "tools.h"
+#include "patricia.h"
+#include "channel.h"
+#include "client.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_log.h"
+#include "s_serv.h"
+#include "send.h"
+#include "whowas.h"
+#include "irc_string.h"
+#include "hash.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+
+static int mo_opme(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
+
+struct Message opme_msgtab = {
+       "OPME", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_opme, 2}}
+};
+
+mapi_clist_av1 opme_clist[] = { &opme_msgtab, NULL };
+
+DECLARE_MODULE_AV1(opme, NULL, NULL, opme_clist, NULL, NULL, "$Revision: 3121 $");
+
+
+/*
+** mo_opme
+**      parv[0] = sender prefix
+**      parv[1] = channel
+*/
+static int
+mo_opme(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Channel *chptr;
+       struct membership *msptr;
+       dlink_node *ptr;
+
+       /* admins only */
+       if(!IsOperAdmin(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "opme");
+               return 0;
+       }
+
+       if((chptr = find_channel(parv[1])) == NULL)
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
+                                  form_str(ERR_NOSUCHCHANNEL), parv[1]);
+               return 0;
+       }
+
+       DLINK_FOREACH(ptr, chptr->members.head)
+       {
+               msptr = ptr->data;
+
+               if(is_chanop(msptr))
+               {
+                       sendto_one(source_p, ":%s NOTICE %s :%s Channel is not opless",
+                                  me.name, parv[0], parv[1]);
+                       return 0;
+               }
+       }
+
+       msptr = find_channel_membership(chptr, source_p);
+
+       if(msptr == NULL)
+               return 0;
+
+       msptr->flags |= CHFL_CHANOP;
+
+       sendto_wallops_flags(UMODE_WALLOP, &me,
+                            "OPME called for [%s] by %s!%s@%s",
+                            parv[1], source_p->name, source_p->username, source_p->host);
+       ilog(L_MAIN, "OPME called for [%s] by %s",
+            parv[1], get_oper_name(source_p));
+
+       /* dont send stuff for local channels remotely. */
+       if(*chptr->chname != '&')
+       {
+               sendto_server(NULL, NULL, NOCAPS, NOCAPS,
+                             ":%s WALLOPS :OPME called for [%s] by %s!%s@%s",
+                             me.name, parv[1], source_p->name, source_p->username, source_p->host);
+               sendto_server(NULL, chptr, NOCAPS, NOCAPS, ":%s PART %s", source_p->name, parv[1]);
+               sendto_server(NULL, chptr, NOCAPS, NOCAPS,
+                             ":%s SJOIN %ld %s + :@%s",
+                             me.name, (long) chptr->channelts, parv[1], source_p->name);
+       }
+
+       sendto_channel_local(ALL_MEMBERS, chptr,
+                            ":%s MODE %s +o %s", me.name, parv[1], source_p->name);
+
+       return 0;
+}
diff --git a/extensions/m_webirc.c b/extensions/m_webirc.c
new file mode 100644 (file)
index 0000000..58aa48d
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_webirc.c: Makes CGI:IRC users appear as coming from their real host
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2006 ircd-ratbox development 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: m_webirc.c 2757 2006-11-10 22:58:15Z jilles $
+ */
+/* Usage:
+ * auth {
+ *   user = "webirc@<cgiirc ip>"; # if identd used, put ident username instead
+ *   password = "<password>"; # encryption possible
+ *   spoof = "webirc."
+ *   class = "users";
+ * };
+ * Possible flags:
+ *   encrypted - password is encrypted (recommended)
+ *   kline_exempt - k/g lines on the cgiirc ip are ignored
+ *   gline_exempt - glines on the cgiirc ip are ignored
+ * dlines are checked on the cgiirc ip (of course).
+ * k/d/g/x lines, auth blocks, user limits, etc are checked using the
+ * real host/ip.
+ * The password should be specified unencrypted in webirc_password in
+ * cgiirc.config
+ */
+
+#include "stdinc.h"
+#include "client.h"            /* client struct */
+#include "irc_string.h"
+#include "hostmask.h"
+#include "send.h"              /* sendto_one */
+#include "numeric.h"           /* ERR_xxx */
+#include "ircd.h"              /* me */
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_serv.h"
+#include "hash.h"
+#include "s_conf.h"
+
+static int mr_webirc(struct Client *, struct Client *, int, const char **);
+
+struct Message webirc_msgtab = {
+       "WEBIRC", 0, 0, 0, MFLG_SLOW | MFLG_UNREG,
+       {{mr_webirc, 4}, mg_reg, mg_ignore, mg_ignore, mg_ignore, mg_reg}
+};
+
+mapi_clist_av1 webirc_clist[] = { &webirc_msgtab, NULL };
+DECLARE_MODULE_AV1(webirc, NULL, NULL, webirc_clist, NULL, NULL, "$Revision: 20702 $");
+
+/*
+ * mr_webirc - webirc message handler
+ *      parv[0] = sender prefix
+ *      parv[1] = password
+ *      parv[2] = fake username (we ignore this)
+ *     parv[3] = fake hostname 
+ *     parv[4] = fake ip
+ */
+static int
+mr_webirc(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct ConfItem *aconf;
+       const char *encr;
+
+       if (!strchr(parv[4], '.') && !strchr(parv[4], ':'))
+       {
+               sendto_one(source_p, "NOTICE * :Invalid IP");
+               return 0;
+       }
+
+       aconf = find_address_conf(client_p->host, client_p->sockhost, 
+                               IsGotId(client_p) ? client_p->username : "webirc",
+                               IsGotId(client_p) ? client_p->username : "webirc",
+                               (struct sockaddr *) &client_p->localClient->ip,
+                               client_p->localClient->ip.ss_family);
+       if (aconf == NULL || !(aconf->status & CONF_CLIENT))
+               return 0;
+       if (!IsConfDoSpoofIp(aconf) || irccmp(aconf->name, "webirc."))
+       {
+               /* XXX */
+               sendto_one(source_p, "NOTICE * :Not a CGI:IRC auth block");
+               return 0;
+       }
+       if (EmptyString(aconf->passwd))
+       {
+               sendto_one(source_p, "NOTICE * :CGI:IRC auth blocks must have a password");
+               return 0;
+       }
+
+       if (EmptyString(parv[1]))
+               encr = "";
+       else if (IsConfEncrypted(aconf))
+               encr = crypt(parv[1], aconf->passwd);
+       else
+               encr = parv[1];
+
+       if (strcmp(encr, aconf->passwd))
+       {
+               sendto_one(source_p, "NOTICE * :CGI:IRC password incorrect");
+               return 0;
+       }
+
+
+       strlcpy(source_p->sockhost, parv[4], sizeof(source_p->sockhost));
+
+       if(strlen(parv[3]) <= HOSTLEN)
+               strlcpy(source_p->host, parv[3], sizeof(source_p->host));
+       else
+               strlcpy(source_p->host, source_p->sockhost, sizeof(source_p->host));
+       
+       inetpton_sock(parv[4], (struct sockaddr *)&source_p->localClient->ip);
+
+       /* Check dlines now, k/glines will be checked on registration */
+       if((aconf = find_dline((struct sockaddr *)&source_p->localClient->ip, 
+                              source_p->localClient->ip.ss_family)))
+       {
+               if(!(aconf->status & CONF_EXEMPTDLINE))
+               {
+                       exit_client(client_p, source_p, &me, "D-lined");
+                       return 0;
+               }
+       }
+
+       sendto_one(source_p, "NOTICE * :CGI:IRC host/IP set to %s %s", parv[3], parv[4]);
+       return 0;
+}
diff --git a/extensions/no_oper_invis.c b/extensions/no_oper_invis.c
new file mode 100644 (file)
index 0000000..8449b8f
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Deny opers setting themselves +i unless they are bots (i.e. have
+ * hidden_oper privilege).
+ * -- jilles
+ *
+ * $Id: no_oper_invis.c 1086 2006-03-17 23:20:30Z jilles $
+ */
+
+#include "stdinc.h"
+#include "modules.h"
+#include "client.h"
+#include "hook.h"
+#include "ircd.h"
+#include "send.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+
+static void h_noi_umode_changed(hook_data_umode_changed *);
+
+mapi_hfn_list_av1 noi_hfnlist[] = {
+       { "umode_changed", (hookfn) h_noi_umode_changed },
+       { NULL, NULL }
+};
+
+DECLARE_MODULE_AV1(no_oper_invis, NULL, NULL, NULL, NULL, noi_hfnlist, "$Revision: 1086 $");
+
+static void
+h_noi_umode_changed(hook_data_umode_changed *hdata)
+{
+       struct Client *source_p = hdata->client;
+
+       if (MyClient(source_p) && IsOper(source_p) && !IsOperInvis(source_p) &&
+                       IsInvisible(source_p))
+       {
+               ClearInvisible(source_p);
+               /* If they tried /umode +i, complain; do not complain
+                * if they opered up while invisible -- jilles */
+               if (hdata->oldumodes & UMODE_OPER)
+                       sendto_one_notice(source_p, ":*** Opers may not set themselves invisible");
+       }
+}
diff --git a/extensions/sno_farconnect.c b/extensions/sno_farconnect.c
new file mode 100644 (file)
index 0000000..03877b4
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Remote client connect/exit notices on snomask +F (far).
+ * To avoid flooding, connects/exits part of netjoins/netsplits are not shown.
+ * Consequently, it is not possible to use these notices to keep track
+ * of all clients.
+ * -- jilles
+ *
+ * $Id: sno_farconnect.c 1869 2006-08-27 14:24:25Z jilles $
+ */
+
+#include "stdinc.h"
+#include "modules.h"
+#include "client.h"
+#include "hook.h"
+#include "ircd.h"
+#include "send.h"
+#include "s_conf.h"
+#include "snomask.h"
+
+static int _modinit(void);
+static void _moddeinit(void);
+static void h_gcn_new_remote_user(struct Client *);
+static void h_gcn_client_exit(hook_data_client_exit *);
+
+mapi_hfn_list_av1 gcn_hfnlist[] = {
+       { "new_remote_user", (hookfn) h_gcn_new_remote_user },
+       { "client_exit", (hookfn) h_gcn_client_exit },
+       { NULL, NULL }
+};
+
+DECLARE_MODULE_AV1(globalconnexit, _modinit, _moddeinit, NULL, NULL, gcn_hfnlist, "$Revision: 1869 $");
+
+static int
+_modinit(void)
+{
+       /* add the snomask to the available slot */
+       snomask_modes['F'] = find_snomask_slot();
+
+       /* show the fact that we are showing user information in /version */
+       opers_see_all_users = 1;
+
+       return 0;
+}
+
+static void
+_moddeinit(void)
+{
+       /* disable the snomask and remove it from the available list */
+       snomask_modes['F'] = 0;
+}
+
+static void
+h_gcn_new_remote_user(struct Client *source_p)
+{
+
+       if (!HasSentEob(source_p->servptr))
+               return;
+       sendto_realops_snomask_from(snomask_modes['F'], L_ALL, source_p->servptr,
+                       "Client connecting: %s (%s@%s) [%s] {%s} [%s]",
+                       source_p->name, source_p->username, source_p->orighost,
+                       show_ip(NULL, source_p) ? source_p->sockhost : "255.255.255.255",
+                       "?", source_p->info);
+}
+
+static void
+h_gcn_client_exit(hook_data_client_exit *hdata)
+{
+       struct Client *source_p;
+
+       source_p = hdata->target;
+
+       if (MyConnect(source_p) || !IsClient(source_p))
+               return;
+       if (!HasSentEob(source_p->servptr))
+               return;
+       sendto_realops_snomask_from(snomask_modes['F'], L_ALL, source_p->servptr,
+                            "Client exiting: %s (%s@%s) [%s] [%s]",
+                            source_p->name,
+                            source_p->username, source_p->host, hdata->comment,
+                             show_ip(NULL, source_p) ? source_p->sockhost : "255.255.255.255");
+}
diff --git a/extensions/sno_globalkline.c b/extensions/sno_globalkline.c
new file mode 100644 (file)
index 0000000..8a5699a
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Shows notices if remote clients exit with "Bad user info" or
+ * ConfigFileEntry.kline_reason.
+ * Assumes client_exit is enabled so users can't fake these reasons,
+ * and kline_reason is enabled and the same everywhere.
+ * Yes, this is a hack, but it is simple and avoids sending
+ * more data across servers -- jilles
+ *
+ * $Id: sno_globalkline.c 613 2006-01-29 03:03:02Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "modules.h"
+#include "client.h"
+#include "hook.h"
+#include "ircd.h"
+#include "send.h"
+#include "s_conf.h"
+
+static void h_gla_client_exit(hook_data_client_exit *);
+
+mapi_hfn_list_av1 gla_hfnlist[] = {
+       { "client_exit", (hookfn) h_gla_client_exit },
+       { NULL, NULL }
+};
+
+DECLARE_MODULE_AV1(globallineactive, NULL, NULL, NULL, NULL, gla_hfnlist, "$Revision: 613 $");
+
+static void
+h_gla_client_exit(hook_data_client_exit *hdata)
+{
+       struct Client *source_p;
+
+       source_p = hdata->target;
+
+       if (MyConnect(source_p) || !IsClient(source_p))
+               return;
+       if (!strcmp(hdata->comment, "Bad user info"))
+       {
+               sendto_realops_snomask_from(SNO_GENERAL, L_ALL, source_p->servptr,
+                               "XLINE active for %s[%s@%s]",
+                               source_p->name, source_p->username, source_p->host);
+       }
+       else if (ConfigFileEntry.kline_reason != NULL &&
+                       !strcmp(hdata->comment, ConfigFileEntry.kline_reason))
+       {
+               sendto_realops_snomask_from(SNO_GENERAL, L_ALL, source_p->servptr,
+                               "K/D/GLINE active for %s[%s@%s]",
+                               source_p->name, source_p->username, source_p->host);
+       }
+}
diff --git a/extensions/sno_globaloper.c b/extensions/sno_globaloper.c
new file mode 100644 (file)
index 0000000..c0d00d2
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Remote oper up notices.
+ *
+ * $Id: sno_globaloper.c 639 2006-01-29 21:42:06Z jilles $
+ */
+
+#include "stdinc.h"
+#include "modules.h"
+#include "client.h"
+#include "hook.h"
+#include "ircd.h"
+#include "send.h"
+#include "s_conf.h"
+#include "snomask.h"
+
+static void h_sgo_umode_changed(void *);
+
+mapi_hfn_list_av1 sgo_hfnlist[] = {
+       { "umode_changed", (hookfn) h_sgo_umode_changed },
+       { NULL, NULL }
+};
+
+DECLARE_MODULE_AV1(sno_globaloper, NULL, NULL, NULL, NULL, sgo_hfnlist, "$Revision: 639 $");
+
+static void
+h_sgo_umode_changed(void *vdata)
+{
+       hook_data_umode_changed *data = (hook_data_umode_changed *)vdata;
+       struct Client *source_p = data->client;
+
+       if (MyConnect(source_p) || !HasSentEob(source_p->servptr))
+               return;
+
+       if (!(data->oldumodes & UMODE_OPER) && IsOper(source_p))
+               sendto_realops_snomask_from(SNO_GENERAL, L_ALL, source_p->servptr,
+                               "%s (%s@%s) is now an operator",
+                               source_p->name, source_p->username, source_p->host);
+}
diff --git a/extensions/spy_admin_notice.c b/extensions/spy_admin_notice.c
new file mode 100644 (file)
index 0000000..f8627fc
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  spy_admin_notice.c: Sends a notice when someone uses ADMIN.
+ *
+ *  Copyright (C) 2002 by the past and present ircd coders, and others.
+ *
+ *  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: spy_admin_notice.c 498 2006-01-15 16:40:33Z jilles $
+ */
+#include "stdinc.h"
+#include "modules.h"
+#include "hook.h"
+#include "client.h"
+#include "ircd.h"
+#include "send.h"
+
+void show_admin(hook_data *);
+
+mapi_hfn_list_av1 admin_hfnlist[] = {
+       {"doing_admin", (hookfn) show_admin},
+       {NULL, NULL}
+};
+
+DECLARE_MODULE_AV1(admin_spy, NULL, NULL, NULL, NULL, admin_hfnlist, "$Revision: 498 $");
+
+void
+show_admin(hook_data *data)
+{
+       sendto_realops_snomask(SNO_SPY, L_ALL,
+                            "admin requested by %s (%s@%s) [%s]",
+                            data->client->name, data->client->username,
+                            data->client->host, data->client->user->server);
+}
diff --git a/extensions/spy_info_notice.c b/extensions/spy_info_notice.c
new file mode 100644 (file)
index 0000000..3053940
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  spy_info_notice.c: Sends a notice when someone uses INFO.
+ *
+ *  Copyright (C) 2002 by the past and present ircd coders, and others.
+ *
+ *  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: spy_info_notice.c 498 2006-01-15 16:40:33Z jilles $
+ */
+#include "stdinc.h"
+#include "modules.h"
+#include "hook.h"
+#include "client.h"
+#include "ircd.h"
+#include "send.h"
+
+void show_info(hook_data *);
+
+mapi_hfn_list_av1 info_hfnlist[] = {
+       {"doing_info", (hookfn) show_info},
+       {NULL, NULL}
+};
+
+DECLARE_MODULE_AV1(info_spy, NULL, NULL, NULL, NULL, info_hfnlist, "$Revision: 498 $");
+
+void
+show_info(hook_data *data)
+{
+       sendto_realops_snomask(SNO_SPY, L_ALL,
+                            "info requested by %s (%s@%s) [%s]",
+                            data->client->name, data->client->username,
+                            data->client->host, data->client->user->server);
+}
diff --git a/extensions/spy_links_notice.c b/extensions/spy_links_notice.c
new file mode 100644 (file)
index 0000000..b71e2d4
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  spy_links_notice.c: Sends a notice when someone uses LINKS.
+ *
+ *  Copyright (C) 2002 by the past and present ircd coders, and others.
+ *
+ *  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: spy_links_notice.c 498 2006-01-15 16:40:33Z jilles $
+ */
+#include "stdinc.h"
+#include "modules.h"
+#include "hook.h"
+#include "client.h"
+#include "ircd.h"
+#include "send.h"
+
+void show_links(hook_data *);
+
+mapi_hfn_list_av1 links_hfnlist[] = {
+       {"doing_links", (hookfn) show_links},
+       {NULL, NULL}
+};
+
+DECLARE_MODULE_AV1(links_spy, NULL, NULL, NULL, NULL, links_hfnlist, "$Revision: 498 $");
+
+void
+show_links(hook_data *data)
+{
+       const char *mask = data->arg1;
+
+       sendto_realops_snomask(SNO_SPY, L_ALL,
+                            "LINKS '%s' requested by %s (%s@%s) [%s]",
+                            mask, data->client->name, data->client->username,
+                            data->client->host, data->client->user->server);
+}
diff --git a/extensions/spy_motd_notice.c b/extensions/spy_motd_notice.c
new file mode 100644 (file)
index 0000000..b872f34
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  spy_motd_notice.c: Sends a notice when someone uses MOTD.
+ *
+ *  Copyright (C) 2002 by the past and present ircd coders, and others.
+ *
+ *  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: spy_motd_notice.c 498 2006-01-15 16:40:33Z jilles $
+ */
+#include "stdinc.h"
+#include "modules.h"
+#include "hook.h"
+#include "client.h"
+#include "ircd.h"
+#include "send.h"
+
+void show_motd(hook_data *);
+
+mapi_hfn_list_av1 motd_hfnlist[] = {
+       {"doing_motd", (hookfn) show_motd},
+       {NULL, NULL}
+};
+
+DECLARE_MODULE_AV1(motd_spy, NULL, NULL, NULL, NULL, motd_hfnlist, "$Revision: 498 $");
+
+void
+show_motd(hook_data *data)
+{
+       sendto_realops_snomask(SNO_SPY, L_ALL,
+                            "motd requested by %s (%s@%s) [%s]",
+                            data->client->name, data->client->username,
+                            data->client->host, data->client->user->server);
+}
diff --git a/extensions/spy_stats_notice.c b/extensions/spy_stats_notice.c
new file mode 100644 (file)
index 0000000..8d57516
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  spy_stats_notice.c: Sends a notice when someone uses STATS.
+ *
+ *  Copyright (C) 2002 by the past and present ircd coders, and others.
+ *
+ *  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: spy_stats_notice.c 498 2006-01-15 16:40:33Z jilles $
+ */
+#include "stdinc.h"
+#include "modules.h"
+#include "hook.h"
+#include "client.h"
+#include "ircd.h"
+#include "send.h"
+
+void show_stats(hook_data_int *);
+
+mapi_hfn_list_av1 stats_hfnlist[] = {
+       {"doing_stats", (hookfn) show_stats},
+       {NULL, NULL}
+};
+
+DECLARE_MODULE_AV1(stats_spy, NULL, NULL, NULL, NULL, stats_hfnlist, "$Revision: 498 $");
+
+void
+show_stats(hook_data_int *data)
+{
+       char statchar = (char) data->arg2;
+
+       if(statchar == 'L' || statchar == 'l')
+       {
+               const char *name = data->arg1;
+
+               if(!EmptyString(name))
+                       sendto_realops_snomask(SNO_SPY, L_ALL,
+                                       "STATS %c requested by %s (%s@%s) [%s] on %s",
+                                       statchar, data->client->name,
+                                       data->client->username,
+                                       data->client->host,
+                                       data->client->user->server, name);
+               else
+                       sendto_realops_snomask(SNO_SPY, L_ALL,
+                                       "STATS %c requested by %s (%s@%s) [%s]",
+                                       statchar, data->client->name,
+                                       data->client->username,
+                                       data->client->host, data->client->user->server);
+       }
+       else
+       {
+               sendto_realops_snomask(SNO_SPY, L_ALL,
+                               "STATS %c requested by %s (%s@%s) [%s]",
+                               statchar, data->client->name, data->client->username,
+                               data->client->host, data->client->user->server);
+       }
+}
diff --git a/extensions/spy_stats_p_notice.c b/extensions/spy_stats_p_notice.c
new file mode 100644 (file)
index 0000000..72b08b6
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  spy_stats_p_notice.c: Sends a notice when someone uses STATS p.
+ *
+ *  Copyright (C) 2002 by the past and present ircd coders, and others.
+ *
+ *  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: spy_stats_p_notice.c 498 2006-01-15 16:40:33Z jilles $
+ */
+#include "stdinc.h"
+#include "modules.h"
+#include "hook.h"
+#include "client.h"
+#include "ircd.h"
+#include "send.h"
+
+void show_stats_p(hook_data *);
+
+mapi_hfn_list_av1 stats_p_hfnlist[] = {
+       {"doing_stats_p", (hookfn) show_stats_p},
+       {NULL, NULL}
+};
+
+DECLARE_MODULE_AV1(stats_p_spy, NULL, NULL, NULL, NULL, stats_p_hfnlist, "$Revision: 498 $");
+
+void
+show_stats_p(hook_data *data)
+{
+       sendto_realops_snomask(SNO_SPY, L_ALL,
+                            "STATS p requested by %s (%s@%s) [%s]",
+                            data->client->name, data->client->username,
+                            data->client->host, data->client->user->server);
+}
diff --git a/extensions/spy_trace_notice.c b/extensions/spy_trace_notice.c
new file mode 100644 (file)
index 0000000..8c4560a
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  spy_trace_notice.c: Sends a notice when someone uses TRACE or LTRACE
+ *
+ *  Copyright (C) 2002 Hybrid Development 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: spy_trace_notice.c 498 2006-01-15 16:40:33Z jilles $
+ */
+#include "stdinc.h"
+#include "modules.h"
+#include "hook.h"
+#include "client.h"
+#include "ircd.h"
+#include "send.h"
+
+void show_trace(hook_data_client *);
+
+mapi_hfn_list_av1 trace_hfnlist[] = {
+       {"doing_trace", (hookfn) show_trace},
+       {NULL, NULL}
+};
+
+DECLARE_MODULE_AV1(trace_spy, NULL, NULL, NULL, NULL, trace_hfnlist, "$Revision: 498 $");
+
+void
+show_trace(hook_data_client *data)
+{
+       if(data->target)
+               sendto_realops_snomask(SNO_SPY, L_ALL,
+                               "trace requested by %s (%s@%s) [%s] on %s",
+                               data->client->name, data->client->username,
+                               data->client->host, data->client->user->server,
+                               data->target->name);
+       else
+               sendto_realops_snomask(SNO_SPY, L_ALL,
+                               "trace requested by %s (%s@%s) [%s]",
+                               data->client->name, data->client->username,
+                               data->client->host, data->client->user->server);
+}
diff --git a/extensions/spy_whois_notice.c b/extensions/spy_whois_notice.c
new file mode 100644 (file)
index 0000000..ba29ef3
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  spy_whois_notice.c: Sends a notice when someone uses WHOIS.
+ *
+ *  Copyright (C) 2002 by the past and present ircd coders, and others.
+ *
+ *  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: spy_whois_notice.c 498 2006-01-15 16:40:33Z jilles $
+ */
+#include "stdinc.h"
+#include "modules.h"
+#include "hook.h"
+#include "client.h"
+#include "ircd.h"
+#include "send.h"
+
+void show_whois(hook_data_client *);
+
+mapi_hfn_list_av1 whois_hfnlist[] = {
+       {"doing_whois", (hookfn) show_whois},
+       {NULL, NULL}
+};
+
+DECLARE_MODULE_AV1(whois_spy, NULL, NULL, NULL, NULL, whois_hfnlist, "$Revision: 498 $");
+
+void
+show_whois(hook_data_client *data)
+{
+       struct Client *source_p = data->client;
+       struct Client *target_p = data->target;
+
+       /* source being MyConnect() is implicit here from m_whois.c --fl */
+       if(MyClient(target_p) && IsOper(target_p) && (source_p != target_p) &&
+          (target_p->snomask & SNO_SPY))
+       {
+               sendto_one(target_p,
+                               ":%s NOTICE %s :*** Notice -- %s (%s@%s) is doing a whois on you [%s]",
+                               me.name, target_p->name, source_p->name,
+                               source_p->username, source_p->host,
+                               source_p->user->server);
+       }
+}
diff --git a/extensions/spy_whois_notice_global.c b/extensions/spy_whois_notice_global.c
new file mode 100644 (file)
index 0000000..b586d7e
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  spy_whois_notice.c: Sends a notice when someone uses WHOIS.
+ *
+ *  Copyright (C) 2002 by the past and present ircd coders, and others.
+ *
+ *  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: spy_whois_notice_global.c 498 2006-01-15 16:40:33Z jilles $
+ */
+#include "stdinc.h"
+#include "modules.h"
+#include "hook.h"
+#include "client.h"
+#include "ircd.h"
+#include "send.h"
+
+void show_whois_global(hook_data_client *);
+
+mapi_hfn_list_av1 whois_global_hfnlist[] = {
+       {"doing_whois_global", (hookfn) show_whois_global},
+       {NULL, NULL}
+};
+
+DECLARE_MODULE_AV1(whois_global_spy, NULL, NULL, NULL, NULL, whois_global_hfnlist,
+                  "$Revision: 498 $");
+
+void
+show_whois_global(hook_data_client *data)
+{
+       struct Client *source_p = data->client;
+       struct Client *target_p = data->target;
+
+       if(MyClient(target_p) && IsOper(target_p) && (source_p != target_p) &&
+          (target_p->snomask & SNO_SPY))
+       {
+               sendto_one(target_p,
+                               ":%s NOTICE %s :*** Notice -- %s (%s@%s) is doing a whois on you [%s]",
+                               me.name, target_p->name, source_p->name,
+                               source_p->username, source_p->host,
+                               source_p->user->server);
+       }
+}
diff --git a/help/.cvsignore b/help/.cvsignore
new file mode 100644 (file)
index 0000000..f3c7a7c
--- /dev/null
@@ -0,0 +1 @@
+Makefile
diff --git a/help/Makefile.in b/help/Makefile.in
new file mode 100644 (file)
index 0000000..95adfc8
--- /dev/null
@@ -0,0 +1,98 @@
+# Generated automatically from Makefile.in by configure.
+# $Id: Makefile.in 1044 2006-03-12 16:05:39Z jilles $
+# makefile for include/
+
+INSTALL=       @INSTALL@
+INSTALL_DATA=  @INSTALL_DATA@
+RM=            @RM@
+
+prefix=                @prefix@
+exec_prefix=   @execprefix@
+helpdir=       @helpdir@
+uhelpdir=      ${helpdir}/users
+ohelpdir=      ${helpdir}/opers
+
+SYMLINKS=      topic accept cmode admin names links away whowas \
+               version kick who invite quit join list nick oper part \
+               time credits motd userhost users whois ison lusers \
+               user help pass error challenge knock ping pong \
+               cprivmsg cnotice map trace
+
+all:
+build:
+clean:
+depend:
+lint:
+
+index:
+       @echo building index files
+       rm -f users/index.tmp
+       @for help in users/*; do \
+               if [ -f $$help ]; then \
+                       echo $$help >> users/index.tmp; \
+               fi \
+       done
+       @for help in $(SYMLINKS); do \
+               echo $$help >> users/index.tmp; \
+       done
+       echo 'Help topics available to users:' > users/index
+       echo '' >> users/index
+       cat users/index.tmp \
+               | sed -e 's|^users/||' \
+               | sort -u \
+               | tr a-z A-Z \
+               | column -c 65 -x \
+               | expand \
+               >> users/index
+       rm -f users/index.tmp
+       rm -f opers/index.tmp
+       @for help in opers/*; do \
+               if [ -f $$help ]; then \
+                       echo $$help >> opers/index.tmp; \
+               fi \
+       done
+       echo 'Help topics available to opers:' > opers/index
+       echo '' >> opers/index
+       cat opers/index.tmp \
+               | sed -e 's|^opers/||' \
+               | sort -u \
+               | tr a-z A-Z \
+               | column -c 65 -s ' ' -x \
+               | expand \
+               >> opers/index
+       rm -f opers/index.tmp
+
+install:
+       -@if test -d $(DESTDIR)$(helpdir)-old; then \
+               rm -rf $(DESTDIR)$(helpdir)-old; \
+       fi
+       -@if test -d $(DESTDIR)$(helpdir); then \
+               echo "ircd: backing up old help files"; \
+               mv $(DESTDIR)$(helpdir) $(DESTDIR)$(helpdir)-old; \
+       fi
+
+       @echo "ircd: setting up help directory structure"
+       @mkdir -p -m 755 $(DESTDIR)$(helpdir)
+       @mkdir -p -m 755 $(DESTDIR)$(helpdir)/opers
+       @mkdir -p -m 755 $(DESTDIR)$(helpdir)/users
+
+       @for help in opers/*; do \
+       if [ -f $$help ]; then \
+               ${INSTALL_DATA} $$help $(DESTDIR)$(ohelpdir); \
+       fi \
+       done
+       @for help in users/*; do \
+       if [ -f $$help ]; then \
+               $(INSTALL_DATA) $$help $(DESTDIR)$(uhelpdir); \
+       fi \
+       done
+       @for link in $(SYMLINKS); do \
+               rm -f $(DESTDIR)$(uhelpdir)/$$link; \
+               ln -s $(ohelpdir)/$$link $(DESTDIR)$(uhelpdir); \
+       done
+
+
+distclean:
+       ${RM} -f Makefile
+
+depend:
diff --git a/help/opers/accept b/help/opers/accept
new file mode 100644 (file)
index 0000000..c36ad1b
--- /dev/null
@@ -0,0 +1,8 @@
+ACCEPT <parameter>
+
+ACCEPT allows you to control who can send you a NOTICE or PRIVMSG
+while you have user mode +g enabled.
+
+For +g: /QUOTE ACCEPT <nick>   -- Add a permitted nickname
+        /QUOTE ACCEPT -<nick>  -- Remove a permitted nickname
+        /QUOTE ACCEPT *        -- List the present permitted nicknames
diff --git a/help/opers/admin b/help/opers/admin
new file mode 100644 (file)
index 0000000..7b1b8a0
--- /dev/null
@@ -0,0 +1,11 @@
+ADMIN [server]
+
+With no arguments, ADMIN shows the information that was set by the
+administrator of the server. This information can take any form that
+will fit in three lines of text but is usually a list of contacts
+for the persons that run the server.
+
+With a second argument, the administrative information for the
+specified server is displayed.
+
+See also: stats
diff --git a/help/opers/away b/help/opers/away
new file mode 100644 (file)
index 0000000..9f04479
--- /dev/null
@@ -0,0 +1,4 @@
+AWAY :[MSG]
+
+Without an argument, it will set you back.  With an argument,
+it will set you as AWAY with the specified message.
diff --git a/help/opers/capab b/help/opers/capab
new file mode 100644 (file)
index 0000000..36abc97
--- /dev/null
@@ -0,0 +1 @@
+CAPAB - Server to Server Protocol Command.
diff --git a/help/opers/challenge b/help/opers/challenge
new file mode 100644 (file)
index 0000000..9e8d432
--- /dev/null
@@ -0,0 +1,10 @@
+CHALLENGE <nick|+response>
+
+CHALLENGE is used in the RSA controlled
+oper {} system.  CHALLENGE requires you to
+issue the command using the nickname in the
+operator block, while matching the username
+and hostname specified.  The server will
+send you an RSA challenge.  You must send
+a valid RSA response back to the server,
+proceeded with a '+' symbol.
diff --git a/help/opers/chantrace b/help/opers/chantrace
new file mode 100644 (file)
index 0000000..7b63601
--- /dev/null
@@ -0,0 +1,6 @@
+CHANTRACE <#channel>
+
+Outputs a list of members in #channel in ETRACE format, with the classname
+replaced by the server the users are on.
+
+You must be a member of the channel to perform this command.
diff --git a/help/opers/close b/help/opers/close
new file mode 100644 (file)
index 0000000..82fae6b
--- /dev/null
@@ -0,0 +1,4 @@
+CLOSE
+
+Close any connections from clients or servers who have
+not fully registered yet.
diff --git a/help/opers/cmode b/help/opers/cmode
new file mode 100644 (file)
index 0000000..f42fe8e
--- /dev/null
@@ -0,0 +1,55 @@
+MODE <channel> <+|-><modes> [parameters]
+
+CHANNELMODE - DESCRIPTION
+------------------------------------------------------------------------
+NO PARAMETERS:
+     +n     - No external messages.  Only channel members may talk in
+              the channel.
+     +t     - Ops Topic.  Only opped (+o) users may set the topic.
+     +s     - Secret.  Channel will not be shown in /whois and /list etc.
+     +p     - Private.  Disables /knock to the channel.
+     +m     - Moderated.  Only opped/voiced users may talk in channel.
+     +i     - Invite only.  Users need to be /invite'd or match a +I to
+              join the channel.
+     +r     - Registered users only.  Only users identified to services
+              may join.
+     +c     - No color.  All color codes in messages are stripped.
+     +g     - Free invite.  Everyone may invite users.  Significantly
+              weakens +i control.
+     +z     - Op moderated.  Messages blocked by +m are instead sent to ops.
+     +L     - Large ban list.  Increase maximum number of +beIq entries.
+              Only settable by opers.
+     +P     - Permanent.  Channel does not disappear when empty.  Only
+              settable by opers.
+     +F     - Free target.  Anyone may set forwards to this (otherwise
+              ops are necessary).
+     +Q     - Disable forward.  Users cannot be forwarded to the channel
+              (however, new forwards can still be set subject to +F).
+
+WITH PARAMETERS:
+     +f     - Forward.  Forwards users who cannot join because of +i,
+              +j, +l or +r.
+              PARAMS: /mode #channel +f #channel2
+     +j     - Join throttle.  Limits number of joins to the channel per time.
+              PARAMS: /mode #channel +j count:time
+     +k     - Key.  Requires users to issue /join #channel KEY to join.
+              PARAMS: /mode #channel +k key
+     +l     - Limit.  Impose a maximum number of LIMIT people in the channel.
+              PARAMS: /mode #channel +l limit
+     +v     - Voice.  Allows a user to talk in a +m channel.  Noted by +nick.
+              PARAMS: /mode #channel +v nick
+     +o     - Op.  Allows a user full control over the channel.
+              PARAMS: /mode #channel +o nick
+     +b     - Ban.  Prevents a user from entering the channel, based on a 
+              nick!ident@host match.
+              PARAMS: /mode #channel +b nick!user@host
+     +q     - Quiet.  Prevents a user from sending to the channel, based on a
+              nick!ident@host match.
+              PARAMS: /mode #channel +q nick!user@host
+     +e     - Exempt.  Allows a user to join a channel and send to it even if
+              they are banned (+b) or quieted (+q), based on a nick!ident@host
+              match.
+              PARAMS: /mode #channel +e nick!user@host
+     +I     - Invite Exempt.  Allows a user to join a +i channel without an 
+              invite, based on a nick!user@host match.
+              PARAMS: /mode #channel +I nick!user@host
diff --git a/help/opers/cnotice b/help/opers/cnotice
new file mode 100644 (file)
index 0000000..338b643
--- /dev/null
@@ -0,0 +1,5 @@
+CNOTICE <nick> <channel> :<text>
+
+Providing you are opped (+o) or voiced (+v) in <channel>, and <nick>
+is a member of <channel>, CNOTICE generates a NOTICE towards 
+<nick>.  CNOTICE bypasses any anti-spam measures in place.
diff --git a/help/opers/connect b/help/opers/connect
new file mode 100644 (file)
index 0000000..929bfb8
--- /dev/null
@@ -0,0 +1,16 @@
+CONNECT <server_A> [port] [server_B]
+
+When [server_B] is used, CONNECT asks [server_B] to
+connect to <server_A>.  Requires Oper Priv: R
+
+The [port] must be specified with [server_B], this is
+usually 6667.  To use the default port in the connect
+block, you can use 0 as the port.
+
+When [server_B] is not used, CONNECT tries to connect
+your server to <server_A>.
+
+When [port] is used, the connection will be attempted
+to [port].
+When [port] is not used, 6667 is used as a default,
+unless the port is specified in the conf file.
diff --git a/help/opers/cprivmsg b/help/opers/cprivmsg
new file mode 100644 (file)
index 0000000..fd9f0c1
--- /dev/null
@@ -0,0 +1,5 @@
+CPRIVMSG <nick> <channel> :<text>
+
+Providing you are opped (+o) or voiced (+v) in <channel>, and <nick>
+is a member of <channel>, CPRIVMSG generates a PRIVMSG towards 
+<nick>.  CPRIVMSG bypasses any anti-spam measures in place.
diff --git a/help/opers/credits b/help/opers/credits
new file mode 100644 (file)
index 0000000..5919dde
--- /dev/null
@@ -0,0 +1,10 @@
+Help File Credits
+
+Help files were written by the following people:
+
+disasta    David Daley        <disasta@go.com>
+Hwy101     W. Campbell        <wcampbel@botbay.net>
+larne      Edward Brocklesby  <ejb@leguin.org.uk>
+MoeBass    anonymous          <moe@moebass.com>
+screwedup  Jonathan Roes      <jroes@magenet.net>
+zartik     Daniel Hemmerich   <dan@spot.org>
diff --git a/help/opers/die b/help/opers/die
new file mode 100644 (file)
index 0000000..b81cce9
--- /dev/null
@@ -0,0 +1,5 @@
+DIE server.name
+
+Terminates the IRC server
+
+- Requires Oper Priv: D
diff --git a/help/opers/dline b/help/opers/dline
new file mode 100644 (file)
index 0000000..00b320e
--- /dev/null
@@ -0,0 +1,10 @@
+DLINE [duration] <ip> :[reason]
+
+Adds a DLINE to the ircd.conf or klines.conf file
+which will deny any connections from the IP address
+of the banned client.  The banned client will receive
+a message saying he/she is banned with reason [reason]
+
+Duration is optional, and is in minutes.
+
+- Requires Oper Priv: K
diff --git a/help/opers/error b/help/opers/error
new file mode 100644 (file)
index 0000000..e3f163b
--- /dev/null
@@ -0,0 +1,8 @@
+ERROR :<message>
+
+ERROR is sent by the server to clients
+or other servers when an exception occurs.
+
+If another server sends your server an
+ERROR, it will be shown to all operators
+on the server.
diff --git a/help/opers/etrace b/help/opers/etrace
new file mode 100644 (file)
index 0000000..e40e8e9
--- /dev/null
@@ -0,0 +1,16 @@
+ETRACE [-full|-v4|-v6|nick]
+
+With no argument, ETRACE gives a list of all clients connected
+to the local server, both users and operators.
+
+With -full option, ETRACE lists all clients along with the
+two unused fields sent in the USER command when they connected.
+
+When ipv6 is enabled, the -v4 and -v6 options display clients
+using ipv4 and ipv6 respectively.
+
+You may also specify a specific nickname to ETRACE.  The target
+can be a local or remote client, however the ETRACE will be "lost"
+if the remote server does not support this extension.  The
+"-full" option will be implied and should not be specified with
+it.
diff --git a/help/opers/gline b/help/opers/gline
new file mode 100644 (file)
index 0000000..3273044
--- /dev/null
@@ -0,0 +1,11 @@
+GLINE <user@host> :[reason]
+
+-- if glines are enabled --
+Attempts to add a global IRC-network wide ban on
+<user@host> for the reason [reason].
+
+It takes three different opers on three different
+servers to do the same GLINE within a short interval,
+to have a GLINE triggered for a compiled time of hours.
+
+- Requires Oper Priv: G
diff --git a/help/opers/help b/help/opers/help
new file mode 100644 (file)
index 0000000..fd20128
--- /dev/null
@@ -0,0 +1,6 @@
+HELP [topic]
+
+HELP displays the contents of the help
+file for topic requested.  If no topic is
+requested, it will perform the equivalent
+to HELP index.
diff --git a/help/opers/index b/help/opers/index
new file mode 100644 (file)
index 0000000..7ddc768
--- /dev/null
@@ -0,0 +1,24 @@
+Help topics available to opers:
+
+ACCEPT          ADMIN           AWAY            CAPAB
+CHALLENGE       CHANTRACE       CLOSE           CMODE
+CNOTICE         CONNECT         CPRIVMSG        CREDITS
+DIE             DLINE           ERROR           ETRACE
+GLINE           HELP            INDEX           INFO
+INVITE          ISON            JOIN            KICK
+KILL            KLINE           KNOCK           LINKS
+LIST            LOCOPS          LUSERS          MAP
+MASKTRACE       MODLIST         MODLOAD         MODRESTART
+MODUNLOAD       MOTD            NAMES           NICK
+NOTICE          OPER            OPERSPY         OPERWALL
+PART            PASS            PING            PONG
+POST            PRIVMSG         QUIT            REHASH
+RESTART         RESV            SCAN            SERVER
+SET             SJOIN           SNOMASK         SQUIT
+STATS           SVINFO          TESTGECOS       TESTLINE
+TESTMASK        TIME            TOPIC           TRACE
+UHELP           UMODE           UNDLINE         UNGLINE
+UNKLINE         UNREJECT        UNRESV          UNXLINE
+USER            USERHOST        USERS           VERSION
+WALLOPS         WHO             WHOIS           WHOWAS
+XLINE
diff --git a/help/opers/info b/help/opers/info
new file mode 100644 (file)
index 0000000..80d9332
--- /dev/null
@@ -0,0 +1,5 @@
+INFO
+
+INFO displays the copyright, list of authors and contributors
+to ircd, and the server configuration (as defined in config.h
+and ircd.conf).
diff --git a/help/opers/invite b/help/opers/invite
new file mode 100644 (file)
index 0000000..6e64fa3
--- /dev/null
@@ -0,0 +1,4 @@
+INVITE <nickname> <channel>
+
+INVITE sends a notice to the user that you have 
+asked him/her to come to the specified channel.
diff --git a/help/opers/ison b/help/opers/ison
new file mode 100644 (file)
index 0000000..f79de3a
--- /dev/null
@@ -0,0 +1,6 @@
+ISON <nick_A> [nick_B] :[nick_C] [nick_D]
+
+ISON will return a list of users who are present
+on the network from the list that was passed in.
+
+This command is rarely used directly.
diff --git a/help/opers/join b/help/opers/join
new file mode 100644 (file)
index 0000000..ca59f5d
--- /dev/null
@@ -0,0 +1,11 @@
+JOIN <#channel> [key]
+
+The JOIN command allows you to enter a public chat area known as
+a channel. Network wide channels are proceeded by a '#', while
+a local server channel is proceeded by an '&'. More than one
+channel may be specified, separated with commas (no spaces).
+
+If the channel has a key set, the 2nd argument must be
+given to enter. This allows channels to be password protected.
+
+See also: part, list
diff --git a/help/opers/kick b/help/opers/kick
new file mode 100644 (file)
index 0000000..a3ce273
--- /dev/null
@@ -0,0 +1,6 @@
+KICK <channel> <nick> :[msg]
+
+The KICK command will remove the specified user
+from the specified channel, using the optional
+kick message.  You must be a channel operator to
+use this command.
diff --git a/help/opers/kill b/help/opers/kill
new file mode 100644 (file)
index 0000000..b24c2aa
--- /dev/null
@@ -0,0 +1,5 @@
+KILL <nick> <reason>
+
+Disconnects user <nick> from the IRC server he/she
+is connected to with reason <reason>.
+- Requires Oper Priv: O for users not on your IRC server
diff --git a/help/opers/kline b/help/opers/kline
new file mode 100644 (file)
index 0000000..de222e5
--- /dev/null
@@ -0,0 +1,26 @@
+KLINE <user@host> :[reason] [| oper reason]
+
+Adds a KLINE to the kline.conf file which will ban the
+specified user from using this server.  The banned
+client will receive a message saying he/she is banned
+with reason [reason].
+
+If an oper reason is added (the pipe must be specified
+to seperate the fields) this will be added into the
+kline.conf but will not be shown to the user when they
+are given the kline reason.
+
+KLINE <user@ip.ip.ip.ip> :[reason] [| oper reason]
+will kline the user at the unresolved ip.
+ip.ip.ip.ip can be in CIDR form i.e. 192.168.0.0/24
+or 192.168.0.* (which is converted to CIDR form internally)
+
+For a temporary KLINE, length of kline is given in
+minutes as the first parameter i.e.
+KLINE 10 <user@host> :cool off for 10 minutes
+
+KLINE [duration] <user@host> ON irc.server :[reason] [| oper reason]
+will kline the user on irc.server if irc.server accepts
+remote klines. irc.server can contain wildcards.
+
+- Requires Oper Priv: K
diff --git a/help/opers/knock b/help/opers/knock
new file mode 100644 (file)
index 0000000..904d5a8
--- /dev/null
@@ -0,0 +1,7 @@
+KNOCK <channel>
+
+KNOCK requests access to a channel that
+for some reason is not open.
+
+KNOCK cannot be used if you are banned, the
+channel is +p, or it is open.
diff --git a/help/opers/links b/help/opers/links
new file mode 100644 (file)
index 0000000..ca27d26
--- /dev/null
@@ -0,0 +1,17 @@
+LINKS [[remote] mask]
+
+LINKS shows a list of all servers linked to the host server.
+
+With a mask parameter, LINKS will just show servers matching
+that parameter.  With the remote server parameter, LINKS will
+request the LINKS data from the remote server, matching the
+mask given.
+
+The information provided by the LINKS command can be helpful
+for determining the overall shape of the network in addition to
+its size.
+
+NOTE: the links command employs an intensive process to generate
+it's output, so sparing use is recommended.
+
+See also: connect map squit
diff --git a/help/opers/list b/help/opers/list
new file mode 100644 (file)
index 0000000..0cc3ae7
--- /dev/null
@@ -0,0 +1,16 @@
+LIST [#channel]|[modifiers]
+
+Without any arguments, LIST will give an entire list of all
+channels which are not set as secret (+s). The list will be in
+the form:
+
+  <#channel> <amount of users> :[topic]
+
+If an argument supplied is a channel name, LIST will give just
+the statistics for the given channel.
+
+Modifiers are also supported, seperated by a comma:
+  <n - List channels with less than n users
+  >n - List channels with more than n users
+
+eg LIST <100,>20
diff --git a/help/opers/locops b/help/opers/locops
new file mode 100644 (file)
index 0000000..e7ef5d4
--- /dev/null
@@ -0,0 +1,4 @@
+LOCOPS :<message>
+
+Sends an LOCOPS message of <message> to all
+opers on local server who are umode +l
diff --git a/help/opers/lusers b/help/opers/lusers
new file mode 100644 (file)
index 0000000..88aa15f
--- /dev/null
@@ -0,0 +1,8 @@
+LUSERS [mask [remoteserver]]
+
+LUSERS will display client count statistics.
+If a remote server is specified, it will
+request the information from that server.
+The mask parameter is obsolete but still
+needs to be used when querying a remote
+server.
diff --git a/help/opers/map b/help/opers/map
new file mode 100644 (file)
index 0000000..8acc02e
--- /dev/null
@@ -0,0 +1,4 @@
+MAP
+
+MAP shows a graphical map of the network with user
+counts and TS6 SIDs (if known).
diff --git a/help/opers/masktrace b/help/opers/masktrace
new file mode 100644 (file)
index 0000000..05b7fb8
--- /dev/null
@@ -0,0 +1,9 @@
+MASKTRACE [<nick>!]<user>@<host> :<gecos>
+
+Outputs a list of local users matching the given masks
+in ETRACE format, with the classname replaced by
+the server the users are on. Gecos uses the same
+wildcards as xlines; nick, user and host use just
+? and *.
+
+Supports using CIDR ip masks as a hostname.
diff --git a/help/opers/modlist b/help/opers/modlist
new file mode 100644 (file)
index 0000000..0abc907
--- /dev/null
@@ -0,0 +1,7 @@
+MODLIST [match string]
+
+-- List the modules that are currently loaded into the
+ircd, along with their address and version.
+When a match string is provided, modlist only prints
+modules with names matching the match string.
+NOTE:  Restricted to admins only
diff --git a/help/opers/modload b/help/opers/modload
new file mode 100644 (file)
index 0000000..ee2bb8b
--- /dev/null
@@ -0,0 +1,7 @@
+MODLOAD <[path/]module.so>
+
+-- Load a module into the ircd
+the optional path can be an absolute path
+from / or from the IRCD_PREFIX
+(ie modules/autoload/m_users.so)
+NOTE:  Restricted to admins only
diff --git a/help/opers/modrestart b/help/opers/modrestart
new file mode 100644 (file)
index 0000000..d78b531
--- /dev/null
@@ -0,0 +1,6 @@
+MODRESTART
+
+-- Reload all modules into the ircd
+All modules are unloaded, then those in modules/autoload
+are loaded
+NOTE:  Restricted to admins only
diff --git a/help/opers/modunload b/help/opers/modunload
new file mode 100644 (file)
index 0000000..6bfcf1e
--- /dev/null
@@ -0,0 +1,7 @@
+MODUNLOAD <module.so>
+
+-- Unload a module from the ircd
+Use just the module name, the path is not needed.
+When a module is unloaded, all commands associated
+with it are unloaded as well.
+NOTE:  Restricted to admins only
diff --git a/help/opers/motd b/help/opers/motd
new file mode 100644 (file)
index 0000000..421e06e
--- /dev/null
@@ -0,0 +1,5 @@
+MOTD [servername]
+
+MOTD will display the message of the day for the
+server name specified, or the local server if there
+was no parameter.
diff --git a/help/opers/names b/help/opers/names
new file mode 100644 (file)
index 0000000..76e72b6
--- /dev/null
@@ -0,0 +1,11 @@
+NAMES [channel]
+
+With no channel argument, NAMES shows the names (nicks) of all clients
+logged in to the network that do not have +i flag.
+
+With the #channel argument, it displays the nicks on that channel,
+also respecting the +i flag of each client. If the channel specified
+is a channel that the issuing client is currently in, all nicks are
+listed in similar fashion to when the user first joins a channel.
+
+See also: join
diff --git a/help/opers/nick b/help/opers/nick
new file mode 100644 (file)
index 0000000..32d56d1
--- /dev/null
@@ -0,0 +1,7 @@
+NICK <nickname>
+
+When first connected to the IRC server, NICK is required to
+set the client's nickname.
+
+NICK will also change the client's nickname once a connection
+has been established.
diff --git a/help/opers/notice b/help/opers/notice
new file mode 100644 (file)
index 0000000..5795d67
--- /dev/null
@@ -0,0 +1,35 @@
+NOTICE <nick|channel> :message
+
+NOTICE will send a notice message to the
+user or channel specified.
+
+NOTICE supports the following prefixes for sending
+messages to specific clients in a channel:
+
+@ - channel operators only
++ - channel operators and voiced users
+
+Two other targets are permitted:
+
+$$servermask - Send a message to a server or set of
+               servers
+$#hostmask   - Send a message to users matching the
+               hostmask specified.
+
+These two are operator only.
+
+The nick can be extended to fit into the following
+syntax:
+
+username[%hostname]@servername
+
+This syntax (without the hostname) is used to securely
+send a message to a service or a bot.
+
+An extension of this is the syntax to send to all opers
+on a server.
+
+opers@servername
+
+In Hybrid 7, all opers on a server will see a message that
+looks like a modified WALLOPS
diff --git a/help/opers/oper b/help/opers/oper
new file mode 100644 (file)
index 0000000..08962bf
--- /dev/null
@@ -0,0 +1,8 @@
+OPER <name> <password>
+
+The OPER command requires two arguments to be given. The first
+argument is the name of the operator as specified in the
+configuration file. The second argument is the password for
+the operator matching the name and host.
+
+The operator privileges are shown on a sucessful OPER.
diff --git a/help/opers/operspy b/help/opers/operspy
new file mode 100644 (file)
index 0000000..0f02c2b
--- /dev/null
@@ -0,0 +1,13 @@
+OPERSPY
+
+Opers with the "oper_spy" flag will be allowed uses of the following
+commands if they are compiled in.  Usage will be sent to +Z and all 
+other servers.
+
+whois !nick     - Gives a full output of channels the user is in.
+who !mask       - Lists all users networkwide whose nick, ident, host,
+                  server or gecos match the mask.
+who !#channel   - Gives a full output of users on the channel.
+mode !#channel  - Gives the full modes of a channel including any keys.
+chantrace !#channel - Gives full output despite not being on channel.
+masktrace !nick!user@host :gecos - Lists matching users on all servers.
diff --git a/help/opers/operwall b/help/opers/operwall
new file mode 100644 (file)
index 0000000..e331548
--- /dev/null
@@ -0,0 +1,4 @@
+OPERWALL :<message>
+
+Sends an OPERWALL message of <message> to all
+opers who are umode +z
diff --git a/help/opers/part b/help/opers/part
new file mode 100644 (file)
index 0000000..50eac68
--- /dev/null
@@ -0,0 +1,10 @@
+PART <#channel> :[part message]
+
+PART requires at least a channel argument to be given. It will
+exit the client from the specified channel. More than one
+channel may be specified, separated with commas (no spaces).
+
+An optional part message may be given to be displayed to the
+channel.
+
+See also: join
diff --git a/help/opers/pass b/help/opers/pass
new file mode 100644 (file)
index 0000000..d4a618d
--- /dev/null
@@ -0,0 +1,6 @@
+PASS <password>
+
+PASS is used during registration to access
+a password protected auth {} block.
+
+PASS is also used during server registration.
diff --git a/help/opers/ping b/help/opers/ping
new file mode 100644 (file)
index 0000000..9de6ed5
--- /dev/null
@@ -0,0 +1,6 @@
+PING <source> :<target>
+
+PING will request a PONG from the target.  If a
+user or operator issues this command, the source
+will always be turned into the nick that issued
+the PING.
diff --git a/help/opers/pong b/help/opers/pong
new file mode 100644 (file)
index 0000000..c05c65a
--- /dev/null
@@ -0,0 +1,6 @@
+PONG <pinged-client> :<source-client>
+
+PONG is the response to a PING command.  The
+source client is the user or server that issued
+the command, and the pinged client is the
+user or server that received the PING.
diff --git a/help/opers/post b/help/opers/post
new file mode 100644 (file)
index 0000000..362ca3d
--- /dev/null
@@ -0,0 +1,5 @@
+POST
+
+The POST command is used to help protect against
+insecure HTTP proxies.  Any proxy that sends a POST
+command during registration will be exited.
diff --git a/help/opers/privmsg b/help/opers/privmsg
new file mode 100644 (file)
index 0000000..c6e5d54
--- /dev/null
@@ -0,0 +1,35 @@
+PRIVMSG <nick|channel> :message
+
+PRIVMSG will send a standard message to the
+user or channel specified.
+
+PRIVMSG supports the following prefixes for sending
+messages to specific clients in a channel:
+
+@ - channel operators only
++ - channel operators and voiced users
+
+Two other targets are permitted:
+
+$$servermask - Send a message to a server or set of
+               servers
+$#hostmask   - Send a message to users matching the
+               hostmask specified.
+
+These two are operator only.
+
+The nick can be extended to fit into the following
+syntax:
+
+username[%hostname]@servername
+
+This syntax (without the hostname) is used to securely
+send a message to a service or a bot.
+
+An extension of this is the syntax to send to all opers
+on a server.
+
+opers@servername
+
+In Hybrid 7, all opers on a server will see a message that
+looks like a modified WALLOPS
diff --git a/help/opers/quit b/help/opers/quit
new file mode 100644 (file)
index 0000000..b6d0735
--- /dev/null
@@ -0,0 +1,5 @@
+QUIT :[quit message]
+
+QUIT sends a message to the IRC server letting it know you would 
+like to disconnect.  The quit message will be displayed to the 
+users in the channels you were in when you are disconnected. 
diff --git a/help/opers/rehash b/help/opers/rehash
new file mode 100644 (file)
index 0000000..b63b278
--- /dev/null
@@ -0,0 +1,28 @@
+REHASH [option]
+
+When no [option] is given, ircd will re-read the
+ircd.conf file.
+
+[option] can be one of the following:
+  BANS     - Re-reads kline.conf, dline.conf, resv.conf and xline.conf
+  DNS      - Re-read the /etc/resolv.conf file
+  GLINES   - Clears G Lines
+  HELP     - Re-reads help files
+  MOTD     - Re-reads MOTD file
+  NICKDELAY - Clears delayed nicks
+  OMOTD    - Re-reads Oper MOTD file
+  PGLINES  - Clears pending G Lines
+  REJECTCACHE - Clears the reject cache
+  TDLINES  - Clears temporary D Lines
+  TKLINES  - Clears temporary K Lines
+  TRESVS   - Clears temporary nick and channel resvs
+  TXLINES  - Clears temporary X Lines
+
+- Requires Oper Priv: H
+
+REHASH [option] irc.server
+
+Rehashes [option], or the config file if none given, on irc.server if
+irc.server accepts remote rehashes.
+
+- Requires Oper Priv: HB
diff --git a/help/opers/restart b/help/opers/restart
new file mode 100644 (file)
index 0000000..868a470
--- /dev/null
@@ -0,0 +1,5 @@
+RESTART server.name
+
+Restarts the IRC server.
+
+- Requires Oper Priv: D
diff --git a/help/opers/resv b/help/opers/resv
new file mode 100644 (file)
index 0000000..7609e00
--- /dev/null
@@ -0,0 +1,11 @@
+RESV [time] <channel|nick> :<reason>
+
+Reserves a channel or nickname from use.  If [time] is not specified this 
+is added to resv.conf, otherwise is temporary for [time] minutes.
+
+Nick resvs accept the same wildcard chars as xlines.
+Channel resvs only use exact string comparisons.
+
+RESV [time] <channel|nick> ON <server> :<reason>
+
+Will attempt to set the RESV on <server> if <server> accepts remote RESVs.
diff --git a/help/opers/scan b/help/opers/scan
new file mode 100644 (file)
index 0000000..bca2524
--- /dev/null
@@ -0,0 +1,16 @@
+SCAN UMODES +<modes>-<modes> [NO-LIST] [LIST] [GLOBAL]
+            [LIST-MAX <number>] [MASK <nick!user@host>]
+
+Searches the local server or network for users that have the
+umodes given with + and do not have the umodes given with -.
+NO-LIST disables the listing of matching users and only
+shows the count. LIST enables the listing (default). GLOBAL
+extends the search to the entire network instead of local
+users only. LIST-MAX limits the listing of matching users to
+the given amount. MASK causes only users matching the given
+nick!user@host mask to be selected. Only the displayed host
+is considered, not the IP address or real host behind
+dynamic spoofs.
+
+Network searches where a listing is given or the MASK option
+is used are operspy commands.
diff --git a/help/opers/server b/help/opers/server
new file mode 100644 (file)
index 0000000..b618436
--- /dev/null
@@ -0,0 +1 @@
+SERVER - Server to Server Protocol Command.
diff --git a/help/opers/set b/help/opers/set
new file mode 100644 (file)
index 0000000..8968856
--- /dev/null
@@ -0,0 +1,31 @@
+SET <option> <value>
+
+<option> can be one of the following:
+  ADMINSTRING - Sets string shown in WHOIS for admins
+  AUTOCONN    - Sets auto-connect on or off for a particular
+                server
+  AUTOCONNALL - Sets auto-connect on or off for all servers
+  FLOODCOUNT  - The number of lines allowed before
+                throttling a connection due to flooding
+                Note that this variable is used for both
+                channels and clients
+  IDENTTIMEOUT- Timeout for requesting ident from a client
+  IDLETIME    - The number of seconds a client can be idle
+                before disconnecting them
+  MAX         - Sets the number of max connections
+                to <value>.  (This number cannot exceed
+                HARD_FDLIMIT in config.h)
+  OPERSTRING  - Sets string shown in WHOIS for opers
+  SPAMNUM     - Sets how many join/parts to channels
+                constitutes a possible spambot.
+  SPAMTIME    - Below this time on a channel
+                counts as a join/part as above.
+  SPLITMODE   - Sets splitmode to <value>:
+                 ON   - splitmode is permanently on
+                 OFF  - splitmode is permanently off
+                 AUTO - ircd chooses splitmode based on 
+                        SPLITUSERS and SPLITNUM
+  SPLITUSERS  - Sets the minimum amount of users needed to
+                deactivate automatic splitmode.
+  SPLITNUM    - Sets the minimum amount of servers needed to
+                deactivate automatic splitmode.
diff --git a/help/opers/sjoin b/help/opers/sjoin
new file mode 100644 (file)
index 0000000..026ab5f
--- /dev/null
@@ -0,0 +1 @@
+SJOIN - Server to Server Protocol Command.
diff --git a/help/opers/snomask b/help/opers/snomask
new file mode 100644 (file)
index 0000000..09f28c4
--- /dev/null
@@ -0,0 +1,19 @@
+MODE <nick> +s <+|-><modes>
+
+Server notice masks:
+
+    SNOMASK     DESCRIPTION
+-----------------------------------------------------------------
+       +b     - Possible bot warnings
+       +c     - Local client connections and exits
+       +C     - Extended local client connections and exits
+       +d     - Server debug messages
+       +f     - 'I-line is full' notices
+       +k     - Server and service kill messages
+       +n     - Local client nick changes
+       +r     - 'Rejected' client notices
+       +s     - Generic server messages and oper kills
+       +u     - Unauthorised client connections
+       +x     - New server introduction and split messages
+       +y     - Juped channel join attempts, etc
+       +Z     - Operspy notices
diff --git a/help/opers/squit b/help/opers/squit
new file mode 100644 (file)
index 0000000..30718de
--- /dev/null
@@ -0,0 +1,4 @@
+SQUIT <server> [reason]
+
+Splits <server> away from your side of the net with [reason].
+- Requires Oper Priv: R for servers not connected to you
diff --git a/help/opers/stats b/help/opers/stats
new file mode 100644 (file)
index 0000000..7068c1b
--- /dev/null
@@ -0,0 +1,44 @@
+STATS <letter> [server|nick]
+
+Queries server [server] (or your own server if no
+server parameter is given) for info corresponding to
+<letter>.
+
+       (X = Admin only.)
+LETTER (* = Oper only.)
+------ (^ = Can be configured to be oper only.)
+X A - Shows DNS servers
+X b - Shows active nick delays
+X B - Shows hash statistics
+^ c - Shows connect blocks (Old C:/N: lines)
+* d - Shows temporary D lines
+* D - Shows D lines
+* e - Shows exemptions to D lines
+X E - Shows Events
+X f - Shows File Descriptors
+* g - Shows pending G lines
+* G - Shows active G lines
+^ h - Shows hub_mask/leaf_mask (Old H:/L: lines)
+^ i - Shows auth blocks (Old I: lines)
+^ K - Shows K lines (or matched klines)
+^ k - Shows temporary K lines (or matched temp klines)
+  L - Shows IP and generic info about [nick]
+  l - Shows hostname and generic info about [nick]
+  m - Shows commands and their usage
+  n - Shows DNS blacklists
+^ o - Shows O/o lines
+^ P - Shows configured ports
+  p - Shows online opers
+* q - Shows temporary resv'd nicks and channels
+* Q - Shows resv'd nicks and channels
+* r - Shows resource usage by ircd
+* t - Shows generic server stats
+* U - Shows shared blocks (Old U: lines)
+  u - Shows server uptime
+^ v - Shows connected servers and brief status information
+* x - Shows temporary gecos bans
+* X - Shows gecos bans (Old X: lines)
+^ y - Shows connection classes (Old Y: lines)
+* z - Shows memory stats
+* Z - Shows ziplinks stats
+^ ? - Shows connected servers and sendq info about them
diff --git a/help/opers/svinfo b/help/opers/svinfo
new file mode 100644 (file)
index 0000000..936db99
--- /dev/null
@@ -0,0 +1 @@
+SVINFO - Server to Server Protocol Command.
diff --git a/help/opers/testgecos b/help/opers/testgecos
new file mode 100644 (file)
index 0000000..f131a8a
--- /dev/null
@@ -0,0 +1,3 @@
+TESTGECOS <gecos>
+
+Looks for matching xlines for the given gecos.
diff --git a/help/opers/testline b/help/opers/testline
new file mode 100644 (file)
index 0000000..5efbd8d
--- /dev/null
@@ -0,0 +1,8 @@
+TESTLINE [[nick!]user@]host
+
+Looks up given mask, looking for any matching I/K/D/G lines.
+If username is not specified, it will look up "dummy@host".
+If nickname is specified it will also search for RESVs.
+
+This command will not perform dns lookups on a host, for best
+results you must testline a host and its IP form.
diff --git a/help/opers/testmask b/help/opers/testmask
new file mode 100644 (file)
index 0000000..699a918
--- /dev/null
@@ -0,0 +1,5 @@
+TESTMASK <[nick!]user@host> [:gecos]
+
+Will test the given nick!user@host gecos mask, reporting how many local
+and global clients match the given mask.  Supports using CIDR ip masks
+as a host.
diff --git a/help/opers/time b/help/opers/time
new file mode 100644 (file)
index 0000000..40d79a1
--- /dev/null
@@ -0,0 +1,6 @@
+TIME [server]
+
+The TIME command will return the server's local date and time.
+
+If an argument is supplied, the time for the server specified
+will be returned.
diff --git a/help/opers/topic b/help/opers/topic
new file mode 100644 (file)
index 0000000..eb7e3a3
--- /dev/null
@@ -0,0 +1,10 @@
+TOPIC <#channel> :[new topic]
+
+With only a channel argument, TOPIC shows the current topic of
+the specified channel.
+
+With a second argument, it changes the topic on that channel to
+<new topic>.  If the channel is +t, only chanops may change the
+topic.
+
+See also: cmode
diff --git a/help/opers/trace b/help/opers/trace
new file mode 100644 (file)
index 0000000..cfcb871
--- /dev/null
@@ -0,0 +1,17 @@
+TRACE [server | nick] [location]
+
+With no argument, TRACE gives a list of all clients connected
+to the local server, both users and operators.
+
+With one argument which is a server, TRACE displays the path 
+to the specified server, and all servers, opers and -i users
+on that server.
+
+Nonopers can only see themselves, opers and servers in the
+first two forms.
+
+With one argument which is a client, TRACE displays the
+path to that client, and that client's information.
+
+If location is given, the command is executed on that server;
+no path is displayed.
diff --git a/help/opers/uhelp b/help/opers/uhelp
new file mode 100644 (file)
index 0000000..74ba8ce
--- /dev/null
@@ -0,0 +1,5 @@
+UHELP [topic]
+
+UHELP allows an operator to view help topics
+for users without opening a second client
+or removing their operator status.
diff --git a/help/opers/umode b/help/opers/umode
new file mode 100644 (file)
index 0000000..22109b5
--- /dev/null
@@ -0,0 +1,18 @@
+MODE <nick> <+|-><modes>
+
+Usermodes: (* designates that the umode is oper only)
+
+     USERMODE     DESCRIPTION
+-----------------------------------------------------------------
+         +i     - Designates this client 'invisible'.
+         +g     - "caller id" mode only allow accept clients to message you
+         +w     - Can see oper and server wallops.
+         +o     - Designates this client is an IRC Operator.
+                  Use the /oper command to attain this.
+       * +a     - Is marked as a server admin in whois.
+       * +l     - Can see oper locops (local wallops).
+       * +s     - Can see server notices (see /quote help snomask).
+       * +z     - Can see operwalls.
+         +D     - Deaf - ignores all channel messages.
+         +Q     - Prevents you from being affected by channel forwarding.
+         +R     - Prevents non accept unidentified users from messaging you.
diff --git a/help/opers/undline b/help/opers/undline
new file mode 100644 (file)
index 0000000..b2b7b10
--- /dev/null
@@ -0,0 +1,5 @@
+UNDLINE <ip>
+
+Will attempt to undline the given <ip>
+
+- Requires Oper Priv: U
diff --git a/help/opers/ungline b/help/opers/ungline
new file mode 100644 (file)
index 0000000..b639fa6
--- /dev/null
@@ -0,0 +1,8 @@
+UNGLINE <user@host>
+
+-- if glines are enabled --
+Will attempt to remove gline matching <user@host>
+This will only remove the gline from YOUR server, it
+does not try to remove it globally.
+
+- Requires Oper Privs: G and U
diff --git a/help/opers/unkline b/help/opers/unkline
new file mode 100644 (file)
index 0000000..ad1b9e6
--- /dev/null
@@ -0,0 +1,10 @@
+UNKLINE <user@host>
+
+Will attempt to unkline the given <user@host>
+Will unkline a temporary kline.
+
+UNKLINE <user@host> ON irc.server will unkline
+the user on irc.server if irc.server accepts
+remote unklines.
+
+- Requires Oper Priv: U
diff --git a/help/opers/unreject b/help/opers/unreject
new file mode 100644 (file)
index 0000000..6d405fe
--- /dev/null
@@ -0,0 +1,6 @@
+UNREJECT <ip>
+
+Removes an IP address from the reject cache.  IP
+addresses are added to the reject cache if they are
+rejected (e.g. connect and are K-lined) several
+times in a short period of time.
diff --git a/help/opers/unresv b/help/opers/unresv
new file mode 100644 (file)
index 0000000..eba5a9b
--- /dev/null
@@ -0,0 +1,6 @@
+UNRESV <channel|nick>
+
+-- Remove a RESV on a channel or nick
+Will attempt to remove the resv for the given
+channel/nick.  If the resv is ircd.conf based, 
+the resv will not be removed.
diff --git a/help/opers/unxline b/help/opers/unxline
new file mode 100644 (file)
index 0000000..fb556b8
--- /dev/null
@@ -0,0 +1,10 @@
+UNXLINE <gecos>
+
+Will attempt to unxline the given <gecos>
+
+
+UNXLINE <gecos> ON <server>
+
+Will attempt to unxline the given <gecos> on <server>.
+
+- Requires Oper Priv: X
diff --git a/help/opers/user b/help/opers/user
new file mode 100644 (file)
index 0000000..f95bcdc
--- /dev/null
@@ -0,0 +1,7 @@
+USER <username> <unused> <unused> :<real name/gecos>
+
+USER is used during registration to set your gecos
+and to set your username if the server cannot get
+a valid ident response.  The second and third fields
+are not used, but there must be something in them.
+The reason is backwards compatibility
diff --git a/help/opers/userhost b/help/opers/userhost
new file mode 100644 (file)
index 0000000..f776fcd
--- /dev/null
@@ -0,0 +1,10 @@
+USERHOST <nick>
+
+USERHOST displays the username, hostname, 
+operator status, and presence of valid ident of
+the specified nickname.
+
+If you use USERHOST on yourself, the hostname
+is replaced with the IP you are connecting from.
+This is needed to provide DCC support for spoofed
+hostnames.
diff --git a/help/opers/users b/help/opers/users
new file mode 100644 (file)
index 0000000..bb56456
--- /dev/null
@@ -0,0 +1,6 @@
+USERS [remoteserver]
+
+USERS will display the local and global current
+and maximum user statistics for the specified
+server, or the local server if there was no
+parameter.
diff --git a/help/opers/version b/help/opers/version
new file mode 100644 (file)
index 0000000..af6f385
--- /dev/null
@@ -0,0 +1,4 @@
+VERSION [servername]
+
+VERSION will display the server version of the specified
+server, or the local server if there was no parameter.
diff --git a/help/opers/wallops b/help/opers/wallops
new file mode 100644 (file)
index 0000000..3f1e742
--- /dev/null
@@ -0,0 +1,6 @@
+WALLOPS :<message>
+
+Sends a WALLOPS message of <message> to all users
+who are umode +w (including non-opers).
+
+Server sent WALLOPS go to all opers who are umode +w.
diff --git a/help/opers/who b/help/opers/who
new file mode 100644 (file)
index 0000000..147f780
--- /dev/null
@@ -0,0 +1,35 @@
+WHO <#channel|user>
+
+The WHO command displays information about a user, 
+such as their GECOS information, their user@host, 
+whether they are an IRC operator or not, etc.  A
+sample WHO result from a command issued like 
+"WHO pokey" may look something like this:
+
+#lamers pokey H pokey@ppp.newbies.net :0 Jim Jones
+
+The first field indicates the last channel the user
+has joined.  The second is the user's nickname.  
+The third field describes the status information about 
+the user.  The possible combinations for this field 
+are listed below:
+
+H       -       The user is not away.
+G       -       The user is set away.
+*       -       The user is an IRC operator.
+@       -       The user is a channel op in the channel listed
+                in the first field.
++       -       The user is voiced in the channel listed.
+
+The next field contains the username@host of the user.  
+The final field displays the number of server hops and 
+the user's GECOS information.
+
+This command may be executed on a channel, such as
+"WHO #lamers"  The output will consist of WHO 
+listings for each user on the channel.
+
+This command may also be used in conjunction with wildcards 
+such as * and ?.
+
+See also: whois, userhost
diff --git a/help/opers/whois b/help/opers/whois
new file mode 100644 (file)
index 0000000..b45c19b
--- /dev/null
@@ -0,0 +1,8 @@
+WHOIS [remoteserver|nick] nick
+
+WHOIS will display detailed user information for
+the specified nick.  If the first parameter is
+specified, WHOIS will display information from
+the specified server, or the server that the
+user is on.  This is how to remotely see
+idle time and away status.
diff --git a/help/opers/whowas b/help/opers/whowas
new file mode 100644 (file)
index 0000000..e034dd2
--- /dev/null
@@ -0,0 +1,8 @@
+WHOWAS <nick>
+
+WHOWAS will show you the last known host and whois
+information for the specified nick.  Depending on the
+number of times they have connected to the network, there
+may be more than one listing for a specific user.
+
+The WHOWAS data will expire after time.
diff --git a/help/opers/xline b/help/opers/xline
new file mode 100644 (file)
index 0000000..2c976f1
--- /dev/null
@@ -0,0 +1,28 @@
+XLINE [time] <gecos> :<reason>
+
+Bans by gecos (aka 'real name') field.  If [time] is not specified
+this is added to xline.conf, otherwise is temporary for [time] 
+minutes.
+
+Eg. /quote xline eggdrop?bot :no bots
+
+The <gecos> field contains certain special characters:
+  ? - Match any single character
+  * - Many any characters
+  @ - Match any letter [A-Za-z]
+  # - Match any digit [0-9]
+
+To use a literal one of these characters, escape it with '\'.  A 
+literal '\' character must also be escaped.  You may also insert \s
+which will be converted into a space.
+
+If the <gecos> field is purely numeric (ie "123") then the time
+field must be specified.  "0" must be used to denote a permanent 
+numeric XLINE.
+
+XLINE [time] <gecos> ON <server> :<reason>
+
+Will attempt to set the XLINE on <server> if <server> accepts
+remote xlines.
+
+- Requires Oper Priv: X
diff --git a/help/users/index b/help/users/index
new file mode 100644 (file)
index 0000000..654cf5f
--- /dev/null
@@ -0,0 +1,13 @@
+Help topics available to users:
+
+ACCEPT          ADMIN           AWAY            CHALLENGE
+CMODE           CNOTICE         CPRIVMSG        CREDITS
+ERROR           HELP            INDEX           INFO
+INVITE          ISON            JOIN            KICK
+KNOCK           LINKS           LIST            LUSERS
+MAP             MOTD            NAMES           NICK
+NOTICE          OPER            PART            PASS
+PING            PONG            PRIVMSG         QUIT
+STATS           TIME            TOPIC           TRACE
+UMODE           USER            USERHOST        USERS
+VERSION         WHO             WHOIS           WHOWAS
diff --git a/help/users/info b/help/users/info
new file mode 100644 (file)
index 0000000..d76ed0a
--- /dev/null
@@ -0,0 +1,4 @@
+INFO
+
+INFO displays the copyright, authors and contributors list
+for ircd.
diff --git a/help/users/notice b/help/users/notice
new file mode 100644 (file)
index 0000000..3dcf7e0
--- /dev/null
@@ -0,0 +1,18 @@
+NOTICE <nick|channel> :message
+
+NOTICE will send a notice message to the
+user or channel specified.
+
+NOTICE supports the following prefixes for sending
+messages to specific clients in a channel:
+
+@ - channel operators only
++ - channel operators and voiced users
+
+The nick can be extended to fit into the following
+syntax:
+
+username@servername
+
+This syntax is used to securely send a notice to a
+service or a bot.
diff --git a/help/users/privmsg b/help/users/privmsg
new file mode 100644 (file)
index 0000000..99a9096
--- /dev/null
@@ -0,0 +1,18 @@
+PRIVMSG <nick|channel> :message
+
+PRIVMSG will send a standard message to the
+user or channel specified.
+
+PRIVMSG supports the following prefixes for sending
+messages to specific clients in a channel:
+
+@ - channel operators only
++ - channel operators and voiced users
+
+The nick can be extended to fit into the following
+syntax:
+
+username@servername
+
+This syntax is used to securely send a message to a
+service or a bot.
diff --git a/help/users/stats b/help/users/stats
new file mode 100644 (file)
index 0000000..0370a55
--- /dev/null
@@ -0,0 +1,24 @@
+STATS <letter> [server|nick]
+
+Queries server [server] (or your own server if no
+server parameter is given) for info corresponding to
+<letter>.
+
+LETTER
+------ (^ = Can be configured to be oper only.)
+^ c - Shows connect blocks
+^ h - Shows hub_mask/leaf_mask (Old H:/L: lines)
+^ i - Shows auth blocks (or matched auth block)
+^ K - Shows K lines (or matched klines)
+^ k - Shows temporary K lines (or matched temp klines)
+  L - Shows IP and generic info about [nick]
+  l - Shows hostname and generic info about [nick]
+  m - Shows commands and their usage
+  n - Shows DNS blacklists
+^ o - Shows O/o lines
+^ P - Shows configured ports
+  p - Shows online opers
+  u - Shows server uptime
+^ v - Shows connected servers and brief status information
+^ y - Shows connection classes (Old Y: lines)
+^ ? - Shows connected servers and sendq info about them
diff --git a/help/users/umode b/help/users/umode
new file mode 100644 (file)
index 0000000..9f55fd6
--- /dev/null
@@ -0,0 +1,14 @@
+MODE <nick> <+|-><modes>
+
+Usermodes:
+
+     USERMODE     DESCRIPTION
+-----------------------------------------------------------------
+         +o     - Designates this client is an IRC Operator.
+                  Use the /oper command to attain this.
+         +i     - Designates this client 'invisible'.
+         +g     - "caller id" mode only allow accept clients to message you
+         +w     - Can see oper wallops.
+         +D     - Deaf - ignores all channel messages.
+         +Q     - Prevents you from being affected by channel forwarding.
+         +R     - Prevents non accept unidentified users from messaging you.
diff --git a/include/.cvsignore b/include/.cvsignore
new file mode 100644 (file)
index 0000000..b000922
--- /dev/null
@@ -0,0 +1,2 @@
+Makefile
+setup.h
diff --git a/include/.indent.pro b/include/.indent.pro
new file mode 100644 (file)
index 0000000..ed83a1b
--- /dev/null
@@ -0,0 +1 @@
+-i8 -bli0 -cs -ut -nsai -nsaw -nsaf -npcs -nprs -l100
diff --git a/include/blacklist.h b/include/blacklist.h
new file mode 100644 (file)
index 0000000..2fde255
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ *  charybdis: A slightly useful ircd.
+ *  blacklist.h: Manages DNS blacklist entries and lookups
+ *
+ *  Copyright (C) 2006 charybdis development 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: blacklist.h 2023 2006-09-02 23:47:27Z jilles $
+ */
+
+#ifndef _BLACKLIST_H_
+#define _BLACKLIST_H_
+
+/* A configured DNSBL */
+struct Blacklist {
+       unsigned int status;    /* If CONF_ILLEGAL, delete when no clients */
+       int refcount;
+       char host[HOSTLEN];
+       char reject_reason[IRCD_BUFSIZE];
+       unsigned int hits;
+};
+
+/* A lookup in progress for a particular DNSBL for a particular client */
+struct BlacklistClient {
+       struct Blacklist *blacklist;
+       struct Client *client_p;
+       struct DNSQuery dns_query;
+       dlink_node node;
+};
+
+/* public interfaces */
+struct Blacklist *new_blacklist(char *host, char *reject_entry);
+void lookup_blacklists(struct Client *client_p);
+void abort_blacklist_queries(struct Client *client_p);
+void unref_blacklist(struct Blacklist *blptr);
+void destroy_blacklists(void);
+
+extern dlink_list blacklist_list;
+
+#endif
diff --git a/include/cache.h b/include/cache.h
new file mode 100644 (file)
index 0000000..a3485ec
--- /dev/null
@@ -0,0 +1,51 @@
+/* $Id: cache.h 6 2005-09-10 01:02:21Z nenolod $ */
+#ifndef INCLUDED_CACHE_H
+#define INCLUDED_CACHE_H
+
+#include "client.h"
+#include "tools.h"
+
+#define HELP_MAX       100
+
+#define CACHELINELEN   81
+#define CACHEFILELEN   30
+/* two servernames, a gecos, three spaces, ":1", '\0' */
+#define LINKSLINELEN   (HOSTLEN + HOSTLEN + REALLEN + 6)
+
+#define HELP_USER      0x001
+#define HELP_OPER      0x002
+
+struct Client;
+
+struct cachefile
+{
+       char name[CACHEFILELEN];
+       dlink_list contents;
+       int flags;
+};
+
+struct cacheline
+{
+       char data[CACHELINELEN];
+       dlink_node linenode;
+};
+
+extern struct cachefile *user_motd;
+extern struct cachefile *oper_motd;
+extern struct cacheline *emptyline;
+extern dlink_list links_cache_list;
+
+extern char user_motd_changed[MAX_DATE_STRING];
+
+extern void init_cache(void);
+extern struct cachefile *cache_file(const char *, const char *, int);
+extern void cache_links(void *unused);
+extern void free_cachefile(struct cachefile *);
+
+extern void load_help(void);
+
+extern void send_user_motd(struct Client *);
+extern void send_oper_motd(struct Client *);
+
+#endif
+
diff --git a/include/channel.h b/include/channel.h
new file mode 100644 (file)
index 0000000..ce9ef00
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  channel.h: The ircd channel header.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: channel.h 2727 2006-11-09 23:48:45Z jilles $
+ */
+
+#ifndef INCLUDED_channel_h
+#define INCLUDED_channel_h
+#include "config.h"            /* config settings */
+#include "ircd_defs.h"         /* buffer sizes */
+
+#define MODEBUFLEN      200
+
+/* Maximum mode changes allowed per client, per server is different */
+#define MAXMODEPARAMS   4
+#define MAXMODEPARAMSSERV 10
+
+struct Client;
+
+/* mode structure for channels */
+struct Mode
+{
+       unsigned int mode;
+       int limit;
+       char key[KEYLEN];
+       unsigned int join_num;
+       unsigned int join_time;
+       char forward[LOC_CHANNELLEN + 1];
+};
+
+/* channel structure */
+struct Channel
+{
+       dlink_node node;
+       struct Mode mode;
+       char *topic;
+       char *topic_info;
+       time_t topic_time;
+       time_t users_last;      /* when last user was in channel */
+       time_t last_knock;      /* don't allow knock to flood */
+
+       dlink_list members;     /* channel members */
+       dlink_list locmembers;  /* local channel members */
+
+       dlink_list invites;
+       dlink_list banlist;
+       dlink_list exceptlist;
+       dlink_list invexlist;
+       dlink_list quietlist;
+
+       time_t first_received_message_time;     /* channel flood control */
+       int received_number_of_privmsgs;
+       int flood_noticed;
+
+       unsigned int join_count;  /* joins within delta */
+       unsigned int join_delta;  /* last ts of join */
+
+       unsigned long bants;
+       time_t channelts;
+       char *chname;
+};
+
+struct membership
+{
+       dlink_node channode;
+       dlink_node locchannode;
+       dlink_node usernode;
+
+       struct Channel *chptr;
+       struct Client *client_p;
+       unsigned int flags;
+
+       unsigned long bants;
+};
+
+#define BANLEN NICKLEN+USERLEN+HOSTLEN+6
+struct Ban
+{
+       char *banstr;
+       char *who;
+       time_t when;
+       dlink_node node;
+};
+
+struct ChModeChange
+{
+       char letter;
+       const char *arg;
+       const char *id;
+       int dir;
+       int caps;
+       int nocaps;
+       int mems;
+       struct Client *client;
+};
+
+struct ChCapCombo
+{
+       int count;
+       int cap_yes;
+       int cap_no;
+};
+
+struct ChannelMode
+{
+       void (*set_func) (struct Client * source_p, struct Channel * chptr,
+                     int alevel, int parc, int *parn,
+                     const char **parv, int *errors, int dir, char c, long mode_type);
+       long mode_type;
+};
+
+typedef int (*ExtbanFunc)(const char *data, struct Client *client_p,
+               struct Channel *chptr, long mode_type);
+
+/* can_send results */
+#define CAN_SEND_NO    0
+#define CAN_SEND_NONOP  1
+#define CAN_SEND_OPV   2
+
+/* channel status flags */
+#define CHFL_PEON              0x0000  /* normal member of channel */
+#define CHFL_CHANOP            0x0001  /* Channel operator */
+#define CHFL_VOICE             0x0002  /* the power to speak */
+#define CHFL_DEOPPED           0x0004  /* deopped on sjoin, bounce modes */
+#define CHFL_BANNED            0x0008  /* cached as banned */
+#define CHFL_QUIETED           0x0010  /* cached as being +q victim */
+#define ONLY_SERVERS           0x0020
+#define ALL_MEMBERS            CHFL_PEON
+#define ONLY_CHANOPS           CHFL_CHANOP
+#define ONLY_CHANOPSVOICED     (CHFL_CHANOP|CHFL_VOICE)
+
+#define is_chanop(x)   ((x) && (x)->flags & CHFL_CHANOP)
+#define is_voiced(x)   ((x) && (x)->flags & CHFL_VOICE)
+#define is_chanop_voiced(x) ((x) && (x)->flags & (CHFL_CHANOP|CHFL_VOICE))
+#define is_deop(x)     ((x) && (x)->flags & CHFL_DEOPPED)
+#define can_send_banned(x) ((x) && (x)->flags & (CHFL_BANNED|CHFL_QUIETED))
+
+/* channel modes ONLY */
+#define MODE_PRIVATE    0x0001
+#define MODE_SECRET     0x0002
+#define MODE_MODERATED  0x0004
+#define MODE_TOPICLIMIT 0x0008
+#define MODE_INVITEONLY 0x0010
+#define MODE_NOPRIVMSGS 0x0020
+#define MODE_REGONLY   0x0040
+#define MODE_NOCOLOR   0x0080
+#define MODE_EXLIMIT   0x0100  /* exempt from list limits, +b/+e/+I/+q */
+#define MODE_PERMANENT  0x0200  /* permanant channel, +P */
+#define MODE_OPMODERATE 0x0400  /* send rejected messages to ops */
+#define MODE_FREEINVITE 0x0800  /* allow free use of /invite */
+#define MODE_FREETARGET 0x1000  /* can be forwarded to without authorization */
+#define MODE_DISFORWARD 0x2000  /* disable channel forwarding */
+
+#define CHFL_BAN        0x10000000     /* ban channel flag */
+#define CHFL_EXCEPTION  0x20000000     /* exception to ban channel flag */
+#define CHFL_INVEX      0x40000000
+#define CHFL_QUIET      0x80000000
+
+/* mode flags for direction indication */
+#define MODE_QUERY     0
+#define MODE_ADD       1
+#define MODE_DEL       -1
+
+#define SecretChannel(x)        ((x) && ((x)->mode.mode & MODE_SECRET))
+#define HiddenChannel(x)        ((x) && ((x)->mode.mode & MODE_PRIVATE))
+#define PubChannel(x)           ((!x) || ((x)->mode.mode &\
+                                 (MODE_PRIVATE | MODE_SECRET)) == 0)
+
+/* channel visible */
+#define ShowChannel(v,c)        (PubChannel(c) || IsMember((v),(c)))
+
+#define IsMember(who, chan) ((who && who->user && \
+                find_channel_membership(chan, who)) ? 1 : 0)
+
+#define IsChannelName(name) ((name) && (*(name) == '#' || *(name) == '&'))
+
+/* extban function results */
+#define EXTBAN_INVALID -1  /* invalid mask, false even if negated */
+#define EXTBAN_NOMATCH  0  /* valid mask, no match */
+#define EXTBAN_MATCH    1  /* matches */
+
+extern dlink_list global_channel_list;
+void init_channels(void);
+
+struct Channel *allocate_channel(const char *chname);
+void free_channel(struct Channel *chptr);
+struct Ban *allocate_ban(const char *, const char *);
+void free_ban(struct Ban *bptr);
+
+
+extern void destroy_channel(struct Channel *);
+
+extern int can_send(struct Channel *chptr, struct Client *who, 
+                   struct membership *);
+extern int is_banned(struct Channel *chptr, struct Client *who,
+                    struct membership *msptr, const char *, const char *);
+extern int is_quieted(struct Channel *chptr, struct Client *who,
+                    struct membership *msptr, const char *, const char *);
+extern int can_join(struct Client *source_p, struct Channel *chptr, char *key);
+
+extern struct membership *find_channel_membership(struct Channel *, struct Client *);
+extern const char *find_channel_status(struct membership *msptr, int combine);
+extern void add_user_to_channel(struct Channel *, struct Client *, int flags);
+extern void remove_user_from_channel(struct membership *);
+extern void remove_user_from_channels(struct Client *);
+extern void invalidate_bancache_user(struct Client *);
+
+extern void free_channel_list(dlink_list *);
+
+extern int check_channel_name(const char *name);
+
+extern void channel_member_names(struct Channel *chptr, struct Client *,
+                                int show_eon);
+
+extern void del_invite(struct Channel *chptr, struct Client *who);
+
+const char *channel_modes(struct Channel *chptr, struct Client *who);
+
+extern struct Channel *find_bannickchange_channel(struct Client *client_p);
+
+extern void check_spambot_warning(struct Client *source_p, const char *name);
+
+extern void check_splitmode(void *);
+
+void set_channel_topic(struct Channel *chptr, const char *topic,
+                      const char *topic_info, time_t topicts);
+
+extern void init_chcap_usage_counts(void);
+extern void set_chcap_usage_counts(struct Client *serv_p);
+extern void unset_chcap_usage_counts(struct Client *serv_p);
+extern void send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
+                                 struct Channel *chptr, struct ChModeChange foo[], int);
+
+extern void set_channel_mode(struct Client *client_p, struct Client *source_p,
+               struct Channel *chptr, struct membership *msptr, int parc, const char *parv[]);
+
+extern struct ChannelMode chmode_table[256];
+
+extern int add_id(struct Client *source_p, struct Channel *chptr, const char *banid,
+       dlink_list * list, long mode_type);
+
+extern int del_id(struct Channel *chptr, const char *banid, dlink_list * list, long mode_type);
+
+extern ExtbanFunc extban_table[256];
+
+extern int match_extban(const char *banstr, struct Client *client_p, struct Channel *chptr, long mode_type);
+extern int valid_extban(const char *banstr, struct Client *client_p, struct Channel *chptr, long mode_type);
+const char * get_extban_string(void);
+
+
+#endif /* INCLUDED_channel_h */
diff --git a/include/charybdis.h b/include/charybdis.h
new file mode 100644 (file)
index 0000000..e0b7e8a
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ *  charybdis: a useful ircd.
+ *  charybdis.h: primary include file
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2005 Hybrid Development Team
+ *  Copyright (C) 2005 William Pitcock and Jilles Tjoelker
+ *
+ *  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: charybdis.h 238 2005-09-21 05:26:03Z nenolod $
+ */
+
+#ifndef CHARYBDIS_H
+#define CHARYBDIS_H
+
+#endif
diff --git a/include/class.h b/include/class.h
new file mode 100644 (file)
index 0000000..93adb9c
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  class.h: The ircd class management header.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: class.h 6 2005-09-10 01:02:21Z nenolod $
+ */
+
+#ifndef INCLUDED_class_h
+#define INCLUDED_class_h
+
+#include "tools.h"
+
+struct ConfItem;
+struct Client;
+struct _patricia_tree_t;
+
+struct Class
+{
+       struct Class *next;
+       char *class_name;
+       int max_total;
+       int max_local;
+       int max_global;
+       int max_ident;
+       int max_sendq;
+       int con_freq;
+       int ping_freq;
+       int total;
+       struct _patricia_tree_t *ip_limits;
+       int cidr_bitlen;
+       int cidr_amount;
+
+};
+
+extern dlink_list class_list;
+extern struct Class *default_class;
+
+#define ClassName(x)   ((x)->class_name)
+#define ConFreq(x)      ((x)->con_freq)
+#define MaxLocal(x)    ((x)->max_local)
+#define MaxGlobal(x)   ((x)->max_global)
+#define MaxIdent(x)    ((x)->max_ident)
+#define MaxUsers(x)    ((x)->max_total)
+#define PingFreq(x)     ((x)->ping_freq)
+#define MaxSendq(x)     ((x)->max_sendq)
+#define CurrUsers(x)    ((x)->total)
+#define IpLimits(x)     ((x)->ip_limits)
+#define CidrBitlen(x)   ((x)->cidr_bitlen)
+#define CidrAmount(x)  ((x)->cidr_amount)
+#define ClassPtr(x)      ((x)->c_class)
+
+#define ConfClassName(x) (ClassPtr(x)->class_name)
+#define ConfConFreq(x)   (ClassPtr(x)->con_freq)
+#define ConfMaxLocal(x)  (ClassPtr(x)->max_local)
+#define ConfMaxGlobal(x) (ClassPtr(x)->max_global)
+#define ConfMaxIdent(x)  (ClassPtr(x)->max_ident)
+#define ConfMaxUsers(x)  (ClassPtr(x)->max_total)
+#define ConfPingFreq(x)  (ClassPtr(x)->ping_freq)
+#define ConfMaxSendq(x)  (ClassPtr(x)->max_sendq)
+#define ConfCurrUsers(x) (ClassPtr(x)->total)
+#define ConfIpLimits(x) (ClassPtr(x)->ip_limits)
+#define ConfCidrAmount(x) (ClassPtr(x)->cidr_amount)
+#define ConfCidrBitlen(x) (ClassPtr(x)->cidr_bitlen)
+
+void add_class(struct Class *);
+
+struct Class *make_class(void);
+
+extern long get_sendq(struct Client *);
+extern int get_con_freq(struct Class *);
+extern struct Class *find_class(const char *);
+extern const char *get_client_class(struct Client *);
+extern int get_client_ping(struct Client *);
+extern void check_class(void);
+extern void initclass(void);
+extern void free_class(struct Class *);
+extern void fix_class(struct ConfItem *, struct ConfItem *);
+extern void report_classes(struct Client *);
+
+#endif /* INCLUDED_class_h */
diff --git a/include/client.h b/include/client.h
new file mode 100644 (file)
index 0000000..5a3e041
--- /dev/null
@@ -0,0 +1,634 @@
+/*
+ *  charybdis: A useful ircd.
+ *  client.h: The ircd client header.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development team
+ *  Copyright (C) 2005 William Pitcock and Jilles Tjoelker
+ *
+ *  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: client.h 2023 2006-09-02 23:47:27Z jilles $
+ */
+
+#ifndef INCLUDED_client_h
+#define INCLUDED_client_h
+
+#include "config.h"
+
+#if !defined(CONFIG_RATBOX_LEVEL_1)
+#error Incorrect config.h for this revision of ircd.
+#endif
+
+#include "ircd_defs.h"
+#include "linebuf.h"
+#include "channel.h"
+#include "res.h"
+#include "snomask.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "commio.h"
+
+/* other structs */
+struct Blacklist;
+
+/* we store ipv6 ips for remote clients, so this needs to be v6 always */
+#define HOSTIPLEN      53      /* sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255.ipv6") */
+#define PASSWDLEN       128
+#define CIPHERKEYLEN    64     /* 512bit */
+#define CLIENT_BUFSIZE 512     /* must be at least 512 bytes */
+
+#define IDLEN          10
+
+/*
+ * pre declare structs
+ */
+struct ConfItem;
+struct Whowas;
+struct DNSReply;
+struct Listener;
+struct Client;
+struct User;
+struct Server;
+struct LocalUser;
+struct AuthRequest;
+struct PreClient;
+struct ListClient;
+
+/* 
+ * Atheme's coding standards require that we use BSD-style user-defined types
+ * for stuff. Fun! --nenolod
+ */
+typedef struct User user_t;
+typedef struct Server server_t;
+typedef struct Client client_t;
+typedef struct LocalUser local_user_t;
+typedef struct Listener listener_t;
+typedef struct DNSReply dns_reply_t;
+typedef struct Whowas whowas_entry_t;
+typedef struct ConfItem conf_item_t;
+typedef struct AuthRequest auth_request_t;
+typedef struct PreClient pre_client_t;
+typedef struct ListClient list_client_t;
+
+/*
+ * Client structures
+ */
+struct User
+{
+       dlink_list channel;     /* chain of channel pointer blocks */
+       dlink_list invited;     /* chain of invite pointer blocks */
+       char *away;             /* pointer to away message */
+       int refcnt;             /* Number of times this block is referenced */
+       const char *server;     /* pointer to scached server name */
+
+       char suser[NICKLEN+1];
+};
+
+struct Server
+{
+       user_t *user;           /* who activated this connection */
+       const char *up;         /* Pointer to scache name */
+       const char *upid;
+       char by[NICKLEN];
+       dlink_list servers;
+       dlink_list users;
+       int caps;               /* capabilities bit-field */
+       char *fullcaps;
+};
+
+struct SlinkRpl
+{
+       int command;
+       int datalen;
+       int gotdatalen;
+       int readdata;
+       unsigned char *data;
+};
+
+struct ZipStats
+{
+       unsigned long in;
+       unsigned long in_wire;
+       unsigned long out;
+       unsigned long out_wire;
+       unsigned long inK;
+       unsigned long inK_wire;
+       unsigned long outK;
+       unsigned long outK_wire;
+       double in_ratio;
+       double out_ratio;
+};
+
+struct Client
+{
+       dlink_node node;
+       dlink_node lnode;
+       user_t *user;           /* ...defined, if this is a User */
+       server_t *serv;         /* ...defined, if this is a server */
+       client_t *servptr;      /* Points to server this Client is on */
+       client_t *from;         /* == self, if Local Client, *NEVER* NULL! */
+
+       whowas_entry_t *whowas; /* Pointers to whowas structs */
+       time_t tsinfo;          /* TS on the nick, SVINFO on server */
+       unsigned int umodes;    /* opers, normal users subset */
+       unsigned int flags;     /* client flags */
+       unsigned int flags2;    /* ugh. overflow */
+
+       unsigned int snomask;   /* server notice mask */
+
+       int hopcount;           /* number of servers to this 0 = local */
+       unsigned short status;  /* Client type */
+       unsigned char handler;  /* Handler index */
+       unsigned long serial;   /* used to enforce 1 send per nick */
+
+       /* client->name is the unique name for a client nick or host */
+       char name[HOSTLEN + 1];
+
+       /* 
+        * client->username is the username from ident or the USER message, 
+        * If the client is idented the USER message is ignored, otherwise 
+        * the username part of the USER message is put here prefixed with a 
+        * tilde depending on the I:line, Once a client has registered, this
+        * field should be considered read-only.
+        */
+       char username[USERLEN + 1];     /* client's username */
+
+       /*
+        * client->host contains the resolved name or ip address
+        * as a string for the user, it may be fiddled with for oper spoofing etc.
+        */
+       char host[HOSTLEN + 1]; /* client's hostname */
+       char orighost[HOSTLEN + 1]; /* original hostname (before dynamic spoofing) */
+       char sockhost[HOSTIPLEN + 1]; /* clients ip */
+       char info[REALLEN + 1]; /* Free form additional client info */
+
+       char id[IDLEN]; /* UID/SID, unique on the network */
+
+       /* list of who has this client on their allow list, its counterpart
+        * is in LocalUser
+        */
+       dlink_list on_allow_list;
+
+       local_user_t *localClient;
+       pre_client_t *preClient;
+};
+
+struct LocalUser
+{
+       dlink_node tnode;       /* This is the node for the local list type the client is on*/
+       /*
+        * The following fields are allocated only for local clients
+        * (directly connected to *this* server with a socket.
+        */
+       /* Anti flooding part, all because of lamers... */
+       time_t last_join_time;  /* when this client last 
+                                  joined a channel */
+       time_t last_leave_time; /* when this client last 
+                                * left a channel */
+       int join_leave_count;   /* count of JOIN/LEAVE in less than 
+                                  MIN_JOIN_LEAVE_TIME seconds */
+       int oper_warn_count_down;       /* warn opers of this possible 
+                                          spambot every time this gets to 0 */
+       time_t last_caller_id_time;
+       time_t first_received_message_time;
+       int received_number_of_privmsgs;
+       int flood_noticed;
+
+       time_t lasttime;        /* last time we parsed something */
+       time_t firsttime;       /* time client was created */
+
+       /* Send and receive linebuf queues .. */
+       buf_head_t buf_sendq;
+       buf_head_t buf_recvq;
+       /*
+        * we want to use unsigned int here so the sizes have a better chance of
+        * staying the same on 64 bit machines. The current trend is to use
+        * I32LP64, (32 bit ints, 64 bit longs and pointers) and since ircd
+        * will NEVER run on an operating system where ints are less than 32 bits, 
+        * it's a relatively safe bet to use ints. Since right shift operations are
+        * performed on these, it's not safe to allow them to become negative, 
+        * which is possible for long running server connections. Unsigned values 
+        * generally overflow gracefully. --Bleep
+        */
+       unsigned int sendM;     /* Statistics: protocol messages send */
+       unsigned int sendK;     /* Statistics: total k-bytes send */
+       unsigned int receiveM;  /* Statistics: protocol messages received */
+       unsigned int receiveK;  /* Statistics: total k-bytes received */
+       unsigned short sendB;   /* counters to count upto 1-k lots of bytes */
+       unsigned short receiveB;        /* sent and received. */
+       listener_t *listener;           /* listener accepted from */
+       conf_item_t *att_conf;          /* attached conf */
+       struct server_conf *att_sconf;
+
+       struct irc_sockaddr_storage ip;
+       time_t last_nick_change;
+       int number_of_nick_changes;
+
+       /*
+        * XXX - there is no reason to save this, it should be checked when it's
+        * received and not stored, this is not used after registration
+        *
+        * agreed. lets get rid of it someday! --nenolod
+        */
+       char *passwd;
+       char *opername; /* name of operator{} block being used or tried (challenge) */
+       char *challenge;
+       char *fullcaps;
+
+       int caps;               /* capabilities bit-field */
+       int fd;                 /* >= 0, for local clients */
+
+       /* time challenge response is valid for */
+       time_t chal_time;
+
+       int ctrlfd;             /* For servers:
+                                  control fd used for sending commands
+                                  to servlink */
+
+       struct SlinkRpl slinkrpl;       /* slink reply being parsed */
+       unsigned char *slinkq;  /* sendq for control data */
+       int slinkq_ofs;         /* ofset into slinkq */
+       int slinkq_len;         /* length remaining after slinkq_ofs */
+
+       struct ZipStats zipstats;
+
+       time_t last_away;       /* Away since... */
+       time_t last;
+
+       /* clients allowed to talk through +g */
+       dlink_list allow_list;
+
+       /* nicknames theyre monitoring */
+       dlink_list monitor_list;
+
+       /*
+        * Anti-flood stuff. We track how many messages were parsed and how
+        * many we were allowed in the current second, and apply a simple decay
+        * to avoid flooding.
+        *   -- adrian
+        */
+       int allow_read;         /* how many we're allowed to read in this second */
+       int actually_read;      /* how many we've actually read in this second */
+       int sent_parsed;        /* how many messages we've parsed in this second */
+       time_t last_knock;      /* time of last knock */
+       unsigned long random_ping;
+       auth_request_t  *auth_request;
+
+       /* target change stuff */
+       void *targets[10];              /* targets were aware of */
+       unsigned int targinfo[2];       /* cyclic array, no in use */
+       time_t target_last;             /* last time we cleared a slot */
+
+       list_client_t *safelist_data;
+
+       char *mangledhost; /* non-NULL if host mangling module loaded and
+                             applicable to this client */
+};
+
+struct PreClient
+{
+       char spoofnick[NICKLEN + 1];
+       char spoofuser[USERLEN + 1];
+       char spoofhost[HOSTLEN + 1];
+
+       char sasl_agent[IDLEN];
+       unsigned char sasl_out;
+       unsigned char sasl_complete;
+
+       dlink_list dnsbl_queries; /* list of struct BlacklistClient * */
+       struct Blacklist *dnsbl_listed; /* first dnsbl where it's listed */
+};
+
+struct ListClient
+{
+       unsigned int hash_indice;
+       unsigned int users_min, users_max;
+
+       /* It would be nice to add other modifiers,
+        * but not for 1.1 --nenolod
+        */
+};
+
+struct exit_client_hook
+{
+       struct Client *client_p;
+       char exit_message[TOPICLEN];
+};
+
+/*
+ * status macros.
+ */
+#define STAT_CONNECTING         0x01
+#define STAT_HANDSHAKE          0x02
+#define STAT_ME                 0x04
+#define STAT_UNKNOWN            0x08
+#define STAT_REJECT            0x10
+#define STAT_SERVER             0x20
+#define STAT_CLIENT             0x40
+
+
+#define IsRegisteredUser(x)     ((x)->status == STAT_CLIENT)
+#define IsRegistered(x)         (((x)->status  > STAT_UNKNOWN) && ((x)->status != STAT_REJECT))
+#define IsConnecting(x)         ((x)->status == STAT_CONNECTING)
+#define IsHandshake(x)          ((x)->status == STAT_HANDSHAKE)
+#define IsMe(x)                 ((x)->status == STAT_ME)
+#define IsUnknown(x)            ((x)->status == STAT_UNKNOWN)
+#define IsServer(x)             ((x)->status == STAT_SERVER)
+#define IsClient(x)             ((x)->status == STAT_CLIENT)
+#define IsReject(x)            ((x)->status == STAT_REJECT)
+
+#define IsAnyServer(x)          (IsServer(x) || IsHandshake(x) || IsConnecting(x))
+
+#define IsOper(x)              ((x)->umodes & UMODE_OPER)
+#define IsAdmin(x)             ((x)->umodes & UMODE_ADMIN)
+
+#define SetReject(x)           {(x)->status = STAT_REJECT; \
+                                (x)->handler = UNREGISTERED_HANDLER; }
+
+#define SetConnecting(x)        {(x)->status = STAT_CONNECTING; \
+                                (x)->handler = UNREGISTERED_HANDLER; }
+
+#define SetHandshake(x)         {(x)->status = STAT_HANDSHAKE; \
+                                (x)->handler = UNREGISTERED_HANDLER; }
+
+#define SetMe(x)                {(x)->status = STAT_ME; \
+                                (x)->handler = UNREGISTERED_HANDLER; }
+
+#define SetUnknown(x)           {(x)->status = STAT_UNKNOWN; \
+                                (x)->handler = UNREGISTERED_HANDLER; }
+
+#define SetServer(x)            {(x)->status = STAT_SERVER; \
+                                (x)->handler = SERVER_HANDLER; }
+
+#define SetClient(x)            {(x)->status = STAT_CLIENT; \
+                                (x)->handler = IsOper((x)) ? \
+                                       OPER_HANDLER : CLIENT_HANDLER; }
+#define SetRemoteClient(x)     {(x)->status = STAT_CLIENT; \
+                                (x)->handler = RCLIENT_HANDLER; }
+
+#define STAT_CLIENT_PARSE (STAT_UNKNOWN | STAT_CLIENT)
+#define STAT_SERVER_PARSE (STAT_CONNECTING | STAT_HANDSHAKE | STAT_SERVER)
+
+#define PARSE_AS_CLIENT(x)      ((x)->status & STAT_CLIENT_PARSE)
+#define PARSE_AS_SERVER(x)      ((x)->status & STAT_SERVER_PARSE)
+
+
+/*
+ * ts stuff
+ */
+#define TS_CURRENT     6
+
+#ifdef TS6_ONLY
+#define TS_MIN          6
+#else
+#define TS_MIN          3
+#endif
+
+#define TS_DOESTS       0x10000000
+#define DoesTS(x)       ((x)->tsinfo & TS_DOESTS)
+
+#define has_id(source) ((source)->id[0] != '\0')
+#define use_id(source) ((source)->id[0] != '\0' ? (source)->id : (source)->name)
+
+/* if target is TS6, use id if it has one, else name */
+#define get_id(source, target) ((IsServer(target->from) && has_id(target->from)) ? \
+                               use_id(source) : (source)->name)
+
+/* housekeeping flags */
+
+#define FLAGS_PINGSENT     0x0001      /* Unreplied ping sent */
+#define FLAGS_DEAD        0x0002       /* Local socket is dead--Exiting soon */
+#define FLAGS_KILLED       0x0004      /* Prevents "QUIT" from being sent for this */
+#define FLAGS_SENTUSER     0x0008      /* Client sent a USER command. */
+#define FLAGS_CLOSING      0x0020      /* set when closing to suppress errors */
+#define FLAGS_CHKACCESS    0x0040      /* ok to check clients access if set */
+#define FLAGS_GOTID        0x0080      /* successful ident lookup achieved */
+#define FLAGS_NEEDID       0x0100      /* I-lines say must use ident return */
+#define FLAGS_NORMALEX     0x0400      /* Client exited normally */
+#define FLAGS_SENDQEX      0x0800      /* Sendq exceeded */
+#define FLAGS_SERVLINK     0x10000     /* servlink has servlink process */
+#define FLAGS_MARK        0x20000      /* marked client */
+#define FLAGS_HIDDEN       0x40000     /* hidden server */
+#define FLAGS_EOB          0x80000     /* EOB */
+#define FLAGS_MYCONNECT           0x100000     /* MyConnect */
+#define FLAGS_IOERROR      0x200000    /* IO error */
+#define FLAGS_SERVICE     0x400000     /* network service */
+#define FLAGS_TGCHANGE     0x800000    /* we're allowed to clear something */
+#define FLAGS_DYNSPOOF     0x1000000   /* dynamic spoof, only opers see ip */
+
+/* umodes, settable flags */
+/* lots of this moved to snomask -- jilles */
+#define UMODE_SERVNOTICE   0x0001      /* server notices */
+#define UMODE_WALLOP       0x0100      /* send wallops to them */
+#define UMODE_OPERWALL     0x0200      /* Operwalls */
+#define UMODE_INVISIBLE    0x0400      /* makes user invisible */
+#define UMODE_CALLERID     0x2000      /* block unless caller id's */
+#define UMODE_LOCOPS       0x8000      /* show locops */
+#define UMODE_SERVICE      0x40000
+#define UMODE_DEAF        0x80000
+#define UMODE_NOFORWARD    0x400000    /* don't forward */
+#define UMODE_REGONLYMSG   0x800000    /* only allow logged in users to msg */
+
+/* user information flags, only settable by remote mode or local oper */
+#define UMODE_OPER         0x100000    /* Operator */
+#define UMODE_ADMIN        0x200000    /* Admin on server */
+
+#define UMODE_ALL         UMODE_SERVNOTICE
+
+/* overflow flags */
+/* EARLIER FLAGS ARE IN s_newconf.h */
+#define FLAGS2_EXEMPTRESV      0x0080000
+#define FLAGS2_EXEMPTGLINE      0x0100000
+#define FLAGS2_EXEMPTKLINE      0x0200000
+#define FLAGS2_EXEMPTFLOOD      0x0400000
+#define FLAGS2_NOLIMIT          0x0800000
+#define FLAGS2_IDLE_LINED       0x1000000
+#define FLAGS2_CLICAP          0x2000000
+#define FLAGS2_PING_COOKIE      0x4000000
+#define FLAGS2_IP_SPOOFING      0x8000000
+#define FLAGS2_FLOODDONE        0x10000000
+#define FLAGS2_EXEMPTSPAMBOT   0x20000000
+#define FLAGS2_EXEMPTSHIDE     0x40000000
+#define FLAGS2_EXEMPTJUPE      0x80000000
+
+#define DEFAULT_OPER_UMODES (UMODE_SERVNOTICE | UMODE_OPERWALL | \
+                             UMODE_WALLOP | UMODE_LOCOPS)
+#define DEFAULT_OPER_SNOMASK SNO_GENERAL
+
+#define FLAGS_ID     (FLAGS_NEEDID | FLAGS_GOTID)
+
+#define CLICAP_MULTI_PREFIX    0x0001
+#define CLICAP_SASL            0x0002
+
+/*
+ * flags macros.
+ */
+#define IsPerson(x)             (IsClient(x) && (x)->user != NULL)
+#define DoAccess(x)             ((x)->flags & FLAGS_CHKACCESS)
+#define SetAccess(x)            ((x)->flags |= FLAGS_CHKACCESS)
+#define ClearAccess(x)          ((x)->flags &= ~FLAGS_CHKACCESS)
+#define HasServlink(x)          ((x)->flags &  FLAGS_SERVLINK)
+#define SetServlink(x)          ((x)->flags |= FLAGS_SERVLINK)
+#define MyConnect(x)           ((x)->flags & FLAGS_MYCONNECT)
+#define SetMyConnect(x)                ((x)->flags |= FLAGS_MYCONNECT)
+#define ClearMyConnect(x)      ((x)->flags &= ~FLAGS_MYCONNECT)
+
+#define MyClient(x)             (MyConnect(x) && IsClient(x))
+#define SetMark(x)             ((x)->flags |= FLAGS_MARK)
+#define ClearMark(x)           ((x)->flags &= ~FLAGS_MARK)
+#define IsMarked(x)            ((x)->flags & FLAGS_MARK)
+#define SetHidden(x)           ((x)->flags |= FLAGS_HIDDEN)
+#define ClearHidden(x)         ((x)->flags &= ~FLAGS_HIDDEN)
+#define IsHidden(x)            ((x)->flags & FLAGS_HIDDEN)
+#define ClearEob(x)            ((x)->flags &= ~FLAGS_EOB)
+#define SetEob(x)              ((x)->flags |= FLAGS_EOB)
+#define HasSentEob(x)          ((x)->flags & FLAGS_EOB)
+#define IsDead(x)              ((x)->flags &  FLAGS_DEAD)
+#define SetDead(x)             ((x)->flags |= FLAGS_DEAD)
+#define IsClosing(x)           ((x)->flags & FLAGS_CLOSING)
+#define SetClosing(x)          ((x)->flags |= FLAGS_CLOSING)
+#define IsIOError(x)           ((x)->flags & FLAGS_IOERROR)
+#define SetIOError(x)          ((x)->flags |= FLAGS_IOERROR)
+#define IsAnyDead(x)           (IsIOError(x) || IsDead(x) || IsClosing(x))
+#define IsTGChange(x)          ((x)->flags & FLAGS_TGCHANGE)
+#define SetTGChange(x)         ((x)->flags |= FLAGS_TGCHANGE)
+#define ClearTGChange(x)       ((x)->flags &= ~FLAGS_TGCHANGE)
+#define IsDynSpoof(x)          ((x)->flags & FLAGS_DYNSPOOF)
+#define SetDynSpoof(x)         ((x)->flags |= FLAGS_DYNSPOOF)
+#define ClearDynSpoof(x)       ((x)->flags &= ~FLAGS_DYNSPOOF)
+
+/* oper flags */
+#define MyOper(x)               (MyConnect(x) && IsOper(x))
+
+#define SetOper(x)              {(x)->umodes |= UMODE_OPER; \
+                                if (MyClient((x))) (x)->handler = OPER_HANDLER;}
+
+#define ClearOper(x)            {(x)->umodes &= ~(UMODE_OPER|UMODE_ADMIN); \
+                                if (MyClient((x)) && !IsOper((x)) && !IsServer((x))) \
+                                 (x)->handler = CLIENT_HANDLER; }
+
+#define IsPrivileged(x)         (IsOper(x) || IsServer(x))
+
+/* umode flags */
+#define IsInvisible(x)          ((x)->umodes & UMODE_INVISIBLE)
+#define SetInvisible(x)         ((x)->umodes |= UMODE_INVISIBLE)
+#define ClearInvisible(x)       ((x)->umodes &= ~UMODE_INVISIBLE)
+#define SendWallops(x)          ((x)->umodes & UMODE_WALLOP)
+#define ClearWallops(x)         ((x)->umodes &= ~UMODE_WALLOP)
+#define SendLocops(x)           ((x)->umodes & UMODE_LOCOPS)
+#define SendServNotice(x)       ((x)->umodes & UMODE_SERVNOTICE)
+#define SendOperwall(x)         ((x)->umodes & UMODE_OPERWALL)
+#define SetWallops(x)           ((x)->umodes |= UMODE_WALLOP)
+#define SetCallerId(x)         ((x)->umodes |= UMODE_CALLERID)
+#define IsSetCallerId(x)       ((x)->umodes & UMODE_CALLERID)
+#define IsService(x)           ((x)->umodes & UMODE_SERVICE)
+#define IsDeaf(x)              ((x)->umodes & UMODE_DEAF)
+#define IsNoForward(x)         ((x)->umodes & UMODE_NOFORWARD)
+#define IsSetRegOnlyMsg(x)     ((x)->umodes & UMODE_REGONLYMSG)
+
+#define SetNeedId(x)            ((x)->flags |= FLAGS_NEEDID)
+#define IsNeedId(x)             (((x)->flags & FLAGS_NEEDID) != 0)
+
+#define SetGotId(x)             ((x)->flags |= FLAGS_GOTID)
+#define IsGotId(x)              (((x)->flags & FLAGS_GOTID) != 0)
+
+/*
+ * flags2 macros.
+ */
+#define IsExemptKline(x)        ((x)->flags2 & FLAGS2_EXEMPTKLINE)
+#define SetExemptKline(x)       ((x)->flags2 |= FLAGS2_EXEMPTKLINE)
+#define IsExemptLimits(x)       ((x)->flags2 & FLAGS2_NOLIMIT)
+#define SetExemptLimits(x)      ((x)->flags2 |= FLAGS2_NOLIMIT)
+#define IsExemptGline(x)        ((x)->flags2 & FLAGS2_EXEMPTGLINE)
+#define SetExemptGline(x)       ((x)->flags2 |= FLAGS2_EXEMPTGLINE)
+#define IsExemptFlood(x)        ((x)->flags2 & FLAGS2_EXEMPTFLOOD)
+#define SetExemptFlood(x)       ((x)->flags2 |= FLAGS2_EXEMPTFLOOD)
+#define IsExemptSpambot(x)     ((x)->flags2 & FLAGS2_EXEMPTSPAMBOT)
+#define SetExemptSpambot(x)    ((x)->flags2 |= FLAGS2_EXEMPTSPAMBOT)
+#define IsExemptShide(x)       ((x)->flags2 & FLAGS2_EXEMPTSHIDE)
+#define SetExemptShide(x)      ((x)->flags2 |= FLAGS2_EXEMPTSHIDE)
+#define IsExemptJupe(x)                ((x)->flags2 & FLAGS2_EXEMPTJUPE)
+#define SetExemptJupe(x)       ((x)->flags2 |= FLAGS2_EXEMPTJUPE)
+#define IsExemptResv(x)                ((x)->flags2 & FLAGS2_EXEMPTRESV)
+#define SetExemptResv(x)       ((x)->flags2 |= FLAGS2_EXEMPTRESV)
+#define IsIPSpoof(x)            ((x)->flags2 & FLAGS2_IP_SPOOFING)
+#define SetIPSpoof(x)           ((x)->flags2 |= FLAGS2_IP_SPOOFING)
+
+#define SetIdlelined(x)         ((x)->flags2 |= FLAGS2_IDLE_LINED)
+#define IsIdlelined(x)          ((x)->flags2 & FLAGS2_IDLE_LINED)
+
+/* for local users: flood grace period is over
+ * for servers: mentioned in networknotice.c notice
+ */
+#define IsFloodDone(x)          ((x)->flags2 & FLAGS2_FLOODDONE)
+#define SetFloodDone(x)         ((x)->flags2 |= FLAGS2_FLOODDONE)
+
+/*
+ * definitions for get_client_name
+ */
+#define HIDE_IP 0
+#define SHOW_IP 1
+#define MASK_IP 2
+
+extern void check_banned_lines(void);
+extern void check_klines_event(void *unused);
+extern void check_klines(void);
+extern void check_glines(void);
+extern void check_dlines(void);
+extern void check_xlines(void);
+
+extern const char *get_client_name(struct Client *client, int show_ip);
+extern const char *get_server_name(struct Client *client, int show_ip);
+extern const char *log_client_name(struct Client *, int);
+extern int is_remote_connect(struct Client *);
+extern void init_client(void);
+extern client_t *make_client(struct Client *from);
+extern void free_pre_client(struct Client *client);
+extern void free_client(struct Client *client);
+
+extern int exit_client(struct Client *, struct Client *, struct Client *, const char *);
+
+extern void error_exit_client(struct Client *, int);
+
+
+
+extern void count_local_client_memory(size_t * count, size_t * memory);
+extern void count_remote_client_memory(size_t * count, size_t * memory);
+
+extern client_t *find_chasing(struct Client *, const char *, int *);
+extern client_t *find_person(const char *);
+extern client_t *find_named_person(const char *);
+extern client_t *next_client(struct Client *, const char *);
+
+#define accept_message(s, t) ((s) == (t) || (dlinkFind((s), &((t)->localClient->allow_list))))
+extern void del_all_accepts(struct Client *client_p);
+
+extern void dead_link(struct Client *client_p);
+extern int show_ip(struct Client *source_p, struct Client *target_p);
+extern int show_ip_conf(struct ConfItem *aconf, struct Client *target_p);
+
+extern void initUser(void);
+extern void free_user(struct User *, struct Client *);
+extern user_t *make_user(struct Client *);
+extern server_t *make_server(struct Client *);
+extern void close_connection(struct Client *);
+extern void init_uid(void);
+extern char *generate_uid(void);
+
+#endif /* INCLUDED_client_h */
diff --git a/include/common.h b/include/common.h
new file mode 100644 (file)
index 0000000..b96cb0f
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  common.h: An ircd header common to most code.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: common.h 6 2005-09-10 01:02:21Z nenolod $
+ */
+
+#ifndef INCLUDED_common_h
+#define INCLUDED_common_h
+
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifdef TRUE
+#undef TRUE
+#endif
+
+#ifdef FALSE
+#undef FALSE
+#endif
+
+#define FALSE  0
+#define TRUE   1
+#define HIDEME 2
+
+/* Blah. I use these a lot. -Dianora */
+#ifdef YES
+#undef YES
+#endif
+
+#define YES 1
+
+#ifdef NO
+#undef NO
+#endif
+
+#define NO  0
+
+/* Just blindly define our own MIN/MAX macro */
+
+#define IRCD_MAX(a, b)  ((a) > (b) ? (a) : (b))
+#define IRCD_MIN(a, b)  ((a) < (b) ? (a) : (b))
+
+/* Right out of the RFC */
+#define IRCD_BUFSIZE 512
+
+#endif /* INCLUDED_common_h */
diff --git a/include/config.h b/include/config.h
new file mode 100644 (file)
index 0000000..78c48f0
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  config.h: The ircd compile-time-configurable header.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: config.h 1701 2006-06-27 16:25:52Z jilles $
+ */
+
+#ifndef INCLUDED_config_h
+#define INCLUDED_config_h
+
+#include "setup.h"
+
+/* 
+ * Directory paths and filenames for UNIX systems.
+ * IRCD_PREFIX is set using ./configure --prefix, see INSTALL.
+ * The other defaults should be fine.
+ *
+ * NOTE: CHANGING THESE WILL NOT ALTER THE DIRECTORY THAT FILES WILL
+ *       BE INSTALLED TO.  IF YOU CHANGE THESE, DO NOT USE MAKE INSTALL,
+ *       BUT COPY THE FILES MANUALLY TO WHERE YOU WANT THEM.
+ *
+ * IRCD_PREFIX = prefix for all directories,
+ * DPATH       = root directory of installation,
+ * BINPATH     = directory for binary files,
+ * ETCPATH     = directory for configuration files,
+ * LOGPATH     = directory for logfiles,
+ * MODPATH     = directory for modules,
+ * AUTOMODPATH = directory for autoloaded modules
+ */
+
+/* dirs */
+#define DPATH   IRCD_PREFIX
+#define BINPATH IRCD_PREFIX "/bin/"
+#define LIBPATH IRCD_PREFIX "/lib/"
+#define MODPATH MODULE_DIR
+#define AUTOMODPATH MODULE_DIR "/autoload/"
+#define ETCPATH ETC_DIR 
+#define LOGPATH LOG_DIR
+#define UHPATH   HELP_DIR "/users"
+#define HPATH  HELP_DIR "/opers"
+
+/* files */
+#define SPATH    BINPATH "/ircd"                  /* ircd executable */
+#define LIPATH   LIBPATH "/libircd" SHARED_SUFFIX  /* ircd library */
+#define SLPATH   BINPATH "/servlink"              /* servlink executable */
+#define CPATH    ETCPATH "/ircd.conf"             /* ircd.conf file */
+#define KPATH    ETCPATH "/kline.conf"            /* kline file */
+#define DLPATH   ETCPATH "/dline.conf"            /* dline file */
+#define XPATH   ETCPATH "/xline.conf"             /* xline file */
+#define RESVPATH ETCPATH "/resv.conf"             /* resv file */
+#define RPATH    ETCPATH "/ircd.rsa"              /* ircd rsa private keyfile */
+#define MPATH    ETCPATH "/ircd.motd"             /* MOTD file */
+#define LPATH    LOGPATH "/ircd.log"              /* ircd logfile */
+#define PPATH    ETCPATH "/ircd.pid"              /* pid file */
+#define OPATH    ETCPATH "/opers.motd"            /* oper MOTD file */
+
+/* IGNORE_BOGUS_TS
+ * Ignore bogus timestamps from other servers. Yes this will desync
+ * the network, but it will allow chanops to resync with a valid non TS 0
+ *
+ * This should be enabled network wide, or not at all.
+ */
+#undef  IGNORE_BOGUS_TS
+
+/* HIDE_SERVERS_IPS
+ *
+ * If this is undefined, anyone can see a servers ip.  If it is defined,
+ * noone can.
+ */
+#define  HIDE_SERVERS_IPS
+
+/* TS6_ONLY
+ *
+ * If this is defined only TS6 servers may link to the network.  See
+ * doc/TS6.txt for more information.  If your network has old servers
+ * (hyb7.0, ircd-ratbox-1.x, +CSr) or hybserv you should NOT define this.
+ */
+#undef TS6_ONLY
+
+/* USE_LOGFILE - log errors and such to LPATH
+ * If you wish to have the server send 'vital' messages about server
+ * to a logfile, define USE_LOGFILE.
+ */
+#define USE_LOGFILE
+
+/* CLIENT_FLOOD - client excess flood threshold(in messages)
+ * The number of messages that we can receive before we disconnect the
+ * remote client...
+ */
+#define CLIENT_FLOOD 20
+
+/* HANGONGOODLINK and HANGONRETRYDELAY
+ * Often net breaks for a short time and it's useful to try to
+ * establishing the same connection again faster than CONNECTFREQUENCY
+ * would allow. But, to keep trying on bad connection, we require
+ * that connection has been open for certain minimum time
+ * (HANGONGOODLINK) and we give the net few seconds to steady
+ * (HANGONRETRYDELAY). This latter has to be long enough that the
+ * other end of the connection has time to notice it broke too.
+ * 1997/09/18 recommended values by ThemBones for modern EFnet
+ */
+#define HANGONRETRYDELAY 60    /* Recommended value: 30-60 seconds */
+#define HANGONGOODLINK 3600    /* Recommended value: 30-60 minutes */
+
+/* KILLCHASETIMELIMIT -
+ * Max time from the nickname change that still causes KILL
+ * automatically to switch for the current nick of that user. (seconds)
+ */
+#define KILLCHASETIMELIMIT 90  /* Recommended value: 90 */
+
+/* RATBOX_SOMAXCONN
+ * Use SOMAXCONN if OS has it, otherwise use this value for the 
+ * listen(); backlog.  5 for AIX/SUNOS, 25 for other OSs.
+ */
+#define RATBOX_SOMAXCONN 25
+
+/* ----------------------------------------------------------------
+ * STOPSTOPSTOPSTOPSTOPSTOPSTOPSTOPSTOPSTOPSTOPSTOPSTOPSTOPSTOPSTOP
+ * ----------------------------------------------------------------
+ * The options below this line should NOT be modified.
+ * ----------------------------------------------------------------
+ */
+
+/* MAX_BUFFER
+ * The amount of fds to reserve for clients exempt from limits
+ * and dns lookups.
+ */
+#define MAX_BUFFER      60
+
+/* HARD_FDLIMIT_
+ * The maximum amount of FDs to use.  MAX_CLIENTS is set in ./configure.
+ */
+#define HARD_FDLIMIT_    MAX_CLIENTS + MAX_BUFFER + 20
+
+#define CONFIG_RATBOX_LEVEL_2
+
+#include "defaults.h"
+#endif /* INCLUDED_config_h */
diff --git a/include/config.h.dist b/include/config.h.dist
new file mode 100644 (file)
index 0000000..6c0d0bb
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  config.h: The ircd compile-time-configurable header.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: config.h.dist 438 2006-01-06 01:00:44Z jilles $
+ */
+
+#ifndef INCLUDED_config_h
+#define INCLUDED_config_h
+
+#include "setup.h"
+
+/* 
+ * Directory paths and filenames for UNIX systems.
+ * IRCD_PREFIX is set using ./configure --prefix, see INSTALL.
+ * The other defaults should be fine.
+ *
+ * NOTE: CHANGING THESE WILL NOT ALTER THE DIRECTORY THAT FILES WILL
+ *       BE INSTALLED TO.  IF YOU CHANGE THESE, DO NOT USE MAKE INSTALL,
+ *       BUT COPY THE FILES MANUALLY TO WHERE YOU WANT THEM.
+ *
+ * IRCD_PREFIX = prefix for all directories,
+ * DPATH       = root directory of installation,
+ * BINPATH     = directory for binary files,
+ * ETCPATH     = directory for configuration files,
+ * LOGPATH     = directory for logfiles,
+ * MODPATH     = directory for modules,
+ * AUTOMODPATH = directory for autoloaded modules
+ */
+
+/* dirs */
+#define DPATH   IRCD_PREFIX
+#define BINPATH IRCD_PREFIX "/bin/"
+#define MODPATH IRCD_PREFIX "/modules/"
+#define AUTOMODPATH IRCD_PREFIX "/modules/autoload/"
+#define ETCPATH IRCD_PREFIX "/etc"
+#define LOGPATH IRCD_PREFIX "/logs"
+#define UHPATH   IRCD_PREFIX "/help/users"
+#define HPATH  IRCD_PREFIX "/help/opers"
+
+/* files */
+#define SPATH    BINPATH "/ircd"       /* ircd executable */
+#define SLPATH   BINPATH "/servlink"   /* servlink executable */
+#define CPATH    ETCPATH "/ircd.conf"  /* ircd.conf file */
+#define KPATH    ETCPATH "/kline.conf" /* kline file */
+#define DLPATH   ETCPATH "/dline.conf" /* dline file */
+#define XPATH   ETCPATH "/xline.conf"  /* xline file */
+#define RESVPATH ETCPATH "/resv.conf"  /* resv file */
+#define RPATH    ETCPATH "/ircd.rsa"   /* ircd rsa private keyfile */
+#define MPATH    ETCPATH "/ircd.motd"  /* MOTD file */
+#define LPATH    LOGPATH "/ircd.log"   /* ircd logfile */
+#define PPATH    ETCPATH "/ircd.pid"   /* pid file */
+#define OPATH    ETCPATH "/opers.motd" /* oper MOTD file */
+
+/* IGNORE_BOGUS_TS
+ * Ignore bogus timestamps from other servers. Yes this will desync
+ * the network, but it will allow chanops to resync with a valid non TS 0
+ *
+ * This should be enabled network wide, or not at all.
+ */
+#undef  IGNORE_BOGUS_TS
+
+/* HIDE_SERVERS_IPS
+ *
+ * If this is undefined, opers will be unable to see servers ips and will be
+ * shown a masked ip, admins will be shown the real ip.
+ *
+ * If this is defined, nobody can see a servers ip.
+ */
+#define  HIDE_SERVERS_IPS
+
+/* TS6_ONLY
+ *
+ * If this is defined only TS6 servers may link to the network.  See
+ * doc/TS6.txt for more information.  If your network has old servers
+ * (hyb7.0, ircd-ratbox-1.x, +CSr) or hybserv you should NOT define this.
+ */
+#undef TS6_ONLY
+
+/* USE_LOGFILE - log errors and such to LPATH
+ * If you wish to have the server send 'vital' messages about server
+ * to a logfile, define USE_LOGFILE.
+ */
+#define USE_LOGFILE
+
+/* CLIENT_FLOOD - client excess flood threshold(in messages)
+ * The number of messages that we can receive before we disconnect the
+ * remote client...
+ */
+#define CLIENT_FLOOD 20
+
+/* NICKNAMEHISTORYLENGTH - size of WHOWAS array
+ * this defines the length of the nickname history.  each time a user changes
+ * nickname or signs off, their old nickname is added to the top of the list.
+ * NOTE: this is directly related to the amount of memory ircd will use whilst
+ *       resident and running - it hardly ever gets swapped to disk!  Memory
+ *       will be preallocated for the entire whowas array when ircd is started.
+ */
+#ifndef SMALL_NET
+#define NICKNAMEHISTORYLENGTH 15000
+#else
+#define NICKNAMEHISTORYLENGTH 1500
+#endif
+
+/* HANGONGOODLINK and HANGONGOODLINK
+ * Often net breaks for a short time and it's useful to try to
+ * establishing the same connection again faster than CONNECTFREQUENCY
+ * would allow. But, to keep trying on bad connection, we require
+ * that connection has been open for certain minimum time
+ * (HANGONGOODLINK) and we give the net few seconds to steady
+ * (HANGONRETRYDELAY). This latter has to be long enough that the
+ * other end of the connection has time to notice it broke too.
+ * 1997/09/18 recommended values by ThemBones for modern EFnet
+ */
+#define HANGONRETRYDELAY 60    /* Recommended value: 30-60 seconds */
+#define HANGONGOODLINK 3600    /* Recommended value: 30-60 minutes */
+
+/* KILLCHASETIMELIMIT -
+ * Max time from the nickname change that still causes KILL
+ * automatically to switch for the current nick of that user. (seconds)
+ */
+#define KILLCHASETIMELIMIT 90  /* Recommended value: 90 */
+
+/* RATBOX_SOMAXCONN
+ * Use SOMAXCONN if OS has it, otherwise use this value for the 
+ * listen(); backlog.  5 for AIX/SUNOS, 25 for other OSs.
+ */
+#define RATBOX_SOMAXCONN 25
+
+/* ----------------------------------------------------------------
+ * STOPSTOPSTOPSTOPSTOPSTOPSTOPSTOPSTOPSTOPSTOPSTOPSTOPSTOPSTOPSTOP
+ * ----------------------------------------------------------------
+ * The options below this line should NOT be modified.
+ * ----------------------------------------------------------------
+ */
+
+/* MAX_BUFFER
+ * The amount of fds to reserve for clients exempt from limits
+ * and dns lookups.
+ */
+#define MAX_BUFFER      60
+
+/* HARD_FDLIMIT_
+ * The maximum amount of FDs to use.  MAX_CLIENTS is set in ./configure.
+ */
+#define HARD_FDLIMIT_    MAX_CLIENTS + MAX_BUFFER + 20
+
+#define CONFIG_RATBOX_LEVEL_2
+
+#include "defaults.h"
+#endif /* INCLUDED_config_h */
diff --git a/include/defaults.h b/include/defaults.h
new file mode 100644 (file)
index 0000000..a0889fe
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  defaults.h: The ircd defaults header.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: defaults.h 6 2005-09-10 01:02:21Z nenolod $
+ */
+
+#ifndef INCLUDED_defaults_h
+#define INCLUDED_defaults_h
+
+/* this file is included (only) at the end of config.h, to supply default
+ * values for things which are now configurable at runtime.
+ */
+
+/*
+ * First, set other fd limits based on values from user
+ */
+#ifndef HARD_FDLIMIT_
+error HARD_FDLIMIT_ undefined
+#endif
+#define HARD_FDLIMIT    (HARD_FDLIMIT_ - 10)
+#define MAXCONNECTIONS  HARD_FDLIMIT
+#define MASTER_MAX      (HARD_FDLIMIT - MAX_BUFFER)
+/* class {} default values */
+#define DEFAULT_SENDQ 20000000 /* default max SendQ */
+#define PORTNUM 6667           /* default outgoing portnum */
+#define DEFAULT_PINGFREQUENCY    120   /* Default ping frequency */
+#define DEFAULT_CONNECTFREQUENCY 600   /* Default connect frequency */
+#define TS_MAX_DELTA_MIN      10       /* min value for ts_max_delta */
+#define TS_MAX_DELTA_DEFAULT  600      /* default for ts_max_delta */
+#define TS_WARN_DELTA_MIN     10       /* min value for ts_warn_delta */
+#define TS_WARN_DELTA_DEFAULT 30       /* default for ts_warn_delta */
+/* ServerInfo default values */
+#define NETWORK_NAME_DEFAULT "EFnet"   /* default for network_name */
+#define NETWORK_DESC_DEFAULT "Eris Free Network"       /* default for network_desc */
+/* General defaults */
+#define CLIENT_FLOOD_DEFAULT 20        /* default for client_flood */
+#define CLIENT_FLOOD_MAX     2000
+#define CLIENT_FLOOD_MIN     10
+#define LINKS_DELAY_DEFAULT  300
+#define MAX_TARGETS_DEFAULT 4  /* default for max_targets */
+#define IDENT_TIMEOUT 10
+#define MIN_JOIN_LEAVE_TIME  60
+#define MAX_JOIN_LEAVE_COUNT  25
+#define OPER_SPAM_COUNTDOWN   5
+#define JOIN_LEAVE_COUNT_EXPIRE_TIME 120
+#define MIN_SPAM_NUM 5
+#define MIN_SPAM_TIME 60
+#define CONFIG_RATBOX_LEVEL_1
+#endif                         /* INCLUDED_defaults_h */
diff --git a/include/hash.h b/include/hash.h
new file mode 100644 (file)
index 0000000..584f855
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  hash.h: A header for the ircd hashtable code.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: hash.h 722 2006-02-08 21:51:28Z nenolod $
+ */
+
+#ifndef INCLUDED_hash_h
+#define INCLUDED_hash_h
+
+#include "tools.h"
+
+extern dlink_list *clientTable;
+extern dlink_list *channelTable;
+extern dlink_list *idTable;
+extern dlink_list *resvTable;
+extern dlink_list *hostTable;
+extern dlink_list *helpTable;
+extern dlink_list *ndTable;
+
+/* Magic value for FNV hash functions */
+#define FNV1_32_INIT 0x811c9dc5UL
+
+/* Client hash table size, used in hash.c/s_debug.c */
+#define U_MAX_BITS (32-17)
+#define U_MAX 131072 /* 2^17 */
+
+/* Channel hash table size, hash.c/s_debug.c */
+#define CH_MAX_BITS (32-16)
+#define CH_MAX 65536 /* 2^16 */
+
+/* hostname hash table size */
+#define HOST_MAX_BITS (32-17)
+#define HOST_MAX 131072 /* 2^17 */
+
+/* RESV/XLINE hash table size, used in hash.c */
+#define R_MAX_BITS (32-10)
+#define R_MAX 1024 /* 2^10 */
+
+
+#define HASH_WALK(i, max, ptr, table) for (i = 0; i < max; i++) { DLINK_FOREACH(ptr, table[i].head)
+#define HASH_WALK_SAFE(i, max, ptr, nptr, table) for (i = 0; i < max; i++) { DLINK_FOREACH_SAFE(ptr, nptr, table[i].head)
+#define HASH_WALK_END }
+
+struct Client;
+struct Channel;
+struct ConfItem;
+struct cachefile;
+struct nd_entry;
+
+extern u_int32_t fnv_hash_upper(const unsigned char *s, int bits);
+extern u_int32_t fnv_hash(const unsigned char *s, int bits);
+extern u_int32_t fnv_hash_len(const unsigned char *s, int bits, int len);
+extern u_int32_t fnv_hash_upper_len(const unsigned char *s, int bits, int len);
+
+extern void init_hash(void);
+
+extern void add_to_client_hash(const char *name, struct Client *client);
+extern void del_from_client_hash(const char *name, struct Client *client);
+extern struct Client *find_any_client(const char *name);
+extern struct Client *find_client(const char *name);
+extern struct Client *find_named_client(const char *name);
+extern struct Client *find_server(struct Client *source_p, const char *name);
+
+extern void add_to_id_hash(const char *, struct Client *);
+extern void del_from_id_hash(const char *name, struct Client *client);
+extern struct Client *find_id(const char *name);
+
+extern struct Channel *get_or_create_channel(struct Client *client_p, const char *chname, int *isnew);
+extern void del_from_channel_hash(const char *name, struct Channel *chan);
+extern struct Channel *find_channel(const char *name);
+
+extern void add_to_hostname_hash(const char *, struct Client *);
+extern void del_from_hostname_hash(const char *, struct Client *);
+extern dlink_node *find_hostname(const char *);
+
+extern void add_to_resv_hash(const char *name, struct ConfItem *aconf);
+extern void del_from_resv_hash(const char *name, struct ConfItem *aconf);
+extern struct ConfItem *hash_find_resv(const char *name);
+extern void clear_resv_hash(void);
+
+extern void add_to_help_hash(const char *name, struct cachefile *hptr);
+extern void clear_help_hash(void);
+extern struct cachefile *hash_find_help(const char *name, int flags);
+
+extern void add_to_nd_hash(const char *name, struct nd_entry *nd);
+extern struct nd_entry *hash_find_nd(const char *name);
+
+extern void hash_stats(struct Client *);
+
+#endif /* INCLUDED_hash_h */
diff --git a/include/hook.h b/include/hook.h
new file mode 100644 (file)
index 0000000..b3d608b
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2004-2005 Lee Hardy <lee -at- leeh.co.uk>
+ * Copyright (C) 2004-2005 ircd-ratbox development team
+ *
+ * $Id: hook.h 906 2006-02-21 02:25:43Z nenolod $
+ */
+#ifndef INCLUDED_HOOK_H
+#define INCLUDED_HOOK_H
+
+typedef struct
+{
+       char *name;
+       dlink_list hooks;
+} hook;
+
+typedef void (*hookfn) (void *data);
+
+int h_iosend_id;
+int h_iorecv_id;
+int h_iorecvctrl_id;
+
+int h_burst_client;
+int h_burst_channel;
+int h_burst_finished;
+int h_server_introduced;
+int h_server_eob;
+int h_client_exit;
+int h_umode_changed;
+int h_new_local_user;
+int h_new_remote_user;
+int h_introduce_client;
+
+void init_hook(void);
+int register_hook(const char *name);
+void add_hook(const char *name, hookfn fn);
+void remove_hook(const char *name, hookfn fn);
+void call_hook(int id, void *arg);
+
+typedef struct
+{
+       struct Client *client;
+       const void *arg1;
+       const void *arg2;
+} hook_data;
+
+typedef struct
+{
+       struct Client *client;
+       const void *arg1;
+       int arg2;
+} hook_data_int;
+
+typedef struct
+{
+       struct Client *client;
+       struct Client *target;
+} hook_data_client;
+
+typedef struct
+{
+       struct Client *client;
+       struct Channel *chptr;
+       int approved;
+} hook_data_channel;
+
+typedef struct
+{
+       struct Client *client;
+       struct Channel *chptr;
+       char *key;
+} hook_data_channel_activity;
+
+typedef struct
+{
+       struct Client *client;
+       int approved;
+} hook_data_client_approval;
+
+typedef struct
+{
+       struct Client *local_link; /* local client originating this, or NULL */
+       struct Client *target; /* dying client */
+       struct Client *from; /* causing client (could be &me or target) */
+       const char *comment;
+} hook_data_client_exit;
+
+typedef struct
+{
+       struct Client *client;
+       unsigned int oldumodes;
+       unsigned int oldsnomask;
+} hook_data_umode_changed;
+
+#endif
diff --git a/include/hostmask.h b/include/hostmask.h
new file mode 100644 (file)
index 0000000..ebd8bfc
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ *  charybdis: an advanced Internet Relay Chat Daemon(ircd).
+ *  hostmask.h: A header for the hostmask code.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development team
+ *  Copyright (C) 2005-2006 charybdis development 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: hostmask.h 2757 2006-11-10 22:58:15Z jilles $
+ */
+
+#ifndef INCLUDE_hostmask_h
+#define INCLUDE_hostmask_h 1
+enum
+{
+       HM_HOST,
+       HM_IPV4
+#ifdef IPV6
+               , HM_IPV6
+#endif
+};
+
+int parse_netmask(const char *, struct sockaddr *, int *);
+struct ConfItem *find_conf_by_address(const char *host, const char *sockhost,
+                                     const char *orighost, struct sockaddr *,
+                                     int, int, const char *);
+void add_conf_by_address(const char *, int, const char *, struct ConfItem *);
+void delete_one_address_conf(const char *, struct ConfItem *);
+void clear_out_address_conf(void);
+void clear_out_address_conf_bans(void);
+void init_host_hash(void);
+struct ConfItem *find_address_conf(const char *host, const char *sockhost, 
+                               const char *, const char *, struct sockaddr *,
+                               int);
+
+struct ConfItem *find_dline(struct sockaddr *, int);
+
+#define find_kline(x)  (find_conf_by_address((x)->host, (x)->sockhost, \
+                        (x)->orighost, \
+                        (struct sockaddr *)&(x)->localClient->ip, CONF_KILL,\
+                        (x)->localClient->ip.ss_family, (x)->username))
+#define find_gline(x)  (find_conf_by_address((x)->host, (x)->sockhost, \
+                        (x)->orighost, \
+                        (struct sockaddr *)&(x)->localClient->ip, CONF_GLINE,\
+                        (x)->localClient->ip.ss_family, (x)->username))
+
+void report_Klines(struct Client *);
+void report_auth(struct Client *);
+#ifdef IPV6
+int match_ipv6(struct sockaddr *, struct sockaddr *, int);
+#endif
+int match_ipv4(struct sockaddr *, struct sockaddr *, int);
+
+/* Hashtable stuff... */
+#define ATABLE_SIZE 0x1000 /* 2^12 */
+#define ATABLE_BITS (32-12)
+
+extern struct AddressRec *atable[ATABLE_SIZE];
+
+struct AddressRec
+{
+       /* masktype: HM_HOST, HM_IPV4, HM_IPV6 -A1kmm */
+       int masktype;
+
+       union
+       {
+               struct
+               {
+                       /* Pointer into ConfItem... -A1kmm */
+                       struct irc_sockaddr_storage addr;
+                       int bits;
+               }
+               ipa;
+
+               /* Pointer into ConfItem... -A1kmm */
+               const char *hostname;
+       }
+       Mask;
+
+       /* type: CONF_CLIENT, CONF_DLINE, CONF_KILL etc... -A1kmm */
+       int type;
+
+       /* Higher precedences overrule lower ones... */
+       unsigned long precedence;
+
+       /* Only checked if !(type & 1)... */
+       const char *username;
+       struct ConfItem *aconf;
+
+       /* The next record in this hash bucket. */
+       struct AddressRec *next;
+};
+
+
+#endif /* INCLUDE_hostmask_h */
diff --git a/include/irc_string.h b/include/irc_string.h
new file mode 100644 (file)
index 0000000..d2bd104
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  irc_string.h: A header for the ircd string functions.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: irc_string.h 678 2006-02-03 20:25:01Z jilles $
+ */
+
+#ifndef INCLUDED_irc_string_h
+#define INCLUDED_irc_string_h
+
+#include "setup.h"
+#include "ircd_defs.h"
+
+/*
+ * match - compare name with mask, mask may contain * and ? as wildcards
+ * match - returns 1 on successful match, 0 otherwise
+ *
+ * match_esc - compare with support for escaping chars
+ * match_cidr - compares u!h@addr with u!h@addr/cidr
+ * match_ips - compares addr with addr/cidr in ascii form
+ */
+extern int match(const char *mask, const char *name);
+extern int match_esc(const char *mask, const char *name);
+extern int match_cidr(const char *mask, const char *name);
+extern int match_ips(const char *mask, const char *name);
+
+/*
+ * comp_with_mask - compares to IP address
+ */
+int comp_with_mask(void *addr, void *dest, u_int mask);
+int comp_with_mask_sock(struct sockaddr *addr, struct sockaddr *dest, u_int mask);
+
+/*
+ * collapse - collapse a string in place, converts multiple adjacent *'s 
+ * into a single *.
+ * collapse - modifies the contents of pattern 
+ *
+ * collapse_esc() - collapse with support for escaping chars
+ */
+extern char *collapse(char *pattern);
+extern char *collapse_esc(char *pattern);
+
+/*
+ * irccmp - case insensitive comparison of s1 and s2
+ */
+extern int irccmp(const char *s1, const char *s2);
+/*
+ * ircncmp - counted case insensitive comparison of s1 and s2
+ */
+extern int ircncmp(const char *s1, const char *s2, int n);
+/*
+** canonize - reduce a string of duplicate list entries to contain
+** only the unique items.
+*/
+#ifdef NO_DUPE_MULTI_MESSAGES
+extern char *canonize(char *);
+#endif
+/*
+ * inetntoa - optimized inet_ntoa
+ */
+const char *inetntoa(const char *in_addr);
+
+/* 
+ * inetntop() 
+ * inetpton()
+ * portable interfaces for inet_ntop() and inet_pton()
+ */
+const char *inetntop(int af, const void *src, char *dst, unsigned int size);
+int inetpton(int af, const char *src, void *dst);
+const char *inetntop_sock(struct sockaddr *src, char *dst, unsigned int size);
+int inetpton_sock(const char *src, struct sockaddr *dst);
+
+#ifndef HAVE_STRLCPY
+size_t strlcpy(char *dst, const char *src, size_t siz);
+#endif
+
+#ifndef HAVE_STRLCAT
+size_t strlcat(char *dst, const char *src, size_t siz);
+#endif
+
+#ifdef HAVE_STRDUP
+#define DupString(x,y) do { x = strdup(y); if(x == NULL) outofmemory(); } while(0)
+#else
+#define DupString(x,y) do { x = malloc(strlen(y) + 1); if(x == NULL) outofmemory(); strcpy(x, y); } while(0)
+#endif
+
+#ifdef HAVE_STRNDUP
+#define DupNString(x, y, len) do { x = strndup(y, len); if(x == NULL) outofmemory(); } while (0)
+#else
+#define DupNString(x, y, len) do { x = malloc(len+1); if(x == NULL) outofmemory(); strlcpy(x, y, len+1); } while(0)
+#endif
+
+/*
+ * clean_string - cleanup control and high ascii characters
+ * -Dianora
+ */
+char *clean_string(char *dest, const unsigned char *src, size_t len);
+
+/*
+ * strip_colour - remove colour codes from a string
+ * -asuffield (?)
+ */
+char *strip_colour(char *string);
+
+/*
+ * strip_tabs - convert tabs to spaces
+ * - jdc
+ */
+char *strip_tabs(char *dest, const unsigned char *src, size_t len);
+
+const char *myctime(time_t);
+
+#define EmptyString(x) (!(x) || (*(x) == '\0'))
+#define CheckEmpty(x) EmptyString(x) ? "" : x
+
+char *strtoken(char **save, char *str, const char *fs);
+
+unsigned char *ircd_base64_encode(const unsigned char *str, int length);
+unsigned char *ircd_base64_decode(const unsigned char *str, int length, int *ret);
+
+/*
+ * character macros
+ */
+extern const unsigned char ToLowerTab[];
+#define ToLower(c) (ToLowerTab[(unsigned char)(c)])
+
+extern const unsigned char ToUpperTab[];
+#define ToUpper(c) (ToUpperTab[(unsigned char)(c)])
+
+extern const unsigned int CharAttrs[];
+
+#define PRINT_C   0x001
+#define CNTRL_C   0x002
+#define ALPHA_C   0x004
+#define PUNCT_C   0x008
+#define DIGIT_C   0x010
+#define SPACE_C   0x020
+#define NICK_C    0x040
+#define CHAN_C    0x080
+#define KWILD_C   0x100
+#define CHANPFX_C 0x200
+#define USER_C    0x400
+#define HOST_C    0x800
+#define NONEOS_C 0x1000
+#define SERV_C   0x2000
+#define EOL_C    0x4000
+#define MWILD_C  0x8000
+#define LET_C   0x10000 /* an actual letter */
+#define FCHAN_C 0x20000 /* a 'fake' channel char */
+
+#define IsHostChar(c)   (CharAttrs[(unsigned char)(c)] & HOST_C)
+#define IsUserChar(c)   (CharAttrs[(unsigned char)(c)] & USER_C)
+#define IsChanPrefix(c) (CharAttrs[(unsigned char)(c)] & CHANPFX_C)
+#define IsChanChar(c)   (CharAttrs[(unsigned char)(c)] & CHAN_C)
+#define IsFakeChanChar(c)      (CharAttrs[(unsigned char)(c)] & FCHAN_C)
+#define IsKWildChar(c)  (CharAttrs[(unsigned char)(c)] & KWILD_C)
+#define IsMWildChar(c)  (CharAttrs[(unsigned char)(c)] & MWILD_C)
+#define IsNickChar(c)   (CharAttrs[(unsigned char)(c)] & NICK_C)
+#define IsServChar(c)   (CharAttrs[(unsigned char)(c)] & (NICK_C | SERV_C))
+#define IsIdChar(c)    (CharAttrs[(unsigned char)(c)] & (DIGIT_C | LET_C))
+#define IsLetter(c)    (CharAttrs[(unsigned char)(c)] & LET_C)
+#define IsCntrl(c)      (CharAttrs[(unsigned char)(c)] & CNTRL_C)
+#define IsAlpha(c)      (CharAttrs[(unsigned char)(c)] & ALPHA_C)
+#define IsSpace(c)      (CharAttrs[(unsigned char)(c)] & SPACE_C)
+#define IsLower(c)      (IsAlpha((c)) && ((unsigned char)(c) > 0x5f))
+#define IsUpper(c)      (IsAlpha((c)) && ((unsigned char)(c) < 0x60))
+#define IsDigit(c)      (CharAttrs[(unsigned char)(c)] & DIGIT_C)
+#define IsXDigit(c) (IsDigit(c) || ('a' <= (c) && (c) <= 'f') || \
+        ('A' <= (c) && (c) <= 'F'))
+#define IsAlNum(c) (CharAttrs[(unsigned char)(c)] & (DIGIT_C | ALPHA_C))
+#define IsPrint(c) (CharAttrs[(unsigned char)(c)] & PRINT_C)
+#define IsAscii(c) ((unsigned char)(c) < 0x80)
+#define IsGraph(c) (IsPrint((c)) && ((unsigned char)(c) != 0x32))
+#define IsPunct(c) (!(CharAttrs[(unsigned char)(c)] & \
+                                           (CNTRL_C | ALPHA_C | DIGIT_C)))
+
+#define IsNonEOS(c) (CharAttrs[(unsigned char)(c)] & NONEOS_C)
+#define IsEol(c) (CharAttrs[(unsigned char)(c)] & EOL_C)
+
+#endif /* INCLUDED_irc_string_h */
diff --git a/include/ircd.h b/include/ircd.h
new file mode 100644 (file)
index 0000000..a530e68
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  ircd.h: A header for the ircd startup routines.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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.h 1851 2006-08-24 17:16:53Z jilles $
+ */
+
+#ifndef INCLUDED_ircd_h
+#define INCLUDED_ircd_h
+
+#include "config.h"
+#include "tools.h"
+#include "memory.h"
+
+struct Client;
+struct dlink_list;
+
+struct SetOptions
+{
+       int maxclients;         /* max clients allowed */
+       int autoconn;           /* autoconn enabled for all servers? */
+
+       int idletime;
+
+       int floodcount;         /* Number of messages in 1 second */
+       int ident_timeout;      /* timeout for identd lookups */
+
+       int spam_num;
+       int spam_time;
+
+       char operstring[REALLEN];
+       char adminstring[REALLEN];
+};
+
+struct Counter
+{
+       int oper;               /* Opers */
+       int total;              /* total clients */
+       int invisi;             /* invisible clients */
+       int max_loc;            /* MAX local clients */
+       int max_tot;            /* MAX global clients */
+       unsigned long totalrestartcount;        /* Total client count ever */
+};
+
+extern struct SetOptions GlobalSetOptions;     /* defined in ircd.c */
+
+extern const char *creation;
+extern const char *generation;
+extern const char *platform;
+extern const char *infotext[];
+extern const char *serno;
+extern const char *ircd_version;
+extern const char *logFileName;
+extern const char *pidFileName;
+extern int cold_start;
+extern int dorehash;
+extern int dorehashbans;
+extern int doremotd;
+extern int kline_queued;
+extern int server_state_foreground;
+extern int opers_see_all_users; /* sno_farconnect.so loaded, operspy without
+                                  accountability, etc */
+
+extern struct Client me;
+extern dlink_list global_client_list;
+extern struct Client *local[];
+extern struct Counter Count;
+#if 0
+extern time_t CurrentTime;
+#endif
+extern struct timeval SystemTime;
+#define CurrentTime SystemTime.tv_sec
+extern int default_server_capabs;
+
+extern time_t startup_time;
+
+extern int splitmode;
+extern int splitchecking;
+extern int split_users;
+extern int split_servers;
+int eob_count;
+
+extern dlink_list unknown_list;
+extern dlink_list lclient_list;
+extern dlink_list serv_list;
+extern dlink_list global_serv_list;
+extern dlink_list local_oper_list;
+extern dlink_list oper_list;
+extern dlink_list dead_list;
+
+extern void get_current_bandwidth(struct Client *source_p, struct Client *target_p);
+
+extern unsigned long get_maxrss(void);
+extern void set_time(void);
+extern void charybdis_io_loop(void);
+
+extern int testing_conf;
+
+#endif
diff --git a/include/ircd_defs.h b/include/ircd_defs.h
new file mode 100644 (file)
index 0000000..66918e3
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ *  charybdis: An advanced IRCd.
+ *  ircd_defs.h: A header for ircd global definitions.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development team
+ *  Copyright (C) 2005-2006 Charybdis development 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_defs.h 865 2006-02-16 14:05:37Z nenolod $
+ */
+
+/*
+ * NOTE: NICKLEN and TOPICLEN do not live here anymore. Set it with configure
+ * Otherwise there are no user servicable part here. 
+ *
+ */
+ /* ircd_defs.h - Global size definitions for record entries used
+  * througout ircd. Please think 3 times before adding anything to this
+  * file.
+  */
+#ifndef INCLUDED_ircd_defs_h
+#define INCLUDED_ircd_defs_h
+
+#include "config.h"
+
+/* For those unfamiliar with GNU format attributes, a is the 1 based
+ * argument number of the format string, and b is the 1 based argument
+ * number of the variadic ... */
+#ifdef __GNUC__
+#define AFP(a,b) __attribute__((format (printf, a, b)))
+#else
+#define AFP(a,b)
+#endif
+
+
+#include "s_log.h"
+#include "send.h"
+
+#ifdef SOFT_ASSERT
+#ifdef __GNUC__
+#define s_assert(expr) do                                                              \
+                       if(!(expr)) {                                                   \
+                               ilog(L_MAIN,                                            \
+                               "file: %s line: %d (%s): Assertion failed: (%s)",       \
+                               __FILE__, __LINE__, __PRETTY_FUNCTION__, #expr);        \
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,                      \
+                               "file: %s line: %d (%s): Assertion failed: (%s)",       \
+                               __FILE__, __LINE__, __PRETTY_FUNCTION__, #expr);        \
+                       }                                                               \
+                       while(0)
+#else
+#define s_assert(expr) do                                                              \
+                       if(!(expr)) {                                                   \
+                               ilog(L_MAIN,                                            \
+                               "file: %s line: %d: Assertion failed: (%s)",            \
+                               __FILE__, __LINE__, #expr);                             \
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,                      \
+                               "file: %s line: %d: Assertion failed: (%s)"             \
+                               __FILE__, __LINE__, #expr);                             \
+                       }                                                               \
+                       while(0)
+#endif
+#else
+#define s_assert(expr) assert(expr)
+#endif
+
+#if !defined(CONFIG_RATBOX_LEVEL_1)
+#  error Incorrect config.h for this revision of ircd.
+#endif
+
+/*
+ * This defines the version of the data structures used in the ircd.
+ * In the event of a mismatch (i.e. this is incremented due to a major
+ * change that cannot be accomidated for in the ircd), then a hard
+ * restart occurs.
+ */
+#define CHARYBDIS_DV   0x00010200      /* 1.2.0 */
+
+#define HOSTLEN         63     /* Length of hostname.  Updated to         */
+                               /* comply with RFC1123                     */
+
+#define USERLEN         10
+#define REALLEN         50
+#define CHANNELLEN      200
+#define LOC_CHANNELLEN 50
+
+/* reason length of klines, parts, quits etc */
+#define REASONLEN      TOPICLEN        /* in charybdis, reasonlen is controlled via topiclen */
+#define AWAYLEN                TOPICLEN        /* ditto for awaylen */
+#define KILLLEN         TOPICLEN       /* and killlen. have a nice day. --nenolod */
+
+/* 23+1 for \0 */
+#define KEYLEN          24
+#define BUFSIZE         512    /* WARNING: *DONT* CHANGE THIS!!!! */
+#define MAXRECIPIENTS   20
+#define MAXBANLENGTH    1024
+#define OPERNICKLEN     NICKLEN*2      /* Length of OPERNICKs. */
+
+#define USERHOST_REPLYLEN       (NICKLEN+HOSTLEN+USERLEN+5)
+#define MAX_DATE_STRING 32     /* maximum string length for a date string */
+
+#define HELPLEN         400
+
+/* 
+ * message return values 
+ */
+#define CLIENT_EXITED    -2
+#define CLIENT_PARSE_ERROR -1
+#define CLIENT_OK      1
+
+#ifdef IPV6
+#ifndef AF_INET6
+#error "AF_INET6 not defined"
+#endif
+
+
+#else /* #ifdef IPV6 */
+
+#ifndef AF_INET6
+#define AF_INET6 AF_MAX                /* Dummy AF_INET6 declaration */
+#endif
+#endif /* #ifdef IPV6 */
+
+
+#ifdef IPV6
+#define irc_sockaddr_storage sockaddr_storage
+#else
+#define irc_sockaddr_storage sockaddr
+#define ss_family sa_family
+#ifdef SOCKADDR_IN_HAS_LEN
+#define ss_len sa_len
+#endif
+#endif
+
+#ifdef IPV6
+#define PATRICIA_BITS  128
+#else
+#define PATRICIA_BITS  32
+#endif
+
+#ifdef SOCKADDR_IN_HAS_LEN
+#define SET_SS_LEN(x, y) (x).ss_len = (y)
+#define GET_SS_LEN(x) x.ss_len
+#else
+#define SET_SS_LEN(x, y)
+#ifdef IPV6
+#define GET_SS_LEN(x) x.ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)
+#else
+#define GET_SS_LEN(x) sizeof(struct sockaddr_in)
+#endif
+#endif
+
+
+#endif /* INCLUDED_ircd_defs_h */
diff --git a/include/ircd_getopt.h b/include/ircd_getopt.h
new file mode 100644 (file)
index 0000000..ddc9e4d
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  ircd_getopt.h: A header for the getopt() command line option calls.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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_getopt.h 6 2005-09-10 01:02:21Z nenolod $
+ */
+
+#ifndef __GETOPT_H_INCLUDED__
+#define __GETOPT_H_INCLUDED__
+
+struct lgetopt
+{
+       const char *opt;        /* name of the argument */
+       void *argloc;           /* where we store the argument to it (-option argument) */
+       enum
+       { INTEGER, YESNO, STRING, USAGE, ENDEBUG }
+       argtype;
+       const char *desc;       /* description of the argument, usage for printing help */
+};
+
+extern struct lgetopt myopts[];
+
+void usage(char *);
+void parseargs(int *, char ***, struct lgetopt *);
+
+#endif /* __GETOPT_H_INCLUDED__ */
diff --git a/include/ircd_linker.h b/include/ircd_linker.h
new file mode 100644 (file)
index 0000000..feb651e
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * charybdis: An advanced ircd.
+ * ircd_linker.h: IRCd symbol table linking and maintainance
+ *
+ * Copyright (c) 2006 William Pitcock <nenolod@nenolod.net>
+ *
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: ircd_linker.h 863 2006-02-16 06:51:59Z nenolod $
+ */
+
+#ifndef _CHARYBDIS_IRCD_LINKER_H
+#define _CHARYBDIS_IRCD_LINKER_H
+
+#include <dlfcn.h>
+
+struct ircd_symbol
+{
+       char *sym;      /* name of symbol to be bound to ptr */
+       void *ptr;      /* ptr to symbol in library */
+};
+
+extern void build_symtable(void *, struct ircd_symbol *);
+extern void report_symtable(struct ircd_symbol *);
+
+#endif
diff --git a/include/ircd_signal.h b/include/ircd_signal.h
new file mode 100644 (file)
index 0000000..ddff2bc
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  ircd_signal.h: A header for ircd signals.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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_signal.h 6 2005-09-10 01:02:21Z nenolod $
+ */
+
+#ifndef INCLUDED_ircd_signal_h
+#define INCLUDED_ircd_signal_h
+
+extern void setup_signals(void);
+
+#endif /* INCLUDED_ircd_signal_h */
diff --git a/include/ircd_state.h b/include/ircd_state.h
new file mode 100644 (file)
index 0000000..8d488b3
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * charybdis: An advanced ircd.
+ * ircd_state.h: Functions for backing up and synchronizing IRCd's state
+ *
+ * Copyright (c) 2006 William Pitcock <nenolod@nenolod.net>
+ *
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: main.c 867 2006-02-16 14:25:09Z nenolod $
+ */
+
+#ifndef _IRCD_STATE_H
+#define _IRCD_STATE_H
+
+#include "stdinc.h"
+#include "setup.h"
+#include "config.h"
+#include "ircd_defs.h"
+#include "ircd_linker.h"
+#include "ircd_state.h"
+
+#ifdef NOTYET
+
+/* I haven't designed this structure yet, so this is a placeholder. */
+struct IRCdState {
+       void *moo;
+};
+
+#endif
+
+#endif
diff --git a/include/listener.h b/include/listener.h
new file mode 100644 (file)
index 0000000..9bab533
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  listener.h: A header for the listener code.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: listener.h 6 2005-09-10 01:02:21Z nenolod $
+ */
+
+#ifndef INCLUDED_listener_h
+#define INCLUDED_listener_h
+
+#include "ircd_defs.h"
+
+struct Client;
+
+struct Listener
+{
+       struct Listener *next;  /* list node pointer */
+       const char *name;       /* listener name */
+       int fd;                 /* file descriptor */
+       int ref_count;          /* number of connection references */
+       int active;             /* current state of listener */
+       int index;              /* index into poll array */
+       struct irc_sockaddr_storage addr;
+       struct DNSQuery *dns_query;
+       char vhost[HOSTLEN + 1];        /* virtual name of listener */
+};
+
+extern void add_listener(int port, const char *vaddr_ip, int family);
+extern void close_listener(struct Listener *listener);
+extern void close_listeners(void);
+extern const char *get_listener_name(const struct Listener *listener);
+extern void show_ports(struct Client *client);
+extern void free_listener(struct Listener *);
+
+#endif /* INCLUDED_listener_h */
diff --git a/include/m_info.h b/include/m_info.h
new file mode 100644 (file)
index 0000000..141133f
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_info.h: A header for the information sent by /info
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: m_info.h 70 2005-09-10 07:03:09Z nenolod $
+ */
+
+#ifndef INCLUDED_m_info_h
+#define INCLUDED_m_info_h
+
+#include "config.h"
+
+typedef struct Information
+{
+       const char *name;       /* name of item */
+       const char *strvalue;   /* value of item if it's a boolean */
+       int intvalue;           /* value of item if it's an integer */
+       const char *desc;       /* short description of item */
+}
+Info;
+
+Info MyInformation[] = {
+
+#ifdef CPATH
+       {"CPATH", CPATH, 0, "Path to Main Configuration File"},
+#else
+       {"CPATH", "NONE", 0, "Path to Main Configuration File"},
+#endif /* CPATH */
+
+#ifdef DPATH
+       {"DPATH", DPATH, 0, "Directory Containing Configuration Files"},
+#else
+       {"DPATH", "NONE", 0, "Directory Containing Configuration Files"},
+#endif /* DPATH */
+
+#ifdef DLPATH
+       {"DLPATH", DLPATH, 0, "Path to D-line File"},
+#else
+       {"DLPATH", "NONE", 0, "Path to D-line File"},
+#endif /* DLPATH */
+
+#ifdef RESVPATH
+       {"RESVPATH", RESVPATH, 0, "Path to resv file"},
+#else
+       {"RESVPATH", "NONE", 0, "Path to resv file"},
+#endif
+
+       {"HARD_FDLIMIT_", "", HARD_FDLIMIT_,
+        "Maximum Number of File Descriptors Available"},
+
+#ifdef HPATH
+       {"HPATH", HPATH, 0, "Path to Operator Help Files"},
+#else
+       {"HPATH", "NONE", 0, "Path to Operator Help Files"},
+#endif /* HPATH */
+
+#ifdef UHPATH
+       {"UHPATH", UHPATH, 0, "Path to User Help Files"},
+#else
+       {"UHPATH", "NONE", 0, "Path to User Help Files"},
+#endif /* UH PATH */
+
+#ifdef SOMAXCONN
+       {"RATBOX_SOMAXCONN", "", SOMAXCONN,
+        "Maximum Queue Length of Pending Connections"},
+#else
+       {"RATBOX_SOMAXCONN", "", RATBOX_SOMAXCONN,
+        "Maximum Queue Length of Pending Connections"},
+#endif /* SOMAXCONN */
+
+#ifdef IPV6
+       {"IPV6", "ON", 0, "IPv6 Support"},
+#else
+       {"IPV6", "OFF", 0, "IPv6 Support"},
+#endif
+
+       {"MAX_CLIENTS", "", MAX_CLIENTS, "Default maximum Clients"},
+
+       {"JOIN_LEAVE_COUNT_EXPIRE_TIME", "", JOIN_LEAVE_COUNT_EXPIRE_TIME,
+        "Anti SpamBot Parameter"},
+
+       {"KILLCHASETIMELIMIT", "", KILLCHASETIMELIMIT,
+        "Nick Change Tracker for KILL"},
+
+#ifdef KPATH
+       {"KPATH", KPATH, 0, "Path to K-line File"},
+#else
+       {"KPATH", "NONE", 0, "Path to K-line File"},
+#endif /* KPATH */
+
+#ifdef LPATH
+       {"LPATH", LPATH, 0, "Path to Log File"},
+#else
+       {"LPATH", "NONE", 0, "Path to Log File"},
+#endif /* LPATH */
+
+       {"MAX_BUFFER", "", MAX_BUFFER, "Maximum Buffer Connections Allowed"},
+
+       {"MAX_JOIN_LEAVE_COUNT", "", MAX_JOIN_LEAVE_COUNT,
+        "Anti SpamBot Parameter"},
+
+       {"MIN_JOIN_LEAVE_TIME", "", MIN_JOIN_LEAVE_TIME,
+        "Anti SpamBot Parameter"},
+
+#ifdef MPATH
+       {"MPATH", MPATH, 0, "Path to MOTD File"},
+#else
+       {"MPATH", "NONE", 0, "Path to MOTD File"},
+#endif /* MPATH */
+
+       {"NICKNAMEHISTORYLENGTH", "", NICKNAMEHISTORYLENGTH,
+        "Size of WHOWAS Array"},
+
+#ifdef OPATH
+       {"OPATH", OPATH, 0, "Path to Operator MOTD File"},
+#else
+       {"OPATH", "NONE", 0, "Path to Operator MOTD File"},
+#endif /* OPATH */
+
+       {"OPER_SPAM_COUNTDOWN", "", OPER_SPAM_COUNTDOWN,
+        "Anti SpamBot Parameter"},
+
+#ifdef HAVE_LIBCRYPTO
+       {"HAVE_LIBCRYPTO", "ON", 0, "Enable OpenSSL CHALLENGE Support"},
+#else
+       {"HAVE_LIBCRYPTO", "OFF", 0, "Enable OpenSSL CHALLENGE Support"},
+#endif /* HAVE_LIBCRYPTO */
+
+#ifdef HAVE_LIBZ
+       {"HAVE_LIBZ", "YES", 0, "zlib (ziplinks) support"},
+#else
+       {"HAVE_LIBZ", "NO", 0, "zlib (ziplinks)  support"},
+#endif /* HAVE_LIBZ */
+
+#ifdef PPATH
+       {"PPATH", PPATH, 0, "Path to Pid File"},
+#else
+       {"PPATH", "NONE", 0, "Path to Pid File"},
+#endif /* PPATH */
+
+       {"SELECT_TYPE", SELECT_TYPE, 0, "Method of Multiplexed I/O"},
+
+#ifdef SPATH
+       {"SPATH", SPATH, 0, "Path to Server Executable"},
+#else
+       {"SPATH", "NONE", 0, "Path to Server Executable"},
+#endif /* SPATH */
+
+       {"TS_MAX_DELTA_DEFAULT", "", TS_MAX_DELTA_DEFAULT,
+        "Maximum Allowed TS Delta from another Server"},
+       {"TS_WARN_DELTA_DEFAULT", "", TS_WARN_DELTA_DEFAULT,
+        "Maximum TS Delta before Sending Warning"},
+#ifdef USE_IODEBUG_HOOKS
+       {"USE_IODEBUG_HOOKS", "YES", 0, "IO Debugging support"},
+#else
+       {"USE_IODEBUG_HOOKS", "NO", 0, "IO Debugging support"},
+#endif
+
+       /*
+        * since we don't want to include the world here, NULL probably
+        * isn't defined by the time we read this, just use plain 0 instead
+        * 0 is guaranteed by the language to be assignable to ALL built
+        * in types with the correct results.
+        */
+       {0, 0, 0, 0}
+};
+
+
+#endif /* INCLUDED_m_info_h */
diff --git a/include/modules.h b/include/modules.h
new file mode 100644 (file)
index 0000000..168a7ac
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  modules.h: A header for the modules functions.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: modules.h 6 2005-09-10 01:02:21Z nenolod $
+ */
+
+#ifndef INCLUDED_modules_h
+#define INCLUDED_modules_h
+#include "config.h"
+#include "setup.h"
+#include "parse.h"
+
+#define MAPI_RATBOX 1
+
+#if defined(HAVE_SHL_LOAD)
+#include <dl.h>
+#endif
+#if !defined(STATIC_MODULES) && defined(HAVE_DLFCN_H)
+#include <dlfcn.h>
+#endif
+
+#include "msg.h"
+#include "memory.h"
+#include "hook.h"
+
+struct module
+{
+       char *name;
+       const char *version;
+       void *address;
+       int core;
+       int mapi_version;
+       void * mapi_header; /* actually struct mapi_mheader_av<mapi_version>    */
+};
+
+struct module_path
+{
+       char path[MAXPATHLEN];
+};
+
+#define MAPI_MAGIC_HDR 0x4D410000
+
+#define MAPI_V1                (MAPI_MAGIC_HDR | 0x1)
+
+#define MAPI_MAGIC(x)  ((x) & 0xffff0000)
+#define MAPI_VERSION(x)        ((x) & 0x0000ffff)
+
+typedef struct Message* mapi_clist_av1;
+
+typedef struct
+{
+       const char *    hapi_name;
+       int *           hapi_id;
+} mapi_hlist_av1;
+
+typedef struct
+{
+       const char *    hapi_name;
+       hookfn          fn;
+} mapi_hfn_list_av1;
+
+struct mapi_mheader_av1
+{
+       int               mapi_version;                         /* Module API version           */
+       int             (*mapi_register)        (void);         /* Register function;
+                                                                  ret -1 = failure (unload)    */
+       void            (*mapi_unregister)      (void);         /* Unregister function.         */
+       mapi_clist_av1  * mapi_command_list;                    /* List of commands to add.     */
+       mapi_hlist_av1  * mapi_hook_list;                       /* List of hooks to add.        */
+       mapi_hfn_list_av1 *mapi_hfn_list;                       /* List of hook_add_hook's to do */
+       const char *      mapi_module_version;                  /* Module's version (freeform)  */
+};
+
+#ifndef STATIC_MODULES
+# define DECLARE_MODULE_AV1(name,reg,unreg,cl,hl,hfnlist, v) \
+       struct mapi_mheader_av1 _mheader = { MAPI_V1, reg, unreg, cl, hl, hfnlist, v}
+#else
+# define DECLARE_MODULE_AV1(name,reg,unreg,cl,hl,hfnlist, v) \
+       struct mapi_mheader_av1 name ## _mheader = { MAPI_V1, reg, unreg, cl, hl, hfnlist, v}
+void load_static_modules(void);
+#endif
+
+/* add a path */
+void mod_add_path(const char *path);
+void mod_clear_paths(void);
+
+/* load a module */
+extern void load_module(char *path);
+
+/* load all modules */
+extern void load_all_modules(int warn);
+
+/* load core modules */
+extern void load_core_modules(int);
+
+extern int unload_one_module(const char *, int);
+extern int load_one_module(const char *, int);
+extern int load_a_module(const char *, int, int);
+extern int findmodule_byname(const char *);
+extern char *irc_basename(const char *);
+extern void modules_init(void);
+
+#endif /* INCLUDED_modules_h */
diff --git a/include/monitor.h b/include/monitor.h
new file mode 100644 (file)
index 0000000..5e0eb49
--- /dev/null
@@ -0,0 +1,32 @@
+/* 
+ * ircd-ratbox: an advanced Internet Relay Chat Daemon(ircd).
+ * monitor.h: Code for server-side notify lists.
+ *
+ * Copyright (C) 2005 Lee Hardy <lee -at- leeh.co.uk>
+ * Copyright (C) 2005 ircd-ratbox development team
+ *
+ * $Id: monitor.h 6 2005-09-10 01:02:21Z nenolod $
+ */
+#ifndef INCLUDED_monitor_h
+#define INCLUDED_monitor_h
+
+struct monitor
+{
+       struct monitor *hnext;
+       char name[NICKLEN];
+       dlink_list users;
+};
+
+extern BlockHeap *monitor_heap;
+
+#define MONITOR_HASH_SIZE 65536
+#define MONITOR_HASH_BITS 16
+
+void init_monitor(void);
+struct monitor *find_monitor(const char *name, int add);
+void clear_monitor(struct Client *);
+
+void monitor_signon(struct Client *);
+void monitor_signoff(struct Client *);
+
+#endif
diff --git a/include/msg.h b/include/msg.h
new file mode 100644 (file)
index 0000000..283eb9b
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  msg.h: A header for the message handler structure.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: msg.h 6 2005-09-10 01:02:21Z nenolod $
+ */
+
+#ifndef INCLUDED_msg_h
+#define INCLUDED_msg_h
+
+#include "config.h"
+
+struct Client;
+
+/* MessageHandler */
+typedef enum HandlerType
+{
+       UNREGISTERED_HANDLER,
+       CLIENT_HANDLER,
+       RCLIENT_HANDLER,
+       SERVER_HANDLER,
+       ENCAP_HANDLER,
+       OPER_HANDLER,
+       LAST_HANDLER_TYPE
+}
+HandlerType;
+
+/* struct Client* client_p   - connection message originated from
+ * struct Client* source_p   - source of message, may be different from client_p
+ * int            parc   - parameter count
+ * char*          parv[] - parameter vector
+ */
+typedef int (*MessageHandler) (struct Client *, struct Client *, int, const char *[]);
+
+struct MessageEntry
+{
+       MessageHandler handler;
+       int min_para;
+};
+
+/* Message table structure */
+struct Message
+{
+       const char *cmd;
+       unsigned int count;     /* number of times command used */
+       unsigned int rcount;    /* number of times command used by server */
+       unsigned long bytes;    /* bytes received for this message */
+       unsigned int flags;     /* bit 0 set means that this command is allowed
+                                * to be used only on the average of once per 2
+                                * seconds -SRB
+                                */
+       /* handlers:
+        * UNREGISTERED, CLIENT, RCLIENT, SERVER, OPER, LAST
+        */
+       struct MessageEntry handlers[LAST_HANDLER_TYPE];
+};
+
+#define MFLG_SLOW      0x01    /* executed roughly once per 2s */
+#define MFLG_UNREG     0x02    /* available to unregistered clients */
+
+#define MAXPARA    15
+
+/* generic handlers */
+extern int m_ignore(struct Client *, struct Client *, int, const char **);
+extern int m_not_oper(struct Client *, struct Client *, int, const char **);
+extern int m_registered(struct Client *, struct Client *, int, const char **);
+extern int m_unregistered(struct Client *, struct Client *, int, const char **);
+
+#define mg_ignore { m_ignore, 0 }
+#define mg_not_oper { m_not_oper, 0 }
+#define mg_reg { m_registered, 0 }
+#define mg_unreg { m_unregistered, 0 }
+
+/*
+ * m_functions execute protocol messages on this server:
+ * int m_func(struct Client* client_p, struct Client* source_p, int parc, char* parv[]);
+ *
+ *    client_p    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...).
+ *
+ *    source_p    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then source_p==client_p.
+ *
+ *            (!IsServer(client_p)) => (client_p == source_p), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(client_p))
+ *                    (source_p == client_p) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (source_p != client_p && IsServer(source_p) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (source_p != client_p && !IsServer(source_p) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *
+ *            combining
+ *
+ *            (!IsServer(source_p)) means that, source_p can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      source_p->from == client_p  (note: client_p->from == client_p)
+ *
+ *    2)      MyConnect(source_p) <=> source_p == client_p (e.g. source_p
+ *            *cannot* be a local connection, unless it's
+ *            actually client_p!). [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.
+ */
+
+#endif /* INCLUDED_msg_h */
diff --git a/include/newconf.h b/include/newconf.h
new file mode 100644 (file)
index 0000000..720f154
--- /dev/null
@@ -0,0 +1,79 @@
+/* This code is in the public domain.
+ * $Nightmare: nightmare/include/config.h,v 1.32.2.2.2.2 2002/07/02 03:41:28 ejb Exp $
+ * $Id: newconf.h 1735 2006-07-19 02:35:40Z nenolod $
+ */
+
+#ifndef _NEWCONF_H_INCLUDED
+#define _NEWCONF_H_INCLUDED
+
+#include <sys/types.h>
+
+#include <stdio.h>
+
+#include "tools.h"
+#include "client.h"
+
+struct ConfEntry
+{
+       const char *cf_name;
+       int cf_type;
+       void (*cf_func) (void *);
+       int cf_len;
+       void *cf_arg;
+};
+
+struct TopConf
+{
+       char *tc_name;
+       int (*tc_sfunc) (struct TopConf *);
+       int (*tc_efunc) (struct TopConf *);
+       dlink_list tc_items;
+       struct ConfEntry *tc_entries;
+};
+
+
+#define CF_QSTRING     0x01
+#define CF_INT         0x02
+#define CF_STRING      0x03
+#define CF_TIME                0x04
+#define CF_YESNO       0x05
+#define CF_LIST                0x06
+#define CF_ONE         0x07
+
+#define CF_MTYPE       0xFF
+
+#define CF_FLIST       0x1000
+#define CF_MFLAG       0xFF00
+
+typedef struct conf_parm_t_stru
+{
+       struct conf_parm_t_stru *next;
+       int type;
+       union
+       {
+               char *string;
+               int number;
+               struct conf_parm_t_stru *list;
+       }
+       v;
+}
+conf_parm_t;
+
+extern struct TopConf *conf_cur_block;
+
+extern char *current_file;
+
+int read_config(char *);
+int conf_start_block(char *, char *);
+int conf_end_block(struct TopConf *);
+int conf_call_set(struct TopConf *, char *, conf_parm_t *, int);
+void conf_report_error(const char *, ...);
+void newconf_init(void);
+int add_conf_item(const char *topconf, const char *name, int type, void (*func) (void *));
+int remove_conf_item(const char *topconf, const char *name);
+int add_top_conf(const char *name, int (*sfunc) (struct TopConf *), int (*efunc) (struct TopConf *), struct ConfEntry *items);
+int remove_top_conf(char *name);
+struct TopConf *find_top_conf(const char *name);
+struct ConfEntry *find_conf_item(const struct TopConf *top, const char *name);
+
+#endif
diff --git a/include/numeric.h b/include/numeric.h
new file mode 100644 (file)
index 0000000..1fcedcd
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  numeric.h: A header for the numeric functions.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: numeric.h 1793 2006-08-04 19:56:03Z jilles $
+ */
+
+#ifndef INCLUDED_numeric_h
+#define INCLUDED_numeric_h
+
+#include "config.h"
+
+/*
+ * form_str - return a format string for a message number
+ * messages are defined below
+ */
+extern const char *form_str(int);
+
+/*
+ * 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          001
+#define RPL_YOURHOST         002
+#define RPL_CREATED          003
+#define RPL_MYINFO           004
+#define RPL_ISUPPORT         005
+
+#define RPL_SNOMASK         8
+
+#define RPL_REDIR            10
+#define RPL_MAP                     15 /* Undernet extension */
+#define RPL_MAPMORE         16 /* Undernet extension */
+#define RPL_MAPEND          17 /* Undernet extension */
+#define RPL_SAVENICK         43 /* From ircnet */
+
+/*
+ * Numeric 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
+
+#define RPL_STATSLINKINFO    211
+#define RPL_STATSCOMMANDS    212
+#define RPL_STATSCLINE       213
+#define RPL_STATSNLINE       214
+#define RPL_STATSILINE       215
+#define RPL_STATSKLINE       216
+#define RPL_STATSQLINE       217
+#define RPL_STATSYLINE       218
+#define RPL_ENDOFSTATS       219
+/* note ircu uses 217 for STATSPLINE frip. conflict
+ * as RPL_STATSQLINE was used in old 2.8 for Q line 
+ * I'm going to steal 220 for now *sigh*
+ * -Dianora
+ */
+#define RPL_STATSPLINE       220
+#define RPL_UMODEIS          221
+
+#define RPL_STATSFLINE       224
+#define RPL_STATSDLINE       225
+
+#define RPL_SERVLIST         234
+#define RPL_SERVLISTEND      235
+
+#define RPL_STATSLLINE       241
+#define RPL_STATSUPTIME      242
+#define RPL_STATSOLINE       243
+#define RPL_STATSHLINE       244
+/* 245 No longer used in ircd-ratbox */
+#define RPL_STATSSLINE       245
+#define RPL_STATSXLINE       247
+#define RPL_STATSULINE       248
+#define RPL_STATSDEBUG       249
+#define RPL_STATSCONN        250
+#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
+
+#define RPL_TRACELOG         261
+#define RPL_ENDOFTRACE       262
+#define RPL_LOAD2HI          263
+
+#define RPL_LOCALUSERS       265
+#define RPL_GLOBALUSERS      266
+
+#define RPL_ACCEPTLIST      281
+#define RPL_ENDOFACCEPT      282
+
+/* numeric_replies */
+
+#define RPL_NONE             300
+#define RPL_AWAY             301
+#define RPL_USERHOST         302
+#define RPL_ISON             303
+#define RPL_TEXT             304
+#define RPL_UNAWAY           305
+#define RPL_NOWAWAY          306
+
+/*      RPL_WHOISADMIN       308 -- hybrid */
+
+#define RPL_WHOISUSER        311
+#define RPL_WHOISSERVER      312
+#define RPL_WHOISOPERATOR    313
+
+#define RPL_WHOWASUSER       314
+/* rpl_endofwho below (315) */
+#define RPL_ENDOFWHOWAS      369
+
+#define RPL_WHOISCHANOP      316       /* redundant and not needed but reserved */
+#define RPL_WHOISIDLE        317
+
+#define RPL_ENDOFWHOIS       318
+#define RPL_WHOISCHANNELS    319
+
+#define RPL_LISTSTART        321
+#define RPL_LIST             322
+#define RPL_LISTEND          323
+#define RPL_CHANNELMODEIS    324
+
+#define RPL_CREATIONTIME     329
+#define RPL_WHOISLOGGEDIN    330
+
+#define RPL_NOTOPIC          331
+#define RPL_TOPIC            332
+#define RPL_TOPICWHOTIME     333
+#define RPL_WHOISACTUALLY    338
+
+#define RPL_INVITING         341
+#define RPL_SUMMONING        342
+
+#define RPL_INVITELIST       346
+#define RPL_ENDOFINVITELIST  347
+#define RPL_EXCEPTLIST       348
+#define RPL_ENDOFEXCEPTLIST  349
+
+#define RPL_VERSION          351
+
+#define RPL_WHOREPLY         352
+#define RPL_ENDOFWHO         315
+#define RPL_NAMREPLY         353
+#define RPL_WHOWASREAL       360
+#define RPL_ENDOFNAMES       366
+
+#define RPL_KILLDONE         361
+#define RPL_CLOSING          362
+#define RPL_CLOSEEND         363
+#define RPL_LINKS            364
+#define RPL_ENDOFLINKS       365
+/* rpl_endofnames above (366) */
+#define RPL_BANLIST          367
+#define RPL_ENDOFBANLIST     368
+/* rpl_endofwhowas above (369) */
+
+#define RPL_INFO             371
+#define RPL_MOTD             372
+#define RPL_INFOSTART        373
+#define RPL_ENDOFINFO        374
+#define RPL_MOTDSTART        375
+#define RPL_ENDOFMOTD        376
+#define RPL_WHOISHOST        378
+
+#define RPL_YOUREOPER        381
+#define RPL_REHASHING        382
+#define RPL_MYPORTIS         384
+#define RPL_NOTOPERANYMORE   385
+#define RPL_RSACHALLENGE     386
+
+#define RPL_TIME             391
+#define RPL_USERSSTART       392
+#define RPL_USERS            393
+#define RPL_ENDOFUSERS       394
+#define RPL_NOUSERS          395
+#define RPL_HOSTHIDDEN       396 /* from ircu -- jilles */
+
+/*
+ * Errors are in the range from 400-599 currently and are grouped by what
+ * commands they come from.
+ */
+#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_NOORIGIN         409
+
+#define ERR_INVALIDCAPCMD    410
+
+#define ERR_NORECIPIENT      411
+#define ERR_NOTEXTTOSEND     412
+#define ERR_NOTOPLEVEL       413
+#define ERR_WILDTOPLEVEL     414
+
+#define ERR_TOOMANYMATCHES   416
+
+#define ERR_UNKNOWNCOMMAND   421
+#define ERR_NOMOTD           422
+#define ERR_NOADMININFO      423
+#define ERR_FILEERROR        424
+
+#define ERR_NONICKNAMEGIVEN  431
+#define ERR_ERRONEUSNICKNAME 432
+#define ERR_NICKNAMEINUSE    433
+#define ERR_BANNICKCHANGE    435       /* bahamut's ERR_BANONCHAN -- jilles */
+#define ERR_NICKCOLLISION    436
+#define ERR_UNAVAILRESOURCE  437
+#define ERR_NICKTOOFAST             438        /* We did it first Undernet! ;) db */
+
+#define ERR_SERVICESDOWN     440
+#define ERR_USERNOTINCHANNEL 441
+#define ERR_NOTONCHANNEL     442
+#define ERR_USERONCHANNEL    443
+#define ERR_NOLOGIN          444
+#define ERR_SUMMONDISABLED   445
+#define ERR_USERSDISABLED    446
+
+#define ERR_NOTREGISTERED    451
+
+#define ERR_ACCEPTFULL       456
+#define ERR_ACCEPTEXIST      457
+#define ERR_ACCEPTNOT        458
+
+#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
+
+#define ERR_LINKCHANNEL      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
+#define ERR_NEEDREGGEDNICK   477
+#define ERR_BANLISTFULL      478       /* I stole the numeric from ircu -db */
+#define ERR_BADCHANNAME      479
+
+#define ERR_THROTTLE         480
+
+#define ERR_NOPRIVILEGES     481
+#define ERR_CHANOPRIVSNEEDED 482
+#define ERR_CANTKILLSERVER   483
+#define ERR_ISCHANSERVICE    484
+/* #define ERR_RESTRICTED       484    - hyb derived, no longer here */
+#define ERR_BANNEDNICK       485
+#define ERR_NONONREG         486 /* bahamut; aka ERR_ACCOUNTONLY asuka -- jilles */
+
+#define ERR_VOICENEEDED                489
+
+#define ERR_NOOPERHOST       491
+
+#define ERR_UMODEUNKNOWNFLAG 501
+#define ERR_USERSDONTMATCH   502
+
+#define ERR_GHOSTEDCLIENT    503
+
+#define ERR_USERNOTONSERV    504
+
+/* #define ERR_LAST_ERR_MSG 505 
+ * moved to 999
+ */
+#define ERR_WRONGPONG       513
+
+#define ERR_HELPNOTFOUND     524
+
+#define RPL_MODLIST          702
+#define RPL_ENDOFMODLIST     703
+
+#define RPL_HELPSTART        704
+#define RPL_HELPTXT          705
+#define RPL_ENDOFHELP        706
+
+#define ERR_TARGCHANGE         707
+
+#define RPL_ETRACEFULL      708
+#define RPL_ETRACE          709
+
+#define RPL_KNOCK           710
+#define RPL_KNOCKDLVR       711
+
+#define ERR_TOOMANYKNOCK     712
+#define ERR_CHANOPEN         713
+#define ERR_KNOCKONCHAN      714
+#define ERR_KNOCKDISABLED    715
+
+#define ERR_TARGUMODEG       716
+#define RPL_TARGNOTIFY       717
+#define RPL_UMODEGMSG        718
+
+#define RPL_OMOTDSTART      720
+#define RPL_OMOTD           721
+#define RPL_ENDOFOMOTD       722
+
+#define ERR_NOPRIVS            723
+
+#define RPL_TESTMASK           724
+#define RPL_TESTLINE           725
+#define RPL_NOTESTLINE         726
+#define RPL_TESTMASKGECOS      727
+
+#define RPL_MONONLINE          730
+#define RPL_MONOFFLINE         731
+#define RPL_MONLIST            732
+#define RPL_ENDOFMONLIST       733
+#define ERR_MONLISTFULL                734
+
+#define RPL_RSACHALLENGE2       740
+#define RPL_ENDOFRSACHALLENGE2  741
+
+#define RPL_SCANMATCHED                750
+#define RPL_SCANUMODES         751
+
+#define RPL_LOGGEDIN           900
+#define RPL_LOGGEDOUT          901
+#define ERR_NICKLOCKED         902
+
+#define RPL_SASLSUCCESS                903
+#define ERR_SASLFAIL           904
+#define ERR_SASLTOOLONG                905
+#define ERR_SASLABORTED                906
+#define ERR_SASLALREADY                907
+
+#define ERR_LAST_ERR_MSG     999
+
+#endif /* INCLUDED_numeric_h */
diff --git a/include/packet.h b/include/packet.h
new file mode 100644 (file)
index 0000000..13b7feb
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  packet.h: A header for the packet functions.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: packet.h 813 2006-02-14 20:52:15Z nenolod $
+ */
+
+#ifndef INCLUDED_packet_h
+#define INCLUDED_packet_h
+
+#include "commio.h"
+
+/*
+ * this hides in here rather than a config.h because it really shouldn't
+ * be tweaked unless you *REALLY REALLY* know what you're doing!
+ * Remember, messages are only anti-flooded on incoming from the client, not on
+ * incoming from a server for a given client, so if you tweak this you risk
+ * allowing a client to flood differently depending upon where they are on
+ * the network..
+ *   -- adrian
+ */
+/* MAX_FLOOD is the amount of lines in a 'burst' we allow from a client, 
+ * anything beyond MAX_FLOOD is limited to about one line per second.
+ *
+ * MAX_FLOOD_CONN is the amount of lines we allow from a client who has
+ * just connected.  this allows clients to rejoin multiple channels
+ * without being so heavily penalised they excess flood.
+ */
+#define MAX_FLOOD 5
+#define MAX_FLOOD_BURST MAX_FLOOD * 8
+
+extern PF read_ctrl_packet;
+extern PF read_packet;
+extern PF flood_recalc;
+extern void flood_endgrace(struct Client *);
+
+#endif /* INCLUDED_packet_h */
diff --git a/include/parse.h b/include/parse.h
new file mode 100644 (file)
index 0000000..4335e8e
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  parse.h: A header for the message parser.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: parse.h 944 2006-03-06 03:41:31Z nenolod $
+ */
+
+#ifndef INCLUDED_parse_h_h
+#define INCLUDED_parse_h_h
+
+#include "tools.h"
+
+struct Message;
+struct Client;
+
+struct MessageHash
+{
+       char *cmd;
+       struct Message *msg;
+       struct MessageHash *next;
+};
+
+#define MAX_MSG_HASH  387
+
+extern void parse(struct Client *, char *, char *);
+extern void handle_encap(struct Client *, struct Client *, 
+                        const char *, int, const char *parv[]);
+extern void clear_hash_parse(void);
+extern void mod_add_cmd(struct Message *msg);
+extern void mod_del_cmd(struct Message *msg);
+extern void report_messages(struct Client *);
+
+extern dlink_list alias_hash_table[MAX_MSG_HASH];
+
+#endif /* INCLUDED_parse_h_h */
diff --git a/include/patchlevel.h b/include/patchlevel.h
new file mode 100644 (file)
index 0000000..b2d744b
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  patchlevel.h: A header defining the patchlevel.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: patchlevel.h 34 2005-09-10 02:53:04Z nenolod $
+ */
+
+#include "setup.h"
+
+#ifndef PATCHLEVEL
+#define PATCHLEVEL   PACKAGE_NAME "-" PACKAGE_VERSION
+#endif
diff --git a/include/patricia.h b/include/patricia.h
new file mode 100644 (file)
index 0000000..4fac7c0
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * $Id: patricia.h 6 2005-09-10 01:02:21Z nenolod $
+ * Dave Plonka <plonka@doit.wisc.edu>
+ *
+ * This product includes software developed by the University of Michigan,
+ * Merit Network, Inc., and their contributors. 
+ *
+ * This file had been called "radix.h" in the MRT sources.
+ *
+ * I renamed it to "patricia.h" since it's not an implementation of a general
+ * radix trie.  Also, pulled in various requirements from "mrt.h" and added
+ * some other things it could be used as a standalone API.
+ */
+
+#ifndef _PATRICIA_H
+#define _PATRICIA_H
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <assert.h>
+#ifndef TESTING
+#include "class.h"
+#include "client.h"
+#include "common.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "memory.h"
+#include "config.h"
+#endif
+
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE !(FALSE)
+#endif
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 46
+#endif
+
+/* typedef unsigned int u_int; */
+typedef void (*void_fn_t) ();
+#define prefix_touchar(prefix) ((u_char *)&(prefix)->add.sin)
+#define MAXLINE 1024
+#define BIT_TEST(f, b)  ((f) & (b))
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+typedef struct _prefix_t
+{
+       u_short family;         /* AF_INET | AF_INET6 */
+       u_short bitlen;         /* same as mask? */
+       int ref_count;          /* reference count */
+       union
+       {
+               struct in_addr sin;
+#ifdef IPV6
+               struct in6_addr sin6;
+#endif                         /* IPV6 */
+       }
+       add;
+}
+prefix_t;
+
+
+typedef struct _patricia_node_t
+{
+       u_int bit;              /* flag if this node used */
+       prefix_t *prefix;       /* who we are in patricia tree */
+       struct _patricia_node_t *l, *r; /* left and right children */
+       struct _patricia_node_t *parent;        /* may be used */
+       void *data;
+}
+patricia_node_t;
+
+typedef struct _patricia_tree_t
+{
+       patricia_node_t *head;
+       u_int maxbits;          /* for IP, 32 bit addresses */
+       int num_active_node;    /* for debug purpose */
+}
+patricia_tree_t;
+
+
+patricia_node_t *match_ip(patricia_tree_t * tree, struct sockaddr  *ip);
+patricia_node_t *match_string(patricia_tree_t * tree, const char *string);
+patricia_node_t *match_exact_string(patricia_tree_t * tree, const char *string);
+patricia_node_t *patricia_search_exact(patricia_tree_t * patricia, prefix_t * prefix);
+patricia_node_t *patricia_search_best(patricia_tree_t * patricia, prefix_t * prefix);
+patricia_node_t *patricia_search_best2(patricia_tree_t * patricia,
+                                      prefix_t * prefix, int inclusive);
+patricia_node_t *patricia_lookup(patricia_tree_t * patricia, prefix_t * prefix);
+
+void patricia_remove(patricia_tree_t * patricia, patricia_node_t * node);
+patricia_tree_t *New_Patricia(int maxbits);
+void Clear_Patricia(patricia_tree_t * patricia, void_fn_t func);
+void Destroy_Patricia(patricia_tree_t * patricia, void_fn_t func);
+void patricia_process(patricia_tree_t * patricia, void_fn_t func);
+void init_patricia(void);
+
+
+#if 0
+prefix_t *ascii2prefix(int family, char *string);
+#endif
+patricia_node_t *make_and_lookup(patricia_tree_t * tree, const char *string);
+patricia_node_t *make_and_lookup_ip(patricia_tree_t * tree, struct sockaddr *, int bitlen);
+
+
+#define PATRICIA_MAXBITS 128
+#define PATRICIA_NBIT(x)        (0x80 >> ((x) & 0x7f))
+#define PATRICIA_NBYTE(x)       ((x) >> 3)
+
+#define PATRICIA_DATA_GET(node, type) (type *)((node)->data)
+#define PATRICIA_DATA_SET(node, value) ((node)->data = (void *)(value))
+
+#define PATRICIA_WALK(Xhead, Xnode) \
+    do { \
+        patricia_node_t *Xstack[PATRICIA_MAXBITS+1]; \
+        patricia_node_t **Xsp = Xstack; \
+        patricia_node_t *Xrn = (Xhead); \
+        while ((Xnode = Xrn)) { \
+            if (Xnode->prefix)
+
+#define PATRICIA_WALK_ALL(Xhead, Xnode) \
+do { \
+        patricia_node_t *Xstack[PATRICIA_MAXBITS+1]; \
+        patricia_node_t **Xsp = Xstack; \
+        patricia_node_t *Xrn = (Xhead); \
+        while ((Xnode = Xrn)) { \
+           if (1)
+
+#define PATRICIA_WALK_BREAK { \
+           if (Xsp != Xstack) { \
+               Xrn = *(--Xsp); \
+            } else { \
+               Xrn = (patricia_node_t *) 0; \
+           } \
+           continue; }
+
+#define PATRICIA_WALK_END \
+            if (Xrn->l) { \
+                if (Xrn->r) { \
+                    *Xsp++ = Xrn->r; \
+                } \
+                Xrn = Xrn->l; \
+            } else if (Xrn->r) { \
+                Xrn = Xrn->r; \
+            } else if (Xsp != Xstack) { \
+                Xrn = *(--Xsp); \
+            } else { \
+                Xrn = (patricia_node_t *) 0; \
+            } \
+        } \
+    } while (0)
+
+#endif /* _PATRICIA_H */
diff --git a/include/reject.h b/include/reject.h
new file mode 100644 (file)
index 0000000..4e1bc41
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd
+ *  reject.h: header to a file which rejects users with prejudice
+ *
+ *  Copyright (C) 2003 Aaron Sethman <androsyn@ratbox.org>
+ *  Copyright (C) 2003-2004 ircd-ratbox development 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: reject.h 6 2005-09-10 01:02:21Z nenolod $
+ */
+#ifndef INCLUDED_reject_h
+#define INCLUDED_reject_h
+
+/* amount of time to delay a rejected clients exit */
+#define DELAYED_EXIT_TIME      10
+
+extern dlink_list delay_exit;
+
+void init_reject(void);
+int check_reject(struct Client *);
+void add_reject(struct Client *);
+void flush_reject(void);
+int remove_reject(const char *ip);
+#endif
+
diff --git a/include/res.h b/include/res.h
new file mode 100644 (file)
index 0000000..8f53313
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * res.h for referencing functions in res.c, reslib.c
+ *
+ * $Id: res.h 2023 2006-09-02 23:47:27Z jilles $
+ */
+
+#ifndef _CHARYBDIS_RES_H
+#define _CHARYBDIS_RES_H
+
+#include "ircd_defs.h"
+#include "common.h"
+#include "commio.h"
+#include "reslib.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+
+/* Maximum number of nameservers in /etc/resolv.conf we care about 
+ * In hybrid, this was 2 -- but in Charybdis, we want to track
+ * a few more than that ;) --nenolod
+ */
+#define IRCD_MAXNS 10
+
+struct DNSReply
+{
+  char *h_name;
+  struct irc_sockaddr_storage addr;
+};
+
+struct DNSQuery
+{
+  void *ptr; /* pointer used by callback to identify request */
+  void (*callback)(void* vptr, struct DNSReply *reply); /* callback to call */
+};
+
+extern struct irc_sockaddr_storage irc_nsaddr_list[];
+extern int irc_nscount;
+
+extern void init_resolver(void);
+extern void restart_resolver(void);
+extern void delete_resolver_queries(const struct DNSQuery *);
+extern void gethost_byname_type(const char *, struct DNSQuery *, int);
+extern void gethost_byaddr(const struct irc_sockaddr_storage *, struct DNSQuery *);
+extern void add_local_domain(char *, size_t);
+extern void report_dns_servers(struct Client *);
+
+#endif
diff --git a/include/reslib.h b/include/reslib.h
new file mode 100644 (file)
index 0000000..38e061b
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * include/irc_reslib.h
+ *
+ * $Id: reslib.h 446 2006-02-12 02:46:54Z db $
+ */
+
+#ifndef _CHARYBDIS_RESLIB_H
+#define _CHARYBDIS_RESLIB_H
+
+/* Here we define some values lifted from nameser.h */
+#define NS_NOTIFY_OP 4
+#define NS_INT16SZ 2
+#define NS_IN6ADDRSZ    16
+#define NS_INADDRSZ      4
+#define NS_INT32SZ 4
+#define NS_CMPRSFLGS    0xc0
+#define NS_MAXCDNAME 255
+#define QUERY 0
+#define IQUERY 1
+#define NO_ERRORS 0
+#define SERVFAIL 2
+#define NXDOMAIN 3
+#define T_A 1
+#define T_AAAA 28
+#define T_PTR 12
+#define T_CNAME 5
+#define T_NULL 10
+#define C_IN 1
+#define QFIXEDSZ 4
+#define RRFIXEDSZ 10
+#define HFIXEDSZ 12
+
+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;
+
+/*
+ * Inline versions of get/put short/long.  Pointer is advanced.
+ */
+#define IRC_NS_GET16(s, cp) { \
+       const unsigned char *t_cp = (const unsigned char *)(cp); \
+       (s) = ((u_int16_t)t_cp[0] << 8) \
+           | ((u_int16_t)t_cp[1]) \
+           ; \
+       (cp) += NS_INT16SZ; \
+}
+
+#define IRC_NS_GET32(l, cp) { \
+       const unsigned char *t_cp = (const unsigned char *)(cp); \
+       (l) = ((u_int32_t)t_cp[0] << 24) \
+           | ((u_int32_t)t_cp[1] << 16) \
+           | ((u_int32_t)t_cp[2] << 8) \
+           | ((u_int32_t)t_cp[3]) \
+           ; \
+       (cp) += NS_INT32SZ; \
+}
+
+#define IRC_NS_PUT16(s, cp) { \
+       u_int16_t t_s = (u_int16_t)(s); \
+       unsigned char *t_cp = (unsigned char *)(cp); \
+       *t_cp++ = t_s >> 8; \
+       *t_cp   = t_s; \
+       (cp) += NS_INT16SZ; \
+}
+
+#define IRC_NS_PUT32(l, cp) { \
+       u_int32_t t_l = (u_int32_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; \
+}
+
+extern int irc_res_init(void);
+extern int irc_dn_expand(const unsigned char *msg, const unsigned char *eom, const unsigned char *src, char *dst, int dstsiz);
+extern int irc_dn_skipname(const unsigned char *ptr, const unsigned char *eom);
+extern unsigned int irc_ns_get16(const unsigned char *src);
+extern unsigned long irc_ns_get32(const unsigned char *src);
+extern void irc_ns_put16(unsigned int src, unsigned char *dst);
+extern void irc_ns_put32(unsigned long src, unsigned char *dst);
+extern int irc_res_mkquery(const char *dname, int class, int type, unsigned char *buf, int buflen);
+
+#endif
diff --git a/include/restart.h b/include/restart.h
new file mode 100644 (file)
index 0000000..b088eff
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  restart.h: A header with restart functions.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: restart.h 6 2005-09-10 01:02:21Z nenolod $
+ */
+
+#ifndef INCLUDED_restart_h
+#define INCLUDED_restart_h
+
+void restart(const char *);
+void server_reboot(void);
+
+#endif
diff --git a/include/s_auth.h b/include/s_auth.h
new file mode 100644 (file)
index 0000000..fe7ef42
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  s_auth.h: A header for the ident functions.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: s_auth.h 6 2005-09-10 01:02:21Z nenolod $
+ */
+
+#ifndef INCLUDED_s_auth_h
+#define INCLUDED_s_auth_h
+
+#include "config.h"
+#include "res.h"
+/* 
+ * How many auth allocations to allocate in a block. I'm guessing that
+ * a good number here is 64, because these are temporary and don't live
+ * as long as clients do.
+ *     -- adrian
+ */
+#define        AUTH_BLOCK_SIZE         64
+
+struct Client;
+
+struct AuthRequest
+{
+       dlink_node node;
+       struct Client *client;  /* pointer to client struct for request */
+       struct DNSQuery dns_query; /* DNS Query */
+       unsigned int flags;     /* current state of request */
+       int fd;                 /* file descriptor for auth queries */
+       time_t timeout;         /* time when query expires */
+#ifdef IPV6
+       int ip6_int;
+#endif
+};
+
+/*
+ * flag values for AuthRequest
+ * NAMESPACE: AM_xxx - Authentication Module
+ */
+#define AM_AUTH_CONNECTING   (1 << 0)
+#define AM_AUTH_PENDING      (1 << 1)
+#define AM_DNS_PENDING       (1 << 2)
+
+#define SetDNSPending(x)     ((x)->flags |= AM_DNS_PENDING)
+#define ClearDNSPending(x)   ((x)->flags &= ~AM_DNS_PENDING)
+#define IsDNSPending(x)      ((x)->flags &  AM_DNS_PENDING)
+
+#define SetAuthConnect(x)    ((x)->flags |= AM_AUTH_CONNECTING)
+#define ClearAuthConnect(x)  ((x)->flags &= ~AM_AUTH_CONNECTING)
+#define IsAuthConnect(x)     ((x)->flags &  AM_AUTH_CONNECTING)
+
+#define SetAuthPending(x)    ((x)->flags |= AM_AUTH_PENDING)
+#define ClearAuthPending(x)  ((x)->flags &= AM_AUTH_PENDING)
+#define IsAuthPending(x)     ((x)->flags &  AM_AUTH_PENDING)
+
+#define ClearAuth(x)         ((x)->flags &= ~(AM_AUTH_PENDING | AM_AUTH_CONNECTING))
+#define IsDoingAuth(x)       ((x)->flags &  (AM_AUTH_PENDING | AM_AUTH_CONNECTING))
+/* #define SetGotId(x)       ((x)->flags |= FLAGS_GOTID) */
+
+
+
+extern void start_auth(struct Client *);
+extern void send_auth_query(struct AuthRequest *req);
+extern void remove_auth_request(struct AuthRequest *req);
+extern void init_auth(void);
+extern void delete_auth_queries(struct Client *);
+
+#endif /* INCLUDED_s_auth_h */
diff --git a/include/s_conf.h b/include/s_conf.h
new file mode 100644 (file)
index 0000000..628afc2
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ *  charybdis: Advanced, scalable Internet Relay Chat.
+ *  s_conf.h: A header for the configuration functions.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: s_conf.h 3131 2007-01-21 15:36:31Z jilles $
+ */
+
+#ifndef INCLUDED_s_conf_h
+#define INCLUDED_s_conf_h
+#include "setup.h"
+
+#ifdef HAVE_LIBCRYPTO
+#include <openssl/rsa.h>
+#endif
+
+#include "ircd_defs.h"
+#include "class.h"
+#include "client.h"
+#include "common.h"
+#include "patricia.h"
+
+struct Client;
+struct DNSReply;
+struct hostent;
+
+/* used by new parser */
+/* yacc/lex love globals!!! */
+
+struct ip_value
+{
+       struct irc_sockaddr_storage ip;
+       int ip_mask;
+       int type;
+};
+
+extern FILE *conf_fbfile_in;
+extern char conf_line_in[256];
+
+struct ConfItem
+{
+       struct ConfItem *next;  /* list node pointer */
+       unsigned int status;    /* If CONF_ILLEGAL, delete when no clients */
+       unsigned int flags;
+       int clients;            /* Number of *LOCAL* clients using this */
+       char *name;             /* IRC name, nick, server name, or original u@h */
+       char *host;             /* host part of user@host */
+       char *passwd;           /* doubles as kline reason *ugh* */
+       char *spasswd;          /* Password to send. */
+       char *user;             /* user part of user@host */
+       int port;
+       time_t hold;            /* Hold action until this time (calendar time) */
+       char *className;        /* Name of class */
+       struct Class *c_class;  /* Class of connection */
+       patricia_node_t *pnode; /* Our patricia node */
+};
+
+#define CONF_ILLEGAL            0x80000000
+#define CONF_QUARANTINED_NICK   0x0001
+#define CONF_CLIENT             0x0002
+#define CONF_KILL               0x0040
+#define CONF_XLINE             0x0080
+#define CONF_RESV_CHANNEL      0x0100
+#define CONF_RESV_NICK         0x0200
+#define CONF_RESV              (CONF_RESV_CHANNEL | CONF_RESV_NICK)
+
+#define CONF_CLASS              0x0400
+#define CONF_LISTEN_PORT        0x1000
+#define CONF_EXEMPTKLINE        0x4000
+#define CONF_NOLIMIT            0x8000
+#define CONF_GLINE             0x10000
+#define CONF_DLINE             0x20000
+#define CONF_EXEMPTDLINE      0x100000
+
+#define IsIllegal(x)    ((x)->status & CONF_ILLEGAL)
+
+/* aConfItem->flags */
+
+/* Generic flags... */
+/* access flags... */
+#define CONF_FLAGS_DO_IDENTD            0x00000001
+#define CONF_FLAGS_LIMIT_IP             0x00000002
+#define CONF_FLAGS_NO_TILDE             0x00000004
+#define CONF_FLAGS_NEED_IDENTD          0x00000008
+#define CONF_FLAGS_PASS_IDENTD          0x00000010
+#define CONF_FLAGS_NOMATCH_IP           0x00000020
+#define CONF_FLAGS_EXEMPTKLINE          0x00000040
+#define CONF_FLAGS_NOLIMIT              0x00000080
+#define CONF_FLAGS_IDLE_LINED           0x00000100
+#define CONF_FLAGS_SPOOF_IP             0x00000200
+#define CONF_FLAGS_SPOOF_NOTICE                0x00000400
+#define CONF_FLAGS_REDIR                0x00000800
+#define CONF_FLAGS_EXEMPTGLINE          0x00001000
+#define CONF_FLAGS_EXEMPTRESV          0x00002000      /* exempt from resvs */
+#define CONF_FLAGS_EXEMPTFLOOD          0x00004000
+#define CONF_FLAGS_EXEMPTSPAMBOT       0x00008000
+#define CONF_FLAGS_EXEMPTSHIDE         0x00010000
+#define CONF_FLAGS_EXEMPTJUPE          0x00020000      /* exempt from resv generating warnings */
+#define CONF_FLAGS_NEED_SASL           0x00040000
+/* server flags */
+#define CONF_FLAGS_ALLOW_AUTO_CONN      0x00080000
+#define CONF_FLAGS_LAZY_LINK            0x00100000
+#define CONF_FLAGS_ENCRYPTED            0x00200000
+#define CONF_FLAGS_COMPRESSED           0x00400000
+#define CONF_FLAGS_TEMPORARY            0x00800000
+#define CONF_FLAGS_TB                  0x01000000
+#define CONF_FLAGS_VHOSTED             0x02000000
+#define CONF_FLAGS_EXEMPTDNSBL         0x04000000
+
+
+/* Macros for struct ConfItem */
+#define IsLimitIp(x)            ((x)->flags & CONF_FLAGS_LIMIT_IP)
+#define IsNoTilde(x)            ((x)->flags & CONF_FLAGS_NO_TILDE)
+#define IsNeedIdentd(x)         ((x)->flags & CONF_FLAGS_NEED_IDENTD)
+#define IsPassIdentd(x)         ((x)->flags & CONF_FLAGS_PASS_IDENTD)
+#define IsNoMatchIp(x)          ((x)->flags & CONF_FLAGS_NOMATCH_IP)
+#define IsConfExemptKline(x)    ((x)->flags & CONF_FLAGS_EXEMPTKLINE)
+#define IsConfExemptLimits(x)   ((x)->flags & CONF_FLAGS_NOLIMIT)
+#define IsConfExemptGline(x)    ((x)->flags & CONF_FLAGS_EXEMPTGLINE)
+#define IsConfExemptFlood(x)    ((x)->flags & CONF_FLAGS_EXEMPTFLOOD)
+#define IsConfExemptSpambot(x) ((x)->flags & CONF_FLAGS_EXEMPTSPAMBOT)
+#define IsConfExemptShide(x)   ((x)->flags & CONF_FLAGS_EXEMPTSHIDE)
+#define IsConfExemptJupe(x)    ((x)->flags & CONF_FLAGS_EXEMPTJUPE)
+#define IsConfExemptResv(x)    ((x)->flags & CONF_FLAGS_EXEMPTRESV)
+#define IsConfIdlelined(x)      ((x)->flags & CONF_FLAGS_IDLE_LINED)
+#define IsConfDoIdentd(x)       ((x)->flags & CONF_FLAGS_DO_IDENTD)
+#define IsConfDoSpoofIp(x)      ((x)->flags & CONF_FLAGS_SPOOF_IP)
+#define IsConfSpoofNotice(x)    ((x)->flags & CONF_FLAGS_SPOOF_NOTICE)
+#define IsConfEncrypted(x)      ((x)->flags & CONF_FLAGS_ENCRYPTED)
+#define IsConfCompressed(x)     ((x)->flags & CONF_FLAGS_COMPRESSED)
+#define IsConfVhosted(x)       ((x)->flags & CONF_FLAGS_VHOSTED)
+#define IsConfTburst(x)                ((x)->flags & CONF_FLAGS_TB)
+#define IsNeedSasl(x)          ((x)->flags & CONF_FLAGS_NEED_SASL)
+#define IsConfExemptDNSBL(x)   ((x)->flags & CONF_FLAGS_EXEMPTDNSBL)
+
+/* flag definitions for opers now in client.h */
+
+struct config_file_entry
+{
+       const char *dpath;      /* DPATH if set from command line */
+       const char *configfile;
+       const char *klinefile;
+       const char *dlinefile;
+       const char *xlinefile;
+       const char *resvfile;
+
+       char *servlink_path;
+       char *egdpool_path;
+
+       char *default_operstring;
+       char *default_adminstring;
+       char *servicestring;
+       char *kline_reason;
+
+       char *identifyservice;
+       char *identifycommand;
+       
+       char *fname_userlog;
+       char *fname_fuserlog;
+       char *fname_operlog;
+       char *fname_foperlog;
+       char *fname_serverlog;
+       char *fname_killlog;
+       char *fname_glinelog;
+       char *fname_klinelog;
+       char *fname_operspylog;
+       char *fname_ioerrorlog;
+
+       unsigned char compression_level;
+       int disable_fake_channels;
+       int dot_in_ip6_addr;
+       int dots_in_ident;
+       int failed_oper_notice;
+       int anti_nick_flood;
+       int anti_spam_exit_message_time;
+       int max_accept;
+       int max_monitor;
+       int max_nick_time;
+       int max_nick_changes;
+       int ts_max_delta;
+       int ts_warn_delta;
+       int dline_with_reason;
+       int kline_with_reason;
+       int kline_delay;
+       int warn_no_nline;
+       int nick_delay;
+       int non_redundant_klines;
+       int stats_e_disabled;
+       int stats_c_oper_only;
+       int stats_y_oper_only;
+       int stats_h_oper_only;
+       int stats_o_oper_only;
+       int stats_k_oper_only;
+       int stats_i_oper_only;
+       int stats_P_oper_only;
+       int map_oper_only;
+       int operspy_admin_only;
+       int pace_wait;
+       int pace_wait_simple;
+       int short_motd;
+       int no_oper_flood;
+       int glines;
+       int gline_time;
+       int gline_min_cidr;
+       int gline_min_cidr6;
+       int idletime;
+       int hide_server;
+       int hide_spoof_ips;
+       int hide_error_messages;
+       int client_exit;
+       int oper_only_umodes;
+       int oper_umodes;
+       int oper_snomask;
+       int max_targets;
+       int caller_id_wait;
+       int min_nonwildcard;
+       int min_nonwildcard_simple;
+       int default_floodcount;
+       int client_flood;
+       int use_egd;
+       int ping_cookie;
+       int tkline_expire_notices;
+       int use_whois_actually;
+       int disable_auth;
+       int connect_timeout;
+       int burst_away;
+       int reject_ban_time;
+       int reject_after_count;
+       int reject_duration;
+       int target_change;
+       int collision_fnc;
+       int default_umodes;
+       int global_snotices;
+       int operspy_dont_care_user_info;
+};
+
+struct config_channel_entry
+{
+       int use_except;
+       int use_invex;
+       int use_knock;
+       int use_forward;
+       int knock_delay;
+       int knock_delay_channel;
+       int max_bans;
+       int max_bans_large;
+       int max_chans_per_user;
+       int no_create_on_split;
+       int no_join_on_split;
+       int default_split_server_count;
+       int default_split_user_count;
+       int burst_topicwho;
+       int invite_ops_only;
+       int kick_on_split_riding;
+};
+
+struct config_server_hide
+{
+       int flatten_links;
+       int links_delay;
+       int links_disabled;
+       int hidden;
+       int disable_hidden;
+};
+
+struct server_info
+{
+       char *name;
+       char sid[3];
+       char *description;
+       char *network_name;
+       char *network_desc;
+       int hub;
+       int use_ts6;
+       struct sockaddr_in ip;
+#ifdef IPV6
+       struct sockaddr_in6 ip6;
+#endif
+       int specific_ipv4_vhost;
+#ifdef IPV6
+       int specific_ipv6_vhost;
+#endif
+};
+
+struct admin_info
+{
+       char *name;
+       char *description;
+       char *email;
+};
+
+struct alias_entry
+{
+       char *name;
+       char *target;
+       int flags;                      /* reserved for later use */
+       int hits;
+};
+
+/* All variables are GLOBAL */
+extern int specific_ipv4_vhost;        /* used in s_bsd.c */
+extern int specific_ipv6_vhost;
+extern struct config_file_entry ConfigFileEntry;       /* defined in ircd.c */
+extern struct config_channel_entry ConfigChannel;      /* defined in channel.c */
+extern struct config_server_hide ConfigServerHide;     /* defined in s_conf.c */
+extern struct server_info ServerInfo;  /* defined in ircd.c */
+extern struct admin_info AdminInfo;    /* defined in ircd.c */
+/* End GLOBAL section */
+
+dlink_list service_list;
+
+typedef enum temp_list
+{
+       TEMP_MIN,
+       TEMP_HOUR,
+       TEMP_DAY,
+       TEMP_WEEK,
+       LAST_TEMP_TYPE
+} temp_list;
+
+dlink_list temp_klines[LAST_TEMP_TYPE];
+dlink_list temp_dlines[LAST_TEMP_TYPE];
+
+extern void init_s_conf(void);
+
+extern struct ConfItem *make_conf(void);
+extern void free_conf(struct ConfItem *);
+
+extern void read_conf_files(int cold);
+
+extern int attach_conf(struct Client *, struct ConfItem *);
+extern int check_client(struct Client *client_p, struct Client *source_p, const char *);
+
+extern int detach_conf(struct Client *);
+
+extern struct ConfItem *conf_connect_allowed(struct sockaddr *addr, int);
+
+extern struct ConfItem *find_tkline(const char *, const char *, struct sockaddr *);
+extern char *show_iline_prefix(struct Client *, struct ConfItem *, char *);
+extern void get_printable_conf(struct ConfItem *,
+                              char **, char **, char **, char **, int *, char **);
+extern void get_printable_kline(struct Client *, struct ConfItem *,
+                               char **, char **, char **, char **);
+
+extern void yyerror(const char *);
+extern int conf_yy_fatal_error(const char *);
+extern int conf_fgets(char *, int, FILE *);
+
+typedef enum
+{
+       CONF_TYPE,
+       KLINE_TYPE,
+       DLINE_TYPE,
+       RESV_TYPE
+}
+KlineType;
+
+extern void write_confitem(KlineType, struct Client *, char *, char *,
+                          const char *, const char *, const char *, int);
+extern void add_temp_kline(struct ConfItem *);
+extern void add_temp_dline(struct ConfItem *);
+extern void report_temp_klines(struct Client *);
+extern void show_temp_klines(struct Client *, dlink_list *);
+
+extern const char *get_conf_name(KlineType);
+extern int rehash(int);
+extern void rehash_bans(int);
+
+extern int conf_add_server(struct ConfItem *, int);
+extern void conf_add_class_to_conf(struct ConfItem *);
+extern void conf_add_me(struct ConfItem *);
+extern void conf_add_class(struct ConfItem *, int);
+extern void conf_add_d_conf(struct ConfItem *);
+extern void flush_expired_ips(void *);
+
+
+/* XXX consider moving these into kdparse.h */
+extern void parse_k_file(FILE * fb);
+extern void parse_d_file(FILE * fb);
+extern void parse_x_file(FILE * fb);
+extern void parse_resv_file(FILE *);
+extern char *getfield(char *newline);
+
+extern char *get_oper_name(struct Client *client_p);
+
+extern int yylex(void);
+
+extern unsigned long cidr_to_bitmask[];
+
+extern char conffilebuf[IRCD_BUFSIZE + 1];
+extern int lineno;
+
+#define NOT_AUTHORISED  (-1)
+#define SOCKET_ERROR    (-2)
+#define I_LINE_FULL     (-3)
+#define BANNED_CLIENT   (-4)
+#define TOO_MANY_LOCAL (-6)
+#define TOO_MANY_GLOBAL (-7)
+#define TOO_MANY_IDENT (-8)
+
+#endif /* INCLUDED_s_conf_h */
diff --git a/include/s_gline.h b/include/s_gline.h
new file mode 100644 (file)
index 0000000..58a089a
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  s_gline.h: A header for the gline functions.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: s_gline.h 6 2005-09-10 01:02:21Z nenolod $
+ */
+
+#ifndef INCLUDED_s_gline_h
+#define INCLUDED_s_gline_h
+
+#include "config.h"
+#include "ircd_defs.h"
+
+struct Client;
+struct ConfItem;
+
+extern struct ConfItem *find_is_glined(const char *host, const char *name);
+extern void cleanup_glines(void *unused);
+extern void add_gline(struct ConfItem *);
+
+
+typedef struct gline_pending
+{
+       char oper_nick1[NICKLEN + 1];
+       char oper_user1[USERLEN + 1];
+       char oper_host1[HOSTLEN + 1];
+       const char *oper_server1;       /* point to scache */
+       char *reason1;
+       time_t time_request1;
+
+       char oper_nick2[NICKLEN + 1];
+       char oper_user2[USERLEN + 1];
+       char oper_host2[HOSTLEN + 1];
+       const char *oper_server2;       /* point to scache */
+       char *reason2;
+       time_t time_request2;
+
+       time_t last_gline_time; /* for expiring entry */
+       char user[USERLEN + 1];
+       char host[HOSTLEN + 1];
+}
+gline_pending_t;
+
+/* how long a pending G line can be around
+ * 10 minutes should be plenty
+ */
+
+#define GLINE_PENDING_EXPIRE 600
+#define CLEANUP_GLINES_TIME  300
+
+dlink_list pending_glines;
+extern dlink_list glines;
+
+#endif
diff --git a/include/s_log.h b/include/s_log.h
new file mode 100644 (file)
index 0000000..0a302d1
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * ircd-ratbox: an advanced Internet Relay Chat Daemon(ircd).
+ *
+ * Copyright (C) 2003 Lee Hardy <lee@leeh.co.uk>
+ * Copyright (C) 2003-2004 ircd-ratbox development team
+ *
+ * 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.The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: s_log.h 1481 2006-05-27 17:24:05Z nenolod $
+ */
+
+#ifndef INCLUDED_s_log_h
+#define INCLUDED_s_log_h
+
+#include "ircd_defs.h"
+
+typedef enum ilogfile
+{
+       L_MAIN,
+       L_USER,
+       L_FUSER,
+       L_OPERED,
+       L_FOPER,
+       L_SERVER,
+       L_KILL,
+       L_KLINE,
+       L_GLINE,
+       L_OPERSPY,
+       L_IOERROR,
+       LAST_LOGFILE
+} ilogfile;
+
+struct Client;
+
+extern void init_main_logfile(void);
+extern void open_logfiles(void);
+extern void ilog(ilogfile dest, const char *fmt, ...) AFP(2, 3);
+extern void inotice(const char *fmt, ...) AFP(1, 2);
+extern void iwarn(const char *fmt, ...) AFP(1, 2);
+extern void ierror(const char *fmt, ...) AFP(1, 2);
+extern void report_operspy(struct Client *, const char *, const char *);
+extern const char *smalldate(void);
+extern void report_error(const char *, const char *, const char *, int);
+
+#endif
diff --git a/include/s_newconf.h b/include/s_newconf.h
new file mode 100644 (file)
index 0000000..6179535
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * ircd-ratbox: an advanced Internet Relay Chat Daemon(ircd).
+ * s_newconf.h: code for dealing with conf stuff
+ *
+ * Copyright (C) 2004 Lee Hardy <lee@leeh.co.uk>
+ * Copyright (C) 2004 ircd-ratbox development team
+ *
+ * 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.The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: s_newconf.h 1747 2006-07-25 21:22:45Z jilles $
+ */
+
+#ifndef INCLUDED_s_newconf_h
+#define INCLUDED_s_newconf_h
+
+#include "setup.h"
+#include "tools.h"
+
+#ifdef HAVE_LIBCRYPTO
+#include <openssl/rsa.h>
+#endif
+
+struct ConfItem;
+
+extern dlink_list cluster_conf_list;
+extern dlink_list shared_conf_list;
+extern dlink_list oper_conf_list;
+extern dlink_list hubleaf_conf_list;
+extern dlink_list server_conf_list;
+extern dlink_list xline_conf_list;
+extern dlink_list resv_conf_list;
+extern dlink_list nd_list;
+extern dlink_list tgchange_list;
+
+struct _patricia_tree_t *tgchange_tree;
+
+extern void init_s_newconf(void);
+extern void clear_s_newconf(void);
+extern void clear_s_newconf_bans(void);
+
+#define FREE_TARGET(x) ((x)->localClient->targinfo[0])
+#define USED_TARGETS(x) ((x)->localClient->targinfo[1])
+
+typedef struct
+{
+       char *ip;
+       time_t expiry;
+       patricia_node_t *pnode;
+       dlink_node node;
+} tgchange;
+
+void add_tgchange(const char *host);
+tgchange *find_tgchange(const char *host);
+
+/* shared/cluster/hub/leaf confs */
+struct remote_conf
+{
+       char *username;
+       char *host;
+       char *server;
+       int flags;
+       dlink_node node;
+};
+
+/* flags used in shared/cluster */
+#define SHARED_TKLINE  0x0001
+#define SHARED_PKLINE  0x0002
+#define SHARED_UNKLINE 0x0004
+#define SHARED_LOCOPS  0x0008
+#define SHARED_TXLINE  0x0010
+#define SHARED_PXLINE  0x0020
+#define SHARED_UNXLINE 0x0040
+#define SHARED_TRESV   0x0800
+#define SHARED_PRESV   0x0100
+#define SHARED_UNRESV  0x0200
+#define SHARED_REHASH  0x0400
+
+#define SHARED_ALL     (SHARED_TKLINE | SHARED_PKLINE | SHARED_UNKLINE |\
+                       SHARED_PXLINE | SHARED_TXLINE | SHARED_UNXLINE |\
+                       SHARED_TRESV | SHARED_PRESV | SHARED_UNRESV)
+#define CLUSTER_ALL    (SHARED_ALL | SHARED_LOCOPS)
+
+/* flags used in hub/leaf */
+#define CONF_HUB       0x0001
+#define CONF_LEAF      0x0002
+
+struct oper_conf
+{
+       char *name;
+       char *username;
+       char *host;
+       char *passwd;
+
+       int flags;
+       int umodes;
+
+       unsigned int snomask;
+
+#ifdef HAVE_LIBCRYPTO
+       char *rsa_pubkey_file;
+       RSA *rsa_pubkey;
+#endif
+};
+
+extern struct remote_conf *make_remote_conf(void);
+extern void free_remote_conf(struct remote_conf *);
+
+extern int find_shared_conf(const char *username, const char *host,
+                       const char *server, int flags);
+extern void propagate_generic(struct Client *source_p, const char *command,
+               const char *target, int cap, const char *format, ...);
+extern void cluster_generic(struct Client *, const char *, int cltype,
+                       int cap, const char *format, ...);
+
+#define OPER_ENCRYPTED 0x00001
+#define OPER_KLINE     0x00002
+#define OPER_UNKLINE   0x00004
+#define OPER_LOCKILL   0x00008
+#define OPER_GLOBKILL  0x00010
+#define OPER_REMOTE    0x00020
+#define OPER_GLINE     0x00040
+#define OPER_XLINE     0x00080
+#define OPER_RESV      0x00100
+#define OPER_NICKS     0x00200
+#define OPER_REHASH    0x00400
+#define OPER_DIE       0x00800
+#define OPER_ADMIN     0x01000
+#define OPER_HADMIN    0x02000
+#define OPER_OPERWALL  0x04000
+#define OPER_INVIS     0x08000
+#define OPER_SPY       0x10000
+#define OPER_REMOTEBAN 0x20000
+/*                     0x40000         */
+/* 0x80000 and above are in client.h */
+
+#define OPER_FLAGS     (OPER_KLINE|OPER_UNKLINE|OPER_LOCKILL|OPER_GLOBKILL|\
+                        OPER_REMOTE|OPER_GLINE|OPER_XLINE|OPER_RESV|\
+                        OPER_NICKS|OPER_REHASH|OPER_DIE|OPER_ADMIN|\
+                        OPER_HADMIN|OPER_OPERWALL|OPER_INVIS|OPER_SPY|\
+                        OPER_REMOTEBAN)
+
+#define IsOperConfEncrypted(x) ((x)->flags & OPER_ENCRYPTED)
+
+#define IsOperGlobalKill(x)     ((x)->flags2 & OPER_GLOBKILL)
+#define IsOperLocalKill(x)      ((x)->flags2 & OPER_LOCKILL)
+#define IsOperRemote(x)         ((x)->flags2 & OPER_REMOTE)
+#define IsOperUnkline(x)        ((x)->flags2 & OPER_UNKLINE)
+#define IsOperGline(x)          ((x)->flags2 & OPER_GLINE)
+#define IsOperN(x)              ((x)->flags2 & OPER_NICKS)
+#define IsOperK(x)              ((x)->flags2 & OPER_KLINE)
+#define IsOperXline(x)          ((x)->flags2 & OPER_XLINE)
+#define IsOperDie(x)            ((x)->flags2 & OPER_DIE)
+#define IsOperRehash(x)         ((x)->flags2 & OPER_REHASH)
+#define IsOperHiddenAdmin(x)    ((x)->flags2 & OPER_HADMIN)
+#define IsOperAdmin(x)          (((x)->flags2 & OPER_ADMIN) || \
+                                       ((x)->flags2 & OPER_HADMIN))
+#define IsOperOperwall(x)       ((x)->flags2 & OPER_OPERWALL)
+#define IsOperSpy(x)            ((x)->flags2 & OPER_SPY)
+#define IsOperInvis(x)          ((x)->flags2 & OPER_INVIS)
+#define IsOperRemoteBan(x)     ((x)->flags2 & OPER_REMOTEBAN)
+
+extern struct oper_conf *make_oper_conf(void);
+extern void free_oper_conf(struct oper_conf *);
+extern void clear_oper_conf(void);
+
+extern struct oper_conf *find_oper_conf(const char *username, const char *host,
+                                       const char *locip, const char *oname);
+
+extern const char *get_oper_privs(int flags);
+
+struct server_conf
+{
+       char *name;
+       char *host;
+       char *passwd;
+       char *spasswd;
+       int port;
+       int flags;
+       int servers;
+       time_t hold;
+
+       int aftype;
+       struct irc_sockaddr_storage my_ipnum;
+
+       char *class_name;
+       struct Class *class;
+       dlink_node node;
+};
+
+#define SERVER_ILLEGAL         0x0001
+#define SERVER_VHOSTED         0x0002
+#define SERVER_ENCRYPTED       0x0004
+#define SERVER_COMPRESSED      0x0008
+#define SERVER_TB              0x0010
+#define SERVER_AUTOCONN                0x0020
+
+#define ServerConfIllegal(x)   ((x)->flags & SERVER_ILLEGAL)
+#define ServerConfVhosted(x)   ((x)->flags & SERVER_VHOSTED)
+#define ServerConfEncrypted(x) ((x)->flags & SERVER_ENCRYPTED)
+#define ServerConfCompressed(x)        ((x)->flags & SERVER_COMPRESSED)
+#define ServerConfTb(x)                ((x)->flags & SERVER_TB)
+#define ServerConfAutoconn(x)  ((x)->flags & SERVER_AUTOCONN)
+
+extern struct server_conf *make_server_conf(void);
+extern void free_server_conf(struct server_conf *);
+extern void clear_server_conf(void);
+extern void add_server_conf(struct server_conf *);
+
+extern struct server_conf *find_server_conf(const char *name);
+
+extern void attach_server_conf(struct Client *, struct server_conf *);
+extern void detach_server_conf(struct Client *);
+extern void set_server_conf_autoconn(struct Client *source_p, char *name, 
+                                       int newval);
+
+
+extern struct ConfItem *find_xline(const char *, int);
+extern struct ConfItem *find_nick_resv(const char *name);
+
+extern int valid_wild_card_simple(const char *);
+extern int clean_resv_nick(const char *);
+time_t valid_temp_time(const char *p);
+
+struct nd_entry
+{
+       char name[NICKLEN+1];
+       time_t expire;
+       unsigned int hashv;
+
+       dlink_node hnode;       /* node in hash */
+       dlink_node lnode;       /* node in ll */
+};
+
+extern void add_nd_entry(const char *name);
+extern void free_nd_entry(struct nd_entry *);
+extern unsigned long get_nd_count(void);
+
+#endif
+
diff --git a/include/s_serv.h b/include/s_serv.h
new file mode 100644 (file)
index 0000000..5de8eb1
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  s_serv.h: A header for the server functions.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: s_serv.h 1863 2006-08-27 13:40:37Z jilles $
+ */
+
+#ifndef INCLUDED_serv_h
+#define INCLUDED_serv_h
+
+#include "config.h"
+
+/*
+ * The number of seconds between calls to try_connections(). Fiddle with
+ * this ONLY if you KNOW what you're doing!
+ */
+#define TRY_CONNECTIONS_TIME   60
+
+/* collect ziplinks compression ratios/etc every minute */
+#define ZIPSTATS_TIME           60
+
+/*
+ * number of seconds to wait after server starts up, before
+ * starting try_connections()
+ * TOO SOON and you can nick collide like crazy. 
+ */
+#define STARTUP_CONNECTIONS_TIME 60
+
+struct Client;
+struct server_conf;
+struct Channel;
+
+/* Capabilities */
+struct Capability
+{
+       const char *name;       /* name of capability */
+       unsigned int cap;       /* mask value */
+};
+
+#define CAP_CAP         0x00001        /* received a CAP to begin with */
+#define CAP_QS          0x00002        /* Can handle quit storm removal */
+#define CAP_EX          0x00004        /* Can do channel +e exemptions */
+#define CAP_CHW         0x00008        /* Can do channel wall @# */
+#define CAP_IE          0x00010        /* Can do invite exceptions */
+#define CAP_KLN                0x00040 /* Can do KLINE message */
+#define CAP_GLN                0x00080 /* Can do GLINE message */
+#define CAP_ZIP         0x00100        /* Can do ZIPlinks */
+#define CAP_KNOCK      0x00400 /* supports KNOCK */
+#define CAP_TB         0x00800 /* supports TBURST */
+#define CAP_UNKLN       0x01000        /* supports remote unkline */
+#define CAP_CLUSTER     0x02000        /* supports cluster stuff */
+#define CAP_ENCAP      0x04000 /* supports ENCAP */
+#define CAP_TS6                0x08000 /* supports TS6 or above */
+#define CAP_SERVICE    0x10000
+#define CAP_RSFNC      0x20000 /* rserv FNC */
+#define CAP_SAVE       0x40000 /* supports SAVE (nick collision FNC) */
+#define CAP_EUID       0x80000 /* supports EUID (ext UID + nonencap CHGHOST) */
+
+#define CAP_MASK        (CAP_QS  | CAP_EX   | CAP_CHW  | \
+                         CAP_IE  | CAP_KLN  | CAP_SERVICE |\
+                         CAP_GLN | CAP_CLUSTER | CAP_ENCAP | \
+                         CAP_ZIP  | CAP_KNOCK  | CAP_UNKLN | \
+                        CAP_RSFNC | CAP_SAVE | CAP_EUID)
+
+#ifdef HAVE_LIBZ
+#define CAP_ZIP_SUPPORTED       CAP_ZIP
+#else
+#define CAP_ZIP_SUPPORTED       0
+#endif
+
+/*
+ * Capability macros.
+ */
+#define IsCapable(x, cap)       (((x)->localClient->caps & (cap)) == cap)
+#define NotCapable(x, cap)     (((x)->localClient->caps & (cap)) == 0)
+#define ClearCap(x, cap)        ((x)->localClient->caps &= ~(cap))
+
+#define SLINKCMD_SET_ZIP_OUT_LEVEL           1 /* data */
+#define SLINKCMD_START_ZIP_OUT               2
+#define SLINKCMD_START_ZIP_IN                3
+#define SLINKCMD_INJECT_RECVQ                4 /* data */
+#define SLINKCMD_INJECT_SENDQ                5 /* data */
+#define SLINKCMD_INIT                        6
+#define SLINKCMD_ZIPSTATS                    7
+
+#ifndef HAVE_SOCKETPAIR
+#define LAST_SLINK_FD   7
+#else
+#define LAST_SLINK_FD   5
+#endif
+
+#define SLINKRPL_FLAG_DATA      0x0001 /* reply has data following */
+#define SLINKRPL_ERROR          1
+#define SLINKRPL_ZIPSTATS       2
+
+#define MAX_SLINKRPL            2
+
+typedef void SlinkRplHnd(unsigned int replyid, unsigned int datalen,
+                        unsigned char *data, struct Client *client_p);
+struct SlinkRplDef
+{
+       unsigned int replyid;
+       SlinkRplHnd *handler;
+       unsigned int flags;
+};
+
+extern struct SlinkRplDef slinkrpltab[];
+
+/*
+ * Globals
+ *
+ *
+ * list of recognized server capabilities.  "TS" is not on the list
+ * because all servers that we talk to already do TS, and the kludged
+ * extra argument to "PASS" takes care of checking that.  -orabidoo
+ */
+extern struct Capability captab[];
+
+extern int MaxClientCount;     /* GLOBAL - highest number of clients */
+extern int MaxConnectionCount; /* GLOBAL - highest number of connections */
+
+extern int refresh_user_links;
+
+/*
+ * 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 */
+
+
+extern int hunt_server(struct Client *client_pt,
+                      struct Client *source_pt,
+                      const char *command, int server, int parc, const char **parv);
+extern void send_capabilities(struct Client *, int);
+extern const char *show_capabilities(struct Client *client);
+extern void try_connections(void *unused);
+extern void start_collect_zipstats(void);
+extern void collect_zipstats(void *unused);
+
+extern int check_server(const char *name, struct Client *server);
+extern int server_estab(struct Client *client_p);
+
+extern int serv_connect(struct server_conf *, struct Client *);
+
+#endif /* INCLUDED_s_serv_h */
diff --git a/include/s_stats.h b/include/s_stats.h
new file mode 100644 (file)
index 0000000..1fe7afa
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  s_stats.h: A header for the statistics functions.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: s_stats.h 1409 2006-05-21 14:46:17Z jilles $
+ */
+
+#ifndef INCLUDED_s_stats_h
+#define INCLUDED_s_stats_h
+
+#include "config.h"
+
+#define _1MEG     (1024.0)
+#define _1GIG     (1024.0*1024.0)
+#define _1TER     (1024.0*1024.0*1024.0)
+#define _GMKs(x)  ( (x > _1TER) ? "Terabytes" : ((x > _1GIG) ? "Gigabytes" : \
+                  ((x > _1MEG) ? "Megabytes" : "Kilobytes")))
+#define _GMKv(x)  ( (x > _1TER) ? (float)(x/_1TER) : ((x > _1GIG) ? \
+                  (float)(x/_1GIG) : ((x > _1MEG) ? (float)(x/_1MEG) : (float)x)))
+
+struct Client;
+
+/*
+ * statistics structures
+ */
+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 */
+       unsigned short is_cbs;  /* bytes sent to clients */
+       unsigned short is_cbr;  /* bytes received to clients */
+       unsigned short is_sbs;  /* bytes sent to servers */
+       unsigned short is_sbr;  /* bytes received to servers */
+       unsigned long is_cks;   /* k-bytes sent to clients */
+       unsigned long is_ckr;   /* k-bytes received to clients */
+       unsigned long is_sks;   /* k-bytes sent to servers */
+       unsigned long is_skr;   /* k-bytes received to servers */
+       time_t is_cti;          /* time spent connected by clients */
+       time_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_save;   /* number of saves generated on collisions */
+       unsigned int is_asuc;   /* successful auth requests */
+       unsigned int is_abad;   /* bad auth requests */
+       unsigned int is_rej;    /* rejected from cache */
+       unsigned int is_ssuc;   /* successful sasl authentications */
+       unsigned int is_sbad;   /* failed sasl authentications */
+};
+
+extern struct ServerStatistics *ServerStats;
+
+extern void init_stats(void);
+extern void tstats(struct Client *client);
+
+extern void count_memory(struct Client *);
+
+#endif /* INCLUDED_s_stats_h */
diff --git a/include/s_user.h b/include/s_user.h
new file mode 100644 (file)
index 0000000..85da275
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  s_user.h: A header for the user functions.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: s_user.h 1887 2006-08-29 13:42:56Z jilles $
+ */
+
+#ifndef INCLUDED_s_user_h
+#define INCLUDED_s_user_h
+
+#include "config.h"
+
+struct Client;
+struct User;
+struct oper_conf;
+extern time_t LastUsedWallops;
+
+extern int valid_hostname(const char *hostname);
+extern int valid_username(const char *username);
+
+extern int user_mode(struct Client *, struct Client *, int, const char **);
+extern void send_umode(struct Client *, struct Client *, int, int, char *);
+extern void send_umode_out(struct Client *, struct Client *, int);
+extern int show_lusers(struct Client *source_p);
+extern int register_local_user(struct Client *, struct Client *, const char *);
+
+extern int introduce_client(struct Client *client_p, struct Client *source_p, 
+                           struct User *user, const char *nick, int use_euid);
+
+extern void change_nick_user_host(struct Client *target_p, const char *nick, const char *user,
+                                 const char *host, int newts, char *format, ...);
+
+extern int user_modes[256];
+extern void construct_umodebuf(void);
+
+extern int oper_up(struct Client *, struct oper_conf *);
+
+#endif
diff --git a/include/scache.h b/include/scache.h
new file mode 100644 (file)
index 0000000..9c7fc27
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  scache.h: A header for the servername cache functions.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: scache.h 6 2005-09-10 01:02:21Z nenolod $
+ */
+
+#ifndef INCLUDED_scache_h
+#define INCLUDED_scache_h
+
+extern void clear_scache_hash_table(void);
+extern const char *find_or_add(const char *name);
+extern void count_scache(size_t *, size_t *);
+
+#endif
diff --git a/include/send.h b/include/send.h
new file mode 100644 (file)
index 0000000..f1f5349
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  send.h: A header for the message sending functions.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: send.h 661 2006-02-03 04:20:31Z gxti $
+ */
+
+#ifndef INCLUDED_send_h
+#define INCLUDED_send_h
+
+#include "ircd_defs.h"
+#include "config.h"            /* HAVE_STDARG_H */
+
+struct Client;
+struct Channel;
+struct dlink_list;
+
+/* The nasty global also used in s_serv.c for server bursts */
+extern unsigned long current_serial;
+
+extern void send_queued_write(int fd, void *data);
+extern void send_queued_slink_write(int fd, void *data);
+
+extern void sendto_one(struct Client *target_p, const char *, ...) AFP(2, 3);
+extern void sendto_one_notice(struct Client *target_p,const char *, ...) AFP(2, 3);
+extern void sendto_one_prefix(struct Client *target_p, struct Client *source_p,
+                             const char *command, const char *, ...) AFP(4, 5);
+extern void sendto_one_numeric(struct Client *target_p,
+                              int numeric, const char *, ...) AFP(3, 4);
+
+extern void sendto_server(struct Client *one, struct Channel *chptr,
+                         unsigned long caps, unsigned long nocaps,
+                         const char *format, ...) AFP(5, 6);
+
+extern void sendto_channel_flags(struct Client *one, int type, struct Client *source_p,
+                                struct Channel *chptr, const char *, ...) AFP(5, 6);
+
+extern void sendto_channel_local(int type, struct Channel *, const char *, ...) AFP(3, 4);
+extern void sendto_channel_local_butone(struct Client *, int type, struct Channel *, const char *, ...) AFP(4, 5);
+extern void sendto_common_channels_local(struct Client *, const char *, ...) AFP(2, 3);
+extern void sendto_common_channels_local_butone(struct Client *, const char *, ...) AFP(2, 3);
+
+
+extern void sendto_match_butone(struct Client *, struct Client *,
+                               const char *, int, const char *, ...) AFP(5, 6);
+extern void sendto_match_servs(struct Client *source_p, const char *mask, 
+                               int capab, int, const char *, ...) AFP(5, 6);
+
+extern void sendto_anywhere(struct Client *, struct Client *, const char *,
+                           const char *, ...) AFP(4, 5);
+
+extern void sendto_realops_flags(int, int, const char *, ...) AFP(3, 4);
+extern void sendto_realops_snomask(int, int, const char *, ...) AFP(3, 4);
+extern void sendto_realops_snomask_from(int, int, struct Client *, const char *, ...) AFP(4, 5);
+
+extern void sendto_wallops_flags(int, struct Client *, const char *, ...) AFP(3, 4);
+
+extern void kill_client(struct Client *client_p, struct Client *diedie,
+                        const char *pattern, ...) AFP(3, 4);
+extern void kill_client_serv_butone(struct Client *one, struct Client *source_p, 
+                                   const char *pattern, ...) AFP(3, 4);
+
+#define L_ALL  0
+#define L_OPER         1
+#define L_ADMIN        2
+#define L_NETWIDE 256 /* OR with L_ALL or L_OPER */
+
+#define NOCAPS          0      /* no caps */
+
+/* used when sending to #mask or $mask */
+#define MATCH_SERVER  1
+#define MATCH_HOST    2
+
+#endif /* INCLUDED_send_h */
diff --git a/include/serno.h b/include/serno.h
new file mode 100644 (file)
index 0000000..da83cab
--- /dev/null
@@ -0,0 +1 @@
+#define SERNO "20070123-3139"
diff --git a/include/setup.h.in b/include/setup.h.in
new file mode 100644 (file)
index 0000000..54a7b80
--- /dev/null
@@ -0,0 +1,347 @@
+/* include/setup.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Size of the ban heap. */
+#undef BAN_HEAP_SIZE
+
+/* Size of the channel heap. */
+#undef CHANNEL_HEAP_SIZE
+
+/* Define this if you are profiling. */
+#undef CHARYBDIS_PROFILE
+
+/* Size of the client heap. */
+#undef CLIENT_HEAP_SIZE
+
+/* Size of the confitem heap. */
+#undef CONFITEM_HEAP_SIZE
+
+/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
+   systems. This function is required for `alloca.c' support on those systems.
+   */
+#undef CRAY_STACKSEG_END
+
+/* Define to 1 if using `alloca.c'. */
+#undef C_ALLOCA
+
+/* Size of the dlink_node heap. */
+#undef DNODE_HEAP_SIZE
+
+/* Prefix where config files are installed. */
+#undef ETC_DIR
+
+/* Define to 1 if you have `alloca', as a function or macro. */
+#undef HAVE_ALLOCA
+
+/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
+   */
+#undef HAVE_ALLOCA_H
+
+/* Define to 1 if you have the <crypt.h> header file. */
+#undef HAVE_CRYPT_H
+
+/* Define to 1 if you have the <devpoll.h> header file. */
+#undef HAVE_DEVPOLL_H
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the `dlfunc' function. */
+#undef HAVE_DLFUNC
+
+/* Define if the dlopen function is available. */
+#undef HAVE_DLOPEN
+
+/* Define if your system supports the epoll system calls */
+#undef HAVE_EPOLL
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+#undef HAVE_EPOLL_CTL
+
+/* Define to 1 if you have the <errno.h> header file. */
+#undef HAVE_ERRNO_H
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `kevent' function. */
+#undef HAVE_KEVENT
+
+/* Define to 1 if you have the `crypto' library (-lcrypto). */
+#undef HAVE_LIBCRYPTO
+
+/* Define to 1 if zlib (-lz) is available. */
+#undef HAVE_LIBZ
+
+/* Define to 1 if you have the <machine/endian.h> header file. */
+#undef HAVE_MACHINE_ENDIAN_H
+
+/* Define to 1 if you have the <mach-o/dyld.h> header file. */
+#undef HAVE_MACH_O_DYLD_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `mmap' function. */
+#undef HAVE_MMAP
+
+/* Define if nanosleep exists */
+#undef HAVE_NANOSLEEP
+
+/* Define to 1 if you have the `poll' function. */
+#undef HAVE_POLL
+
+/* Define to 1 if you have the `select' function. */
+#undef HAVE_SELECT
+
+/* Define if the shl_load function is available. */
+#undef HAVE_SHL_LOAD
+
+/* Define to 1 if you have the `socketpair' function. */
+#undef HAVE_SOCKETPAIR
+
+/* Define to 1 if you have the <stddef.h> header file. */
+#undef HAVE_STDDEF_H
+
+/* 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 `strdup' function. */
+#undef HAVE_STRDUP
+
+/* 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 `strlcat' function. */
+#undef HAVE_STRLCAT
+
+/* Define to 1 if you have the `strlcpy' function. */
+#undef HAVE_STRLCPY
+
+/* Define to 1 if you have the `strndup' function. */
+#undef HAVE_STRNDUP
+
+/* 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/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/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/syslog.h> header file. */
+#undef HAVE_SYS_SYSLOG_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#undef HAVE_SYS_UIO_H
+
+/* Define to 1 if you have the <sys/wait.h> header file. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define to 1 if the system has the type `uintptr_t'. */
+#undef HAVE_UINTPTR_T
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#undef HAVE_VSNPRINTF
+
+/* Define to 1 if you have the <wait.h> header file. */
+#undef HAVE_WAIT_H
+
+/* Prefix where help file are installed. */
+#undef HELP_DIR
+
+/* Define if IPv6 support is present and available. */
+#undef IPV6
+
+/* Prefix where the ircd is installed. */
+#undef IRCD_PREFIX
+
+/* Size of the local client heap. */
+#undef LCLIENT_HEAP_SIZE
+
+/* Size of the linebuf heap. */
+#undef LINEBUF_HEAP_SIZE
+
+/* Prefix where to write logfiles. */
+#undef LOG_DIR
+
+/* the system's memory page size */
+#undef MALLOC_PAGESIZE
+
+/* Maximum number of network connections */
+#undef MAX_CLIENTS
+
+/* Sizeof member heap. */
+#undef MEMBER_HEAP_SIZE
+
+/* Prefix where modules are installed. */
+#undef MODULE_DIR
+
+/* Size of the monitor heap. */
+#undef MONITOR_HEAP_SIZE
+
+/* Define this to disable debugging support. */
+#undef NDEBUG
+
+/* Size of the nick delay heap. */
+#undef ND_HEAP_SIZE
+
+/* Nickname length */
+#undef NICKLEN
+
+/* Size of the WHOWAS array. */
+#undef NICKNAMEHISTORYLENGTH
+
+/* Define to 1 if you wish to disable the block allocator. */
+#undef NOBALLOC
+
+/* Define to 1 if your system has no in6addr_any. */
+#undef NO_IN6ADDR_ANY
+
+/* 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
+
+/* Path to /dev/null */
+#undef PATH_DEVNULL
+
+/* Size of the pre-client heap. */
+#undef PCLIENT_HEAP_SIZE
+
+/* Define to 1 if you are using the assembly-based hashing routines. */
+#undef RICER_HASHING
+
+/* This is the type of IO loop we are using */
+#undef SELECT_TYPE
+
+/* Suffix for shared libraries on this platform. */
+#undef SHARED_SUFFIX
+
+/* The size of a `int', as computed by sizeof. */
+#undef SIZEOF_INT
+
+/* 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
+
+/* Define to 1 if sockaddr has a 'sa_len' member. */
+#undef SOCKADDR_IN_HAS_LEN
+
+/* Define this to enable soft asserts. */
+#undef SOFT_ASSERT
+
+/* If using the C implementation of alloca, define if you know the
+   direction of stack growth for your system; otherwise it will be
+   automatically deduced at run-time.
+       STACK_DIRECTION > 0 => grows toward higher addresses
+       STACK_DIRECTION < 0 => grows toward lower addresses
+       STACK_DIRECTION = 0 => direction of growth unknown */
+#undef STACK_DIRECTION
+
+/* Define to 1 if dynamic modules can't be used. */
+#undef STATIC_MODULES
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if string.h may be included along with strings.h */
+#undef STRING_WITH_STRINGS
+
+/* String containing extra underscores prepended to symbols loaded from
+   modules. */
+#undef SYMBOL_PREFIX
+
+/* Maximum topic length (<=390) */
+#undef TOPICLEN
+
+/* Size of the topic heap. */
+#undef TOPIC_HEAP_SIZE
+
+/* Size of the user heap. */
+#undef USER_HEAP_SIZE
+
+/* Define this to enable IO Debug hooks. */
+#undef USE_IODEBUG_HOOKS
+
+/* 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
+
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+
+/* This is needed to use strtok_r on Solaris. */
+#undef __EXTENSIONS__
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* If system does not define in_port_t, define it to what it should be. */
+#undef in_port_t
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef pid_t
+
+/* If system does not define sa_family_t, define it here. */
+#undef sa_family_t
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef size_t
+
+/* If we don't have a real socklen_t, unsigned int is good enough. */
+#undef socklen_t
+
+/* If system does not define u_int16_t, define a usable substitute. */
+#undef u_int16_t
+
+/* If system does not define u_int32_t, define to unsigned long int here. */
+#undef u_int32_t
diff --git a/include/snomask.h b/include/snomask.h
new file mode 100644 (file)
index 0000000..a4d12a6
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * charybdis: An advanced ircd.
+ * snomask.h: Management for user server-notice masks.
+ *
+ * Copyright (c) 2006 William Pitcock <nenolod@nenolod.net>
+ *
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id$
+ */
+
+#ifndef SNOMASK_H
+#define SNOMASK_H
+
+#include "client.h"
+
+#define SNO_ADD                        1
+#define SNO_DEL                        2
+
+#define SNO_CCONNEXT           0x00000001
+#define SNO_BOTS               0x00000002
+#define SNO_CCONN              0x00000004
+#define SNO_DEBUG              0x00000008
+#define SNO_FULL               0x00000010
+#define SNO_SKILL              0x00000020
+#define SNO_NCHANGE            0x00000040
+#define SNO_REJ                        0x00000080
+#define SNO_GENERAL            0x00000100
+#define SNO_UNAUTH             0x00000200
+#define SNO_EXTERNAL           0x00000400
+#define SNO_SPY                        0x00000800
+#define SNO_OPERSPY            0x00001000
+
+char *construct_snobuf(unsigned int val);
+unsigned int parse_snobuf_to_mask(unsigned int val, const char *sno);
+unsigned int find_snomask_slot(void);
+
+extern int snomask_modes[];
+
+#endif
diff --git a/include/sprintf_irc.h b/include/sprintf_irc.h
new file mode 100644 (file)
index 0000000..b544132
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  sprintf_irc.h: The irc sprintf header.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: sprintf_irc.h 6 2005-09-10 01:02:21Z nenolod $
+ */
+
+#ifndef SPRINTF_IRC
+#define SPRINTF_IRC
+
+#include <stdarg.h>
+
+/*=============================================================================
+ * Proto types
+ */
+
+
+/*
+ * ircsprintf - optimized sprintf
+ */
+#ifdef __GNUC__
+int ircsprintf(char *str, const char *fmt, ...) __attribute((format(printf, 2, 3)));
+int ircsnprintf(char *str, const size_t size, const char *, ...) __attribute__ ((format(printf, 3, 4)));
+#else
+int ircsprintf(char *str, const char *format, ...);
+int ircsnprintf(char *str, const size_t size, const char *, ...);
+#endif
+
+int ircvsnprintf(char *str, const size_t size, const char *fmt, va_list args);
+int ircvsprintf(char *str, const char *fmt, va_list args);
+
+#endif /* SPRINTF_IRC */
diff --git a/include/stdinc.h b/include/stdinc.h
new file mode 100644 (file)
index 0000000..ddf881a
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  stdinc.h: Pull in all of the necessary system headers
+ *
+ *  Copyright (C) 2002 Aaron Sethman <androsyn@ratbox.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 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: stdinc.h 6 2005-09-10 01:02:21Z nenolod $
+ *
+ */
+
+
+#include "config.h"            /* Gotta pull in the autoconf stuff */
+
+/* AIX requires this to be the first thing in the file.  */
+#ifdef __GNUC__
+#undef alloca
+#define alloca __builtin_alloca
+#else
+# ifdef _MSC_VER
+#  include <malloc.h>
+#  define alloca _alloca
+# else
+#  if HAVE_ALLOCA_H
+#   include <alloca.h>
+#  else
+#   ifdef _AIX
+ #pragma alloca
+#   else
+#    ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+#    endif
+#   endif
+#  endif
+# endif
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef STRING_WITH_STRINGS
+# include <string.h>
+# include <strings.h>
+#else
+# ifdef HAVE_STRING_H
+#  include <string.h>
+# else
+#  ifdef HAVE_STRINGS_H
+#   include <strings.h>
+#  endif
+# endif
+#endif
+
+
+#ifdef HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+
+
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdio.h>
+#include <time.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <dirent.h>
+#include <ctype.h>
+
+#include <limits.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#else
+extern int errno;
+#endif
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#if defined(__INTEL_COMPILER) || defined(__GNUC__)
+# ifdef __unused
+#  undef __unused
+# endif
+# ifdef __printf
+#  undef __printf
+# endif
+# ifdef __noreturn
+#  undef __noreturn
+# endif
+
+# define __unused __attribute__((__unused__))
+# define __printf(x) __attribute__((__format__ (__printf__, x, x + 1)))
+# define __noreturn __attribute__((__noreturn__))
+#else
+# define __unused
+# define __printf
+# define __noreturn
+#endif
+
+
+
+#ifdef strdupa
+#define LOCAL_COPY(s) strdupa(s) 
+#else
+#if defined(__INTEL_COMPILER) || defined(__GNUC__)
+# define LOCAL_COPY(s) __extension__({ char *_s = alloca(strlen(s) + 1); strcpy(_s, s); _s; })
+#else
+# define LOCAL_COPY(s) strcpy(alloca(strlen(s) + 1), s) /* XXX Is that allowed? */
+#endif /* defined(__INTEL_COMPILER) || defined(__GNUC__) */
+#endif /* strdupa */
diff --git a/include/supported.h b/include/supported.h
new file mode 100644 (file)
index 0000000..55e33e1
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ *  charybdis: A slightly useful ircd.
+ *  supported.h: isupport (005) numeric
+ *
+ *  Entirely rewritten, August 2006 by Jilles Tjoelker
+ *  Copyright (C) 2006 Jilles Tjoelker
+ * 
+ *  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.The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ * 
+ *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ *  $Id: supported.h 1887 2006-08-29 13:42:56Z jilles $
+ */
+
+#ifndef INCLUDED_supported_h
+#define INCLUDED_supported_h
+
+extern void add_isupport(const char *, const char *(*)(void *), void *);
+extern void delete_isupport(const char *);
+extern void show_isupport(struct Client *);
+extern void init_isupport(void);
+
+extern const char *isupport_intptr(void *);
+extern const char *isupport_boolean(void *);
+extern const char *isupport_string(void *);
+extern const char *isupport_stringptr(void *);
+
+#endif /* INCLUDED_supported_h */
diff --git a/include/whowas.h b/include/whowas.h
new file mode 100644 (file)
index 0000000..4d5ab21
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  whowas.h: Header for the whowas functions.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: whowas.h 1717 2006-07-04 14:41:11Z jilles $
+ */
+#ifndef INCLUDED_whowas_h
+#define INCLUDED_whowas_h
+
+#include "ircd_defs.h"
+#include "client.h"
+
+#include "setup.h"
+
+/*
+ * Whowas hash table size
+ *
+ */
+#define WW_MAX_BITS 16
+#define WW_MAX 65536
+
+struct User;
+struct Client;
+
+/*
+  lets speed this up...
+  also removed away information. *tough*
+  - Dianora
+ */
+struct Whowas
+{
+       int hashv;
+       char name[NICKLEN + 1];
+       char username[USERLEN + 1];
+       char hostname[HOSTLEN + 1];
+       char sockhost[HOSTIPLEN + 1];
+       const char *servername;
+       char realname[REALLEN + 1];
+       time_t logoff;
+       struct Client *online;  /* Pointer to new nickname for chasing or NULL */
+       struct Whowas *next;    /* for hash table... */
+       struct Whowas *prev;    /* for hash table... */
+       struct Whowas *cnext;   /* for client struct linked list */
+       struct Whowas *cprev;   /* for client struct linked list */
+};
+
+/*
+** initwhowas
+*/
+extern void initwhowas(void);
+
+/*
+** add_history
+**      Add the currently defined name of the client to history.
+**      usually called before changing to a new name (nick).
+**      Client must be a fully registered user (specifically,
+**      the user structure must have been allocated).
+*/
+void add_history(struct Client *, int);
+
+/*
+** off_history
+**      This must be called when the client structure is about to
+**      be released. History mechanism keeps pointers to client
+**      structures and it must know when they cease to exist. This
+**      also implicitly calls AddHistory.
+*/
+void off_history(struct Client *);
+
+/*
+** get_history
+**      Return the current client that was using the given
+**      nickname within the timelimit. Returns NULL, if no
+**      one found...
+*/
+struct Client *get_history(const char *, time_t);
+                                       /* Nick name */
+                                       /* Time limit in seconds */
+
+/*
+** for debugging...counts related structures stored in whowas array.
+*/
+void count_whowas_memory(size_t *, size_t *);
+
+/* XXX m_whowas.c in modules needs these */
+extern struct Whowas WHOWAS[];
+extern struct Whowas *WHOWASHASH[];
+extern unsigned int hash_whowas_name(const char *name);
+
+#endif /* INCLUDED_whowas_h */
diff --git a/install-sh b/install-sh
new file mode 100644 (file)
index 0000000..bbfd618
--- /dev/null
@@ -0,0 +1,270 @@
+#!/bin/sh
+# $Id: install-sh 6 2005-09-10 01:02:21Z nenolod $
+#
+# install - install a program, script, or datafile
+#
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# 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=:
+               chmodcmd=""
+       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/libcharybdis/Makefile.in b/libcharybdis/Makefile.in
new file mode 100644 (file)
index 0000000..e5023a9
--- /dev/null
@@ -0,0 +1,87 @@
+#
+# Makefile.in for ircd/src/io
+#
+# $Id: Makefile.in 1269 2006-04-30 16:51:11Z nenolod $
+#
+CC             = @CC@
+INSTALL                = @INSTALL@
+INSTALL_BIN    = @INSTALL_PROGRAM@
+INSTALL_DATA   = @INSTALL_DATA@
+INSTALL_SUID   = @INSTALL_PROGRAM@ -o root -m 4755
+RM             = @RM@
+LEX            = @LEX@
+LEXLIB         = @LEXLIB@
+CFLAGS         = @IRC_CFLAGS@ -DIRCD_PREFIX=\"@prefix@\"
+LDFLAGS        = @LDFLAGS@
+MKDEP          = @MKDEP@ -DIRCD_PREFIX=\"@prefix@\"
+MV             = @MV@
+RM             = @RM@
+YACC           = @YACC@
+AR             = @AR@
+RANLIB         = @RANLIB@
+
+prefix         = @prefix@
+exec_prefix    = @exec_prefix@
+bindir         = @bindir@
+libexecdir     = @libexecdir@
+sysconfdir     = @sysconfdir@
+localstatedir  = @localstatedir@
+# Change this later! -- adrian
+moduledir      = @prefix@/modules
+automoduledir  = @prefix@/modules/autoload
+
+INCLUDES       = -I../include -I../adns -I.
+CPPFLAGS       = ${INCLUDES} @CPPFLAGS@
+default:       all
+
+BASE_SRCS =            \
+       balloc.c        \
+       commio.c        \
+       event.c         \
+       libcharybdis.c  \
+       linebuf.c       \
+       memory.c        \
+       snprintf.c      \
+       tools.c
+
+SRCS = ${BASE_SRCS} @SELECT_TYPE@.c
+
+OBJS = ${SRCS:.c=.o}
+
+all:   libcharybdis.a
+
+build: all
+
+libcharybdis.a: ${OBJS}
+               rm -f $@
+               ${AR} cqv $@ ${OBJS}
+               ${RANLIB} $@
+
+# this is really the default rule for c files
+.c.o:
+       ${CC} ${CPPFLAGS} ${CFLAGS} -c $<
+
+.PHONY: depend clean distclean
+
+install: 
+
+depend:
+       @${MKDEP} ${CPPFLAGS} ${BASE_SRCS} ${EXTRA_SRCS} > .depend.tmp
+       @sed -e '/^# DO NOT DELETE THIS LINE/,$$d' <Makefile >Makefile.depend
+       @echo '# DO NOT DELETE THIS LINE!!!' >>Makefile.depend
+       @echo '# make depend needs it.' >>Makefile.depend
+       @cat .depend.tmp >>Makefile.depend
+       @mv Makefile.depend Makefile
+       @rm -f .depend.tmp
+
+clean:
+       ${RM} -f *.o *.exe *~ libcharybdis.a
+
+lint:
+
+distclean: clean
+       ${RM} -f Makefile version.c.last
+
+# DO NOT DELETE THIS LINE!!!
+# make depend needs it.
diff --git a/libcharybdis/balloc.c b/libcharybdis/balloc.c
new file mode 100644 (file)
index 0000000..c3f0bbe
--- /dev/null
@@ -0,0 +1,652 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  balloc.c: A block allocator.
+ *
+ * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ * Copyright (C) 1996-2002 Hybrid Development Team
+ * Copyright (C) 2002-2005 ircd-ratbox development team
+ *
+ *  File:   blalloc.c
+ *  Owner:  Wohali (Joan Touzet)
+ *  
+ *  Modified 2001/11/29 for mmap() support by Aaron Sethman <androsyn@ratbox.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 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: balloc.c 388 2005-12-07 16:34:40Z nenolod $
+ */
+
+/* 
+ * About the block allocator
+ *
+ * Basically we have three ways of getting memory off of the operating
+ * system. Below are this list of methods and the order of preference.
+ *
+ * 1. mmap() anonymous pages with the MMAP_ANON flag.
+ * 2. mmap() via the /dev/zero trick.
+ * 3. malloc() 
+ *
+ * The advantages of 1 and 2 are this.  We can munmap() the pages which will
+ * return the pages back to the operating system, thus reducing the size 
+ * of the process as the memory is unused.  malloc() on many systems just keeps
+ * a heap of memory to itself, which never gets given back to the OS, except on
+ * exit.  This of course is bad, if say we have an event that causes us to allocate
+ * say, 200MB of memory, while our normal memory consumption would be 15MB.  In the
+ * malloc() case, the amount of memory allocated to our process never goes down, as
+ * malloc() has it locked up in its heap.  With the mmap() method, we can munmap()
+ * the block and return it back to the OS, thus causing our memory consumption to go
+ * down after we no longer need it.
+ * 
+ * Of course it is up to the caller to make sure BlockHeapGarbageCollect() gets
+ * called periodically to do this cleanup, otherwise you'll keep the memory in the
+ * process.
+ *
+ *
+ */
+
+#include "stdinc.h"
+#include "libcharybdis.h"
+
+#define WE_ARE_MEMORY_C
+#include "setup.h"
+#include "balloc.h"
+#ifndef NOBALLOC
+
+#include "ircd_defs.h"         /* DEBUG_BLOCK_ALLOCATOR */
+#include "ircd.h"
+#include "memory.h"
+#include "irc_string.h"
+#include "tools.h"
+#include "s_log.h"
+#include "client.h"
+#include "event.h"
+
+#ifdef HAVE_MMAP               /* We've got mmap() that is good */
+#include <sys/mman.h>
+/* HP-UX sucks */
+#ifdef MAP_ANONYMOUS
+#ifndef MAP_ANON
+#define MAP_ANON MAP_ANONYMOUS
+#endif
+#endif
+#endif
+
+static int newblock(BlockHeap * bh);
+static int BlockHeapGarbageCollect(BlockHeap *);
+static void block_heap_gc(void *unused);
+static dlink_list heap_lists;
+
+#if defined(HAVE_MMAP) && !defined(MAP_ANON)
+static int zero_fd = -1;
+#endif
+
+#define blockheap_fail(x) _blockheap_fail(x, __FILE__, __LINE__)
+
+static void
+_blockheap_fail(const char *reason, const char *file, int line)
+{
+       libcharybdis_log("Blockheap failure: %s (%s:%d)", reason, file, line);
+       abort();
+}
+                
+
+/*
+ * static inline void free_block(void *ptr, size_t size)
+ *
+ * Inputs: The block and its size
+ * Output: None
+ * Side Effects: Returns memory for the block back to the OS
+ */
+static inline void
+free_block(void *ptr, size_t size)
+{
+#ifdef HAVE_MMAP
+       munmap(ptr, size);
+#else
+       free(ptr);
+#endif
+}
+
+#ifdef DEBUG_BALLOC
+/* Check the list length the very slow way */
+static unsigned long
+slow_list_length(dlink_list *list)
+{
+       dlink_node *ptr;
+       unsigned long count = 0;
+    
+       for (ptr = list->head; ptr; ptr = ptr->next)
+       {
+               count++;
+               if(count > list->length * 2)
+               {
+                       blockheap_fail("count > list->length * 2 - I give up");
+               }
+       }
+       return count;
+}
+
+static void
+bh_sanity_check_block(BlockHeap *bh, Block *block)
+{
+       unsigned long s_used, s_free;
+       s_used = slow_list_length(&block->used_list);
+       s_free = slow_list_length(&block->free_list);
+       if(s_used != dlink_list_length(&block->used_list))
+               blockheap_fail("used link count doesn't match head count");
+       if(s_free != dlink_list_length(&block->free_list))
+               blockheap_fail("free link count doesn't match head count");
+       
+       if(dlink_list_length(&block->used_list) + dlink_list_length(&block->free_list) != bh->elemsPerBlock)
+               blockheap_fail("used_list + free_list != elemsPerBlock");
+}
+
+#if 0
+/* See how confused we are */
+static void
+bh_sanity_check(BlockHeap *bh)
+{
+       Block *walker;
+       unsigned long real_alloc = 0;
+       unsigned long s_used, s_free;
+       unsigned long blockcount = 0;
+       unsigned long allocated;
+       if(bh == NULL)
+               blockheap_fail("Trying to sanity check a NULL block");          
+       
+       allocated = bh->blocksAllocated * bh->elemsPerBlock;
+       
+       for(walker = bh->base; walker != NULL; walker = walker->next)
+       {
+               blockcount++;
+               s_used = slow_list_length(&walker->used_list);
+               s_free = slow_list_length(&walker->free_list);
+               
+               if(s_used != dlink_list_length(&walker->used_list))
+                       blockheap_fail("used link count doesn't match head count");
+               if(s_free != dlink_list_length(&walker->free_list))
+                       blockheap_fail("free link count doesn't match head count");
+               
+               if(dlink_list_length(&walker->used_list) + dlink_list_length(&walker->free_list) != bh->elemsPerBlock)
+                       blockheap_fail("used_list + free_list != elemsPerBlock");
+
+               real_alloc += dlink_list_length(&walker->used_list);
+               real_alloc += dlink_list_length(&walker->free_list);
+       }
+
+       if(allocated != real_alloc)
+               blockheap_fail("block allocations don't match heap");
+
+       if(bh->blocksAllocated != blockcount)
+               blockheap_fail("blocksAllocated don't match blockcount");
+
+        
+}
+
+static void
+bh_sanity_check_all(void *unused)
+{
+        dlink_node *ptr;
+       DLINK_FOREACH(ptr, heap_lists.head)
+       {
+               bh_sanity_check(ptr->data);
+       }                               
+}
+#endif
+
+#endif
+
+
+
+/*
+ * void initBlockHeap(void)
+ * 
+ * Inputs: None
+ * Outputs: None
+ * Side Effects: Initializes the block heap
+ */
+
+void
+initBlockHeap(void)
+{
+#if defined(HAVE_MMAP) && !defined(MAP_ANON)
+       zero_fd = open("/dev/zero", O_RDWR);
+
+       if(zero_fd < 0)
+               blockheap_fail("Failed opening /dev/zero");
+       comm_socket(zero_fd, FD_FILE, "Anonymous mmap()");
+#endif
+       eventAddIsh("block_heap_gc", block_heap_gc, NULL, 30);
+}
+
+/*
+ * static inline void *get_block(size_t size)
+ * 
+ * Input: Size of block to allocate
+ * Output: Pointer to new block
+ * Side Effects: None
+ */
+static inline void *
+get_block(size_t size)
+{
+       void *ptr;
+#ifdef HAVE_MMAP
+#ifdef MAP_ANON
+       ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+#else
+       ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, zero_fd, 0);
+#endif
+       if(ptr == MAP_FAILED)
+       {
+               ptr = NULL;
+       }
+#else
+       ptr = malloc(size);
+#endif
+       return (ptr);
+}
+
+
+static void
+block_heap_gc(void *unused)
+{
+       dlink_node *ptr;
+       DLINK_FOREACH(ptr, heap_lists.head)
+       {
+               BlockHeapGarbageCollect(ptr->data);
+       }
+}
+
+/* ************************************************************************ */
+/* FUNCTION DOCUMENTATION:                                                  */
+/*    newblock                                                              */
+/* Description:                                                             */
+/*    Allocates a new block for addition to a blockheap                     */
+/* Parameters:                                                              */
+/*    bh (IN): Pointer to parent blockheap.                                 */
+/* Returns:                                                                 */
+/*    0 if successful, 1 if not                                             */
+/* ************************************************************************ */
+
+static int
+newblock(BlockHeap * bh)
+{
+       MemBlock *newblk;
+       Block *b;
+       unsigned long i;
+       void *offset;
+
+       /* Setup the initial data structure. */
+       b = (Block *) calloc(1, sizeof(Block));
+       if(b == NULL)
+       {
+               return (1);
+       }
+       b->free_list.head = b->free_list.tail = NULL;
+       b->used_list.head = b->used_list.tail = NULL;
+       b->next = bh->base;
+
+       b->alloc_size = (bh->elemsPerBlock + 1) * (bh->elemSize + sizeof(MemBlock));
+
+       b->elems = get_block(b->alloc_size);
+       if(b->elems == NULL)
+       {
+               return (1);
+       }
+       offset = b->elems;
+       /* Setup our blocks now */
+       for (i = 0; i < bh->elemsPerBlock; i++)
+       {
+               void *data;
+               newblk = (void *) offset;
+               newblk->block = b;
+#ifdef DEBUG_BALLOC
+               newblk->magic = BALLOC_MAGIC;
+#endif
+               data = (void *) ((size_t) offset + sizeof(MemBlock));
+               newblk->block = b;
+               dlinkAdd(data, &newblk->self, &b->free_list);
+               offset = (unsigned char *) ((unsigned char *) offset +
+                                           bh->elemSize + sizeof(MemBlock));
+       }
+
+       ++bh->blocksAllocated;
+       bh->freeElems += bh->elemsPerBlock;
+       bh->base = b;
+
+       return (0);
+}
+
+
+/* ************************************************************************ */
+/* FUNCTION DOCUMENTATION:                                                  */
+/*    BlockHeapCreate                                                       */
+/* Description:                                                             */
+/*   Creates a new blockheap from which smaller blocks can be allocated.    */
+/*   Intended to be used instead of multiple calls to malloc() when         */
+/*   performance is an issue.                                               */
+/* Parameters:                                                              */
+/*   elemsize (IN):  Size of the basic element to be stored                 */
+/*   elemsperblock (IN):  Number of elements to be stored in a single block */
+/*         of memory.  When the blockheap runs out of free memory, it will  */
+/*         allocate elemsize * elemsperblock more.                          */
+/* Returns:                                                                 */
+/*   Pointer to new BlockHeap, or NULL if unsuccessful                      */
+/* ************************************************************************ */
+BlockHeap *
+BlockHeapCreate(size_t elemsize, int elemsperblock)
+{
+       BlockHeap *bh;
+       s_assert(elemsize > 0 && elemsperblock > 0);
+
+       /* Catch idiotic requests up front */
+       if((elemsize <= 0) || (elemsperblock <= 0))
+       {
+               blockheap_fail("Attempting to BlockHeapCreate idiotic sizes");
+       }
+
+       /* Allocate our new BlockHeap */
+       bh = (BlockHeap *) calloc(1, sizeof(BlockHeap));
+       if(bh == NULL)
+       {
+               blockheap_fail("Attempt to calloc() failed");
+               outofmemory();  /* die.. out of memory */
+       }
+
+       if((elemsize % sizeof(void *)) != 0)
+       {
+               /* Pad to even pointer boundary */
+               elemsize += sizeof(void *);
+               elemsize &= ~(sizeof(void *) - 1);
+       }
+
+       bh->elemSize = elemsize;
+       bh->elemsPerBlock = elemsperblock;
+       bh->blocksAllocated = 0;
+       bh->freeElems = 0;
+       bh->base = NULL;
+
+       /* Be sure our malloc was successful */
+       if(newblock(bh))
+       {
+               if(bh != NULL)
+                       free(bh);
+               libcharybdis_restart("Aiee! -- newblock() failed!!!");
+       }
+
+       if(bh == NULL)
+       {
+               blockheap_fail("bh == NULL when it shouldn't be");
+       }
+       dlinkAdd(bh, &bh->hlist, &heap_lists);
+       return (bh);
+}
+
+/* ************************************************************************ */
+/* FUNCTION DOCUMENTATION:                                                  */
+/*    BlockHeapAlloc                                                        */
+/* Description:                                                             */
+/*    Returns a pointer to a struct within our BlockHeap that's free for    */
+/*    the taking.                                                           */
+/* Parameters:                                                              */
+/*    bh (IN):  Pointer to the Blockheap.                                   */
+/* Returns:                                                                 */
+/*    Pointer to a structure (void *), or NULL if unsuccessful.             */
+/* ************************************************************************ */
+
+void *
+BlockHeapAlloc(BlockHeap * bh)
+{
+       Block *walker;
+       dlink_node *new_node;
+
+       s_assert(bh != NULL);
+       if(bh == NULL)
+       {
+               blockheap_fail("Cannot allocate if bh == NULL");
+       }
+
+       if(bh->freeElems == 0)
+       {
+               /* Allocate new block and assign */
+               /* newblock returns 1 if unsuccessful, 0 if not */
+
+               if(newblock(bh))
+               {
+                       /* That didn't work..try to garbage collect */
+                       BlockHeapGarbageCollect(bh);
+                       if(bh->freeElems == 0)
+                       {
+                               libcharybdis_restart("newblock() failed and garbage collection didn't help");
+                       }
+               }
+       }
+
+       for (walker = bh->base; walker != NULL; walker = walker->next)
+       {
+               if(dlink_list_length(&walker->free_list) > 0)
+               {
+#ifdef DEBUG_BALLOC
+                       bh_sanity_check_block(bh, walker);
+#endif
+                       bh->freeElems--;
+                       new_node = walker->free_list.head;
+                       dlinkMoveNode(new_node, &walker->free_list, &walker->used_list);
+                       s_assert(new_node->data != NULL);
+                       if(new_node->data == NULL)
+                               blockheap_fail("new_node->data is NULL and that shouldn't happen!!!");
+                       memset(new_node->data, 0, bh->elemSize);
+#ifdef DEBUG_BALLOC
+                       do
+                       {
+                               struct MemBlock *memblock = (void *) ((size_t) new_node->data - sizeof(MemBlock));
+                               if(memblock->magic == BALLOC_FREE_MAGIC)
+                                       memblock->magic = BALLOC_MAGIC;
+                       
+                       } while(0);
+                       bh_sanity_check_block(bh, walker);
+#endif
+                       return (new_node->data);
+               }
+       }
+       blockheap_fail("BlockHeapAlloc failed, giving up");
+       return NULL;
+}
+
+
+/* ************************************************************************ */
+/* FUNCTION DOCUMENTATION:                                                  */
+/*    BlockHeapFree                                                         */
+/* Description:                                                             */
+/*    Returns an element to the free pool, does not free()                  */
+/* Parameters:                                                              */
+/*    bh (IN): Pointer to BlockHeap containing element                      */
+/*    ptr (in):  Pointer to element to be "freed"                           */
+/* Returns:                                                                 */
+/*    0 if successful, 1 if element not contained within BlockHeap.         */
+/* ************************************************************************ */
+int
+BlockHeapFree(BlockHeap * bh, void *ptr)
+{
+       Block *block;
+       struct MemBlock *memblock;
+
+       s_assert(bh != NULL);
+       s_assert(ptr != NULL);
+
+       if(bh == NULL)
+       {
+               libcharybdis_restart("balloc.c:BlockHeapFree() bh == NULL");
+               return (1);
+       }
+
+       if(ptr == NULL)
+       {
+               libcharybdis_restart("balloc.BlockHeapFree() ptr == NULL");
+               return (1);
+       }
+
+       memblock = (void *) ((size_t) ptr - sizeof(MemBlock));
+#ifdef DEBUG_BALLOC
+       if(memblock->magic == BALLOC_FREE_MAGIC)
+       {
+               blockheap_fail("double free of a block");
+               outofmemory();
+       } else 
+       if(memblock->magic != BALLOC_MAGIC)
+       {
+               blockheap_fail("memblock->magic != BALLOC_MAGIC");
+               outofmemory();
+       }
+#endif
+       s_assert(memblock->block != NULL);
+       if(memblock->block == NULL)
+       {
+               blockheap_fail("memblock->block == NULL, not a valid block?");
+               outofmemory();
+       }
+
+       block = memblock->block;
+#ifdef DEBUG_BALLOC
+       bh_sanity_check_block(bh, block);
+#endif
+       bh->freeElems++;
+       mem_frob(ptr, bh->elemSize);
+       dlinkMoveNode(&memblock->self, &block->used_list, &block->free_list);
+#ifdef DEBUG_BALLOC
+       bh_sanity_check_block(bh, block);
+#endif
+       return (0);
+}
+
+/* ************************************************************************ */
+/* FUNCTION DOCUMENTATION:                                                  */
+/*    BlockHeapGarbageCollect                                               */
+/* Description:                                                             */
+/*    Performs garbage collection on the block heap.  Any blocks that are   */
+/*    completely unallocated are removed from the heap.  Garbage collection */
+/*    will never remove the root node of the heap.                          */
+/* Parameters:                                                              */
+/*    bh (IN):  Pointer to the BlockHeap to be cleaned up                   */
+/* Returns:                                                                 */
+/*   0 if successful, 1 if bh == NULL                                       */
+/* ************************************************************************ */
+static int
+BlockHeapGarbageCollect(BlockHeap * bh)
+{
+       Block *walker, *last;
+       if(bh == NULL)
+       {
+               return (1);
+       }
+
+       if(bh->freeElems < bh->elemsPerBlock || bh->blocksAllocated == 1)
+       {
+               /* There couldn't possibly be an entire free block.  Return. */
+               return (0);
+       }
+
+       last = NULL;
+       walker = bh->base;
+
+       while (walker != NULL)
+       {
+               if((dlink_list_length(&walker->free_list) == bh->elemsPerBlock) != 0)
+               {
+                       free_block(walker->elems, walker->alloc_size);
+                       if(last != NULL)
+                       {
+                               last->next = walker->next;
+                               if(walker != NULL)
+                                       free(walker);
+                               walker = last->next;
+                       }
+                       else
+                       {
+                               bh->base = walker->next;
+                               if(walker != NULL)
+                                       free(walker);
+                               walker = bh->base;
+                       }
+                       bh->blocksAllocated--;
+                       bh->freeElems -= bh->elemsPerBlock;
+               }
+               else
+               {
+                       last = walker;
+                       walker = walker->next;
+               }
+       }
+       return (0);
+}
+
+/* ************************************************************************ */
+/* FUNCTION DOCUMENTATION:                                                  */
+/*    BlockHeapDestroy                                                      */
+/* Description:                                                             */
+/*    Completely free()s a BlockHeap.  Use for cleanup.                     */
+/* Parameters:                                                              */
+/*    bh (IN):  Pointer to the BlockHeap to be destroyed.                   */
+/* Returns:                                                                 */
+/*   0 if successful, 1 if bh == NULL                                       */
+/* ************************************************************************ */
+int
+BlockHeapDestroy(BlockHeap * bh)
+{
+       Block *walker, *next;
+
+       if(bh == NULL)
+       {
+               return (1);
+       }
+
+       for (walker = bh->base; walker != NULL; walker = next)
+       {
+               next = walker->next;
+               free_block(walker->elems, walker->alloc_size);
+               if(walker != NULL)
+                       free(walker);
+       }
+       dlinkDelete(&bh->hlist, &heap_lists);
+       free(bh);
+       return (0);
+}
+
+void
+BlockHeapUsage(BlockHeap * bh, size_t * bused, size_t * bfree, size_t * bmemusage)
+{
+       size_t used;
+       size_t freem;
+       size_t memusage;
+       if(bh == NULL)
+       {
+               return;
+       }
+
+       freem = bh->freeElems;
+       used = (bh->blocksAllocated * bh->elemsPerBlock) - bh->freeElems;
+       memusage = used * (bh->elemSize + sizeof(MemBlock));
+
+       if(bused != NULL)
+               *bused = used;
+       if(bfree != NULL)
+               *bfree = freem;
+       if(bmemusage != NULL)
+               *bmemusage = memusage;
+}
+
+#endif /* NOBALLOC */
+
diff --git a/libcharybdis/balloc.h b/libcharybdis/balloc.h
new file mode 100644 (file)
index 0000000..32fb066
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  balloc.h: The ircd block allocator header.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: balloc.h 1781 2006-07-30 18:07:38Z jilles $
+ */
+
+#ifndef INCLUDED_blalloc_h
+#define INCLUDED_blalloc_h
+
+#include "setup.h"
+#include "tools.h"
+#include "memory.h"
+#include "ircd_defs.h"
+
+#define CACHEFILE_HEAP_SIZE    32
+#define CACHELINE_HEAP_SIZE    64
+
+
+#ifdef NOBALLOC 
+        
+typedef struct BlockHeap BlockHeap;     
+#define initBlockHeap()         
+#define BlockHeapGarbageCollect(x)      
+#define BlockHeapCreate(es, epb) ((BlockHeap*)(es))     
+#define BlockHeapDestroy(x)     
+#define BlockHeapAlloc(x) MyMalloc((int)x)      
+#define BlockHeapFree(x,y) MyFree(y)    
+#define BlockHeapUsage(bh, bused, bfree, bmemusage) do { if (bused) (*(size_t *)bused) = 0; if (bfree) *((size_t *)bfree) = 0; if (bmemusage) *((size_t *)bmemusage) = 0; } while(0)
+typedef struct MemBlock
+{
+       void *dummy;
+} MemBlock;
+#else
+
+#undef DEBUG_BALLOC
+
+#ifdef DEBUG_BALLOC
+#define BALLOC_MAGIC 0x3d3a3c3d
+#define BALLOC_FREE_MAGIC 0xafafafaf
+#endif
+
+/* status information for an allocated block in heap */
+struct Block
+{
+       size_t alloc_size;
+       struct Block *next;     /* Next in our chain of blocks */
+       void *elems;            /* Points to allocated memory */
+       dlink_list free_list;
+       dlink_list used_list;
+};
+typedef struct Block Block;
+
+struct MemBlock
+{
+#ifdef DEBUG_BALLOC
+       unsigned long magic;
+#endif
+       dlink_node self;
+       Block *block;           /* Which block we belong to */
+};
+
+typedef struct MemBlock MemBlock;
+
+/* information for the root node of the heap */
+struct BlockHeap
+{
+       dlink_node hlist;
+       size_t elemSize;        /* Size of each element to be stored */
+       unsigned long elemsPerBlock;    /* Number of elements per block */
+       unsigned long blocksAllocated;  /* Number of blocks allocated */
+       unsigned long freeElems;                /* Number of free elements */
+       Block *base;            /* Pointer to first block */
+};
+typedef struct BlockHeap BlockHeap;
+
+extern int BlockHeapFree(BlockHeap * bh, void *ptr);
+extern void *BlockHeapAlloc(BlockHeap * bh);
+
+extern BlockHeap *BlockHeapCreate(size_t elemsize, int elemsperblock);
+extern int BlockHeapDestroy(BlockHeap * bh);
+
+extern void initBlockHeap(void);
+extern void BlockHeapUsage(BlockHeap * bh, size_t * bused, size_t * bfree, size_t * bmemusage);
+
+
+
+#endif /* NOBALLOC */
+
+
+
+#endif /* INCLUDED_blalloc_h */
diff --git a/libcharybdis/commio.c b/libcharybdis/commio.c
new file mode 100644 (file)
index 0000000..1813d20
--- /dev/null
@@ -0,0 +1,790 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  commio.c: Network/file related functions
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: commio.c 1779 2006-07-30 16:36:39Z jilles $
+ */
+
+#include "libcharybdis.h"
+
+#ifndef IN_LOOPBACKNET
+#define IN_LOOPBACKNET        0x7f
+#endif
+
+#ifndef INADDR_NONE
+#define INADDR_NONE ((unsigned int) 0xffffffff)
+#endif
+
+const char *const NONB_ERROR_MSG = "set_non_blocking failed for %s:%s";
+const char *const SETBUF_ERROR_MSG = "set_sock_buffers failed for server %s:%s";
+
+static const char *comm_err_str[] = { "Comm OK", "Error during bind()",
+       "Error during DNS lookup", "connect timeout",
+       "Error during connect()",
+       "Comm Error"
+};
+
+fde_t *fd_table = NULL;
+
+static void fdlist_update_biggest(int fd, int opening);
+
+/* Highest FD and number of open FDs .. */
+int highest_fd = -1;           /* Its -1 because we haven't started yet -- adrian */
+int number_fd = 0;
+
+static void comm_connect_callback(int fd, int status);
+static PF comm_connect_timeout;
+static void comm_connect_dns_callback(void *vptr, struct DNSReply *reply);
+static PF comm_connect_tryconnect;
+
+/* 32bit solaris is kinda slow and stdio only supports fds < 256
+ * so we got to do this crap below.
+ * (BTW Fuck you Sun, I hate your guts and I hope you go bankrupt soon)
+ */
+#if defined (__SVR4) && defined (__sun) 
+static void comm_fd_hack(int *fd)
+{
+       int newfd;
+       if(*fd > 256 || *fd < 0)
+               return;
+       if((newfd = fcntl(*fd, F_DUPFD, 256)) != -1)
+       {
+               close(*fd);
+               *fd = newfd;
+       } 
+       return;
+}
+#else
+#define comm_fd_hack(fd) 
+#endif
+
+
+/* close_all_connections() can be used *before* the system come up! */
+
+void
+comm_close_all(void)
+{
+       int i;
+#ifndef NDEBUG
+       int fd;
+#endif
+
+       /* XXX someone tell me why we care about 4 fd's ? */
+       /* XXX btw, fd 3 is used for profiler ! */
+
+       for (i = 4; i < MAXCONNECTIONS; ++i)
+       {
+               if(fd_table[i].flags.open)
+                       comm_close(i);
+               else
+                       close(i);
+       }
+
+       /* XXX should his hack be done in all cases? */
+#ifndef NDEBUG
+       /* fugly hack to reserve fd == 2 */
+       (void) close(2);
+       fd = open("stderr.log", O_WRONLY | O_CREAT | O_APPEND, 0644);
+       if(fd >= 0)
+       {
+               dup2(fd, 2);
+               close(fd);
+       }
+#endif
+}
+
+/*
+ * get_sockerr - get the error value from the socket or the current errno
+ *
+ * Get the *real* error from the socket (well try to anyway..).
+ * This may only work when SO_DEBUG is enabled but its worth the
+ * gamble anyway.
+ */
+int
+comm_get_sockerr(int fd)
+{
+       int errtmp = errno;
+#ifdef SO_ERROR
+       int err = 0;
+       socklen_t len = sizeof(err);
+
+       if(-1 < fd && !getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *) &err, (socklen_t *) & len))
+       {
+               if(err)
+                       errtmp = err;
+       }
+       errno = errtmp;
+#endif
+       return errtmp;
+}
+
+/*
+ * set_sock_buffers - set send and receive buffers for socket
+ * 
+ * inputs      - fd file descriptor
+ *             - size to set
+ * output       - returns true (1) if successful, false (0) otherwise
+ * side effects -
+ */
+int
+comm_set_buffers(int fd, int size)
+{
+       if(setsockopt
+          (fd, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof(size))
+          || setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *) &size, sizeof(size)))
+               return 0;
+       return 1;
+}
+
+/*
+ * set_non_blocking - Set the client connection into non-blocking mode. 
+ *
+ * inputs      - fd to set into non blocking mode
+ * output      - 1 if successful 0 if not
+ * side effects - use POSIX compliant non blocking and
+ *                be done with it.
+ */
+int
+comm_set_nb(int fd)
+{
+       int nonb = 0;
+       int res;
+
+       nonb |= O_NONBLOCK;
+       res = fcntl(fd, F_GETFL, 0);
+       if(-1 == res || fcntl(fd, F_SETFL, res | nonb) == -1)
+               return 0;
+
+       fd_table[fd].flags.nonblocking = 1;
+       return 1;
+}
+
+
+/*
+ * stolen from squid - its a neat (but overused! :) routine which we
+ * can use to see whether we can ignore this errno or not. It is
+ * generally useful for non-blocking network IO related errnos.
+ *     -- adrian
+ */
+int
+ignoreErrno(int ierrno)
+{
+       switch (ierrno)
+       {
+       case EINPROGRESS:
+       case EWOULDBLOCK:
+#if EAGAIN != EWOULDBLOCK
+       case EAGAIN:
+#endif
+       case EALREADY:
+       case EINTR:
+#ifdef ERESTART
+       case ERESTART:
+#endif
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+
+/*
+ * comm_settimeout() - set the socket timeout
+ *
+ * Set the timeout for the fd
+ */
+void
+comm_settimeout(int fd, time_t timeout, PF * callback, void *cbdata)
+{
+       fde_t *F;
+       s_assert(fd >= 0);
+       F = &fd_table[fd];
+       s_assert(F->flags.open);
+
+       F->timeout = CurrentTime + (timeout / 1000);
+       F->timeout_handler = callback;
+       F->timeout_data = cbdata;
+}
+
+
+/*
+ * comm_setflush() - set a flush function
+ *
+ * A flush function is simply a function called if found during
+ * comm_timeouts(). Its basically a second timeout, except in this case
+ * I'm too lazy to implement multiple timeout functions! :-)
+ * its kinda nice to have it seperate, since this is designed for
+ * flush functions, and when comm_close() is implemented correctly
+ * with close functions, we _actually_ don't call comm_close() here ..
+ */
+void
+comm_setflush(int fd, time_t timeout, PF * callback, void *cbdata)
+{
+       fde_t *F;
+       s_assert(fd >= 0);
+       F = &fd_table[fd];
+       s_assert(F->flags.open);
+
+       F->flush_timeout = CurrentTime + (timeout / 1000);
+       F->flush_handler = callback;
+       F->flush_data = cbdata;
+}
+
+
+/*
+ * comm_checktimeouts() - check the socket timeouts
+ *
+ * All this routine does is call the given callback/cbdata, without closing
+ * down the file descriptor. When close handlers have been implemented,
+ * this will happen.
+ */
+void
+comm_checktimeouts(void *notused)
+{
+       int fd;
+       PF *hdl;
+       void *data;
+       fde_t *F;
+       for (fd = 0; fd <= highest_fd; fd++)
+       {
+               F = &fd_table[fd];
+               if(!F->flags.open)
+                       continue;
+               if(F->flags.closing)
+                       continue;
+
+               /* check flush functions */
+               if(F->flush_handler &&
+                  F->flush_timeout > 0 && F->flush_timeout < CurrentTime)
+               {
+                       hdl = F->flush_handler;
+                       data = F->flush_data;
+                       comm_setflush(F->fd, 0, NULL, NULL);
+                       hdl(F->fd, data);
+               }
+
+               /* check timeouts */
+               if(F->timeout_handler &&
+                  F->timeout > 0 && F->timeout < CurrentTime)
+               {
+                       /* Call timeout handler */
+                       hdl = F->timeout_handler;
+                       data = F->timeout_data;
+                       comm_settimeout(F->fd, 0, NULL, NULL);
+                       hdl(F->fd, data);
+               }
+       }
+}
+
+/*
+ * void comm_connect_tcp(int fd, const char *host, u_short port,
+ *                       struct sockaddr *clocal, int socklen,
+ *                       CNCB *callback, void *data, int aftype, int timeout)
+ * Input: An fd to connect with, a host and port to connect to,
+ *        a local sockaddr to connect from + length(or NULL to use the
+ *        default), a callback, the data to pass into the callback, the
+ *        address family.
+ * Output: None.
+ * Side-effects: A non-blocking connection to the host is started, and
+ *               if necessary, set up for selection. The callback given
+ *               may be called now, or it may be called later.
+ */
+void
+comm_connect_tcp(int fd, const char *host, u_short port,
+                struct sockaddr *clocal, int socklen, CNCB * callback,
+                void *data, int aftype, int timeout)
+{
+       void *ipptr = NULL;
+       fde_t *F;
+       s_assert(fd >= 0);
+       F = &fd_table[fd];
+       F->flags.called_connect = 1;
+       s_assert(callback);
+       F->connect.callback = callback;
+       F->connect.data = data;
+
+       memset(&F->connect.hostaddr, 0, sizeof(F->connect.hostaddr));
+#ifdef IPV6
+       if(aftype == AF_INET6)
+       {
+               struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&F->connect.hostaddr;
+               SET_SS_LEN(F->connect.hostaddr, sizeof(struct sockaddr_in6));
+               in6->sin6_port = htons(port);
+               in6->sin6_family = AF_INET6;
+               ipptr = &in6->sin6_addr;
+       } else
+#endif
+       {
+               struct sockaddr_in *in = (struct sockaddr_in *)&F->connect.hostaddr;
+               SET_SS_LEN(F->connect.hostaddr, sizeof(struct sockaddr_in));
+               in->sin_port = htons(port);
+               in->sin_family = AF_INET;
+               ipptr = &in->sin_addr;
+       }
+
+       /* Note that we're using a passed sockaddr here. This is because
+        * generally you'll be bind()ing to a sockaddr grabbed from
+        * getsockname(), so this makes things easier.
+        * XXX If NULL is passed as local, we should later on bind() to the
+        * virtual host IP, for completeness.
+        *   -- adrian
+        */
+       if((clocal != NULL) && (bind(F->fd, clocal, socklen) < 0))
+       {
+               /* Failure, call the callback with COMM_ERR_BIND */
+               comm_connect_callback(F->fd, COMM_ERR_BIND);
+               /* ... and quit */
+               return;
+       }
+
+       /* Next, if we have been given an IP, get the addr and skip the
+        * DNS check (and head direct to comm_connect_tryconnect().
+        */
+       if(inetpton(aftype, host, ipptr) <= 0)
+       {
+               /* Send the DNS request, for the next level */
+               F->dns_query = MyMalloc(sizeof(struct DNSQuery));
+               F->dns_query->ptr = F;
+               F->dns_query->callback = comm_connect_dns_callback;
+#ifdef IPV6
+               if (aftype == AF_INET6)
+                       gethost_byname_type(host, F->dns_query, T_AAAA);
+               else
+#endif
+                       gethost_byname_type(host, F->dns_query, T_A);
+       }
+       else
+       {
+               /* We have a valid IP, so we just call tryconnect */
+               /* Make sure we actually set the timeout here .. */
+               comm_settimeout(F->fd, timeout * 1000, comm_connect_timeout, NULL);
+               comm_connect_tryconnect(F->fd, NULL);
+       }
+}
+
+/*
+ * comm_connect_callback() - call the callback, and continue with life
+ */
+static void
+comm_connect_callback(int fd, int status)
+{
+       CNCB *hdl;
+       fde_t *F = &fd_table[fd];
+       /* This check is gross..but probably necessary */
+       if(F->connect.callback == NULL)
+               return;
+       /* Clear the connect flag + handler */
+       hdl = F->connect.callback;
+       F->connect.callback = NULL;
+       F->flags.called_connect = 0;
+
+       /* Clear the timeout handler */
+       comm_settimeout(F->fd, 0, NULL, NULL);
+
+       /* Call the handler */
+       hdl(F->fd, status, F->connect.data);
+}
+
+
+/*
+ * comm_connect_timeout() - this gets called when the socket connection
+ * times out. This *only* can be called once connect() is initially
+ * called ..
+ */
+static void
+comm_connect_timeout(int fd, void *notused)
+{
+       /* error! */
+       comm_connect_callback(fd, COMM_ERR_TIMEOUT);
+}
+
+
+/*
+ * comm_connect_dns_callback() - called at the completion of the DNS request
+ *
+ * The DNS request has completed, so if we've got an error, return it,
+ * otherwise we initiate the connect()
+ */
+static void
+comm_connect_dns_callback(void *vptr, struct DNSReply *reply)
+{
+       fde_t *F = vptr;
+
+       /* Free dns_query now to avoid double reslist free -- jilles */
+       MyFree(F->dns_query);
+       F->dns_query = NULL;
+
+       if(!reply)
+       {
+               comm_connect_callback(F->fd, COMM_ERR_DNS);
+               return;
+       }
+
+       /* No error, set a 10 second timeout */
+       comm_settimeout(F->fd, 30 * 1000, comm_connect_timeout, NULL);
+
+       /* Copy over the DNS reply info so we can use it in the connect() */
+#ifdef IPV6
+       if(reply->addr.ss_family == AF_INET6)
+       {
+               struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&F->connect.hostaddr;
+               memcpy(&in6->sin6_addr, &((struct sockaddr_in6 *)&reply->addr)->sin6_addr, sizeof(struct in6_addr));
+       }
+       else
+#endif
+       {
+               struct sockaddr_in *in = (struct sockaddr_in *)&F->connect.hostaddr;
+               in->sin_addr.s_addr = ((struct sockaddr_in *)&reply->addr)->sin_addr.s_addr;
+       }
+
+       /* Now, call the tryconnect() routine to try a connect() */
+       comm_connect_tryconnect(F->fd, NULL);
+}
+
+
+/* static void comm_connect_tryconnect(int fd, void *notused)
+ * Input: The fd, the handler data(unused).
+ * Output: None.
+ * Side-effects: Try and connect with pending connect data for the FD. If
+ *               we succeed or get a fatal error, call the callback.
+ *               Otherwise, it is still blocking or something, so register
+ *               to select for a write event on this FD.
+ */
+static void
+comm_connect_tryconnect(int fd, void *notused)
+{
+       int retval;
+       fde_t *F = &fd_table[fd];
+
+       if(F->connect.callback == NULL)
+               return;
+       /* Try the connect() */
+       retval = connect(fd, (struct sockaddr *) &fd_table[fd].connect.hostaddr, 
+                              GET_SS_LEN(fd_table[fd].connect.hostaddr));
+       /* Error? */
+       if(retval < 0)
+       {
+               /*
+                * If we get EISCONN, then we've already connect()ed the socket,
+                * which is a good thing.
+                *   -- adrian
+                */
+               if(errno == EISCONN)
+                       comm_connect_callback(F->fd, COMM_OK);
+               else if(ignoreErrno(errno))
+                       /* Ignore error? Reschedule */
+                       comm_setselect(F->fd, FDLIST_SERVER, COMM_SELECT_WRITE|COMM_SELECT_RETRY,
+                                      comm_connect_tryconnect, NULL, 0);
+               else
+                       /* Error? Fail with COMM_ERR_CONNECT */
+                       comm_connect_callback(F->fd, COMM_ERR_CONNECT);
+               return;
+       }
+       /* If we get here, we've suceeded, so call with COMM_OK */
+       comm_connect_callback(F->fd, COMM_OK);
+}
+
+/*
+ * comm_error_str() - return an error string for the given error condition
+ */
+const char *
+comm_errstr(int error)
+{
+       if(error < 0 || error >= COMM_ERR_MAX)
+               return "Invalid error number!";
+       return comm_err_str[error];
+}
+
+
+/*
+ * comm_socket() - open a socket
+ *
+ * This is a highly highly cut down version of squid's comm_open() which
+ * for the most part emulates socket(), *EXCEPT* it fails if we're about
+ * to run out of file descriptors.
+ */
+int
+comm_socket(int family, int sock_type, int proto, const char *note)
+{
+       int fd;
+       /* First, make sure we aren't going to run out of file descriptors */
+       if(number_fd >= MASTER_MAX)
+       {
+               errno = ENFILE;
+               return -1;
+       }
+
+       /*
+        * Next, we try to open the socket. We *should* drop the reserved FD
+        * limit if/when we get an error, but we can deal with that later.
+        * XXX !!! -- adrian
+        */
+       fd = socket(family, sock_type, proto);
+       comm_fd_hack(&fd);
+       if(fd < 0)
+               return -1;      /* errno will be passed through, yay.. */
+
+#if defined(IPV6) && defined(IPV6_V6ONLY)
+       /* 
+        * Make sure we can take both IPv4 and IPv6 connections
+        * on an AF_INET6 socket
+        */
+       if(family == AF_INET6)
+       {
+               int off = 1;
+               if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off)) == -1)
+               {
+                       libcharybdis_log("comm_socket: Could not set IPV6_V6ONLY option to 1 on FD %d: %s",
+                            fd, strerror(errno));
+                       close(fd);
+                       return -1;
+               }
+       }
+#endif
+
+       /* Set the socket non-blocking, and other wonderful bits */
+       if(!comm_set_nb(fd))
+       {
+               libcharybdis_log("comm_open: Couldn't set FD %d non blocking: %s", fd, strerror(errno));
+               close(fd);
+               return -1;
+       }
+
+       /* Next, update things in our fd tracking */
+       comm_open(fd, FD_SOCKET, note);
+       return fd;
+}
+
+
+/*
+ * comm_accept() - accept an incoming connection
+ *
+ * This is a simple wrapper for accept() which enforces FD limits like
+ * comm_open() does.
+ */
+int
+comm_accept(int fd, struct sockaddr *pn, socklen_t *addrlen)
+{
+       int newfd;
+       if(number_fd >= MASTER_MAX)
+       {
+               errno = ENFILE;
+               return -1;
+       }
+
+       /*
+        * Next, do the accept(). if we get an error, we should drop the
+        * reserved fd limit, but we can deal with that when comm_open()
+        * also does it. XXX -- adrian
+        */
+       newfd = accept(fd, (struct sockaddr *) pn, addrlen);
+        comm_fd_hack(&newfd);
+                        
+       if(newfd < 0)
+               return -1;
+
+       /* Set the socket non-blocking, and other wonderful bits */
+       if(!comm_set_nb(newfd))
+       {
+               libcharybdis_log("comm_accept: Couldn't set FD %d non blocking!", newfd);
+               close(newfd);
+               return -1;
+       }
+
+       /* Next, tag the FD as an incoming connection */
+       comm_open(newfd, FD_SOCKET, "Incoming connection");
+
+       /* .. and return */
+       return newfd;
+}
+
+/*
+ * If a sockaddr_storage is AF_INET6 but is a mapped IPv4
+ * socket manged the sockaddr.
+ */
+#ifndef mangle_mapped_sockaddr
+void
+mangle_mapped_sockaddr(struct sockaddr *in)
+{
+       struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)in;                                                           
+
+       if(in->sa_family == AF_INET)
+               return;
+
+       if(in->sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&in6->sin6_addr))
+       {
+               struct sockaddr_in in4;
+               memset(&in4, 0, sizeof(struct sockaddr_in));
+               in4.sin_family = AF_INET;
+               in4.sin_port = in6->sin6_port;
+               in4.sin_addr.s_addr = ((uint32_t *)&in6->sin6_addr)[3];
+               memcpy(in, &in4, sizeof(struct sockaddr_in));           
+       }       
+       return;
+}
+#endif
+
+
+static void
+fdlist_update_biggest(int fd, int opening)
+{
+       if(fd < highest_fd)
+               return;
+       s_assert(fd < MAXCONNECTIONS);
+
+       if(fd > highest_fd)
+       {
+               /*  
+                * s_assert that we are not closing a FD bigger than
+                * our known biggest FD
+                */
+               s_assert(opening);
+               highest_fd = fd;
+               return;
+       }
+       /* if we are here, then fd == Biggest_FD */
+       /*
+        * s_assert that we are closing the biggest FD; we can't be
+        * re-opening it
+        */
+       s_assert(!opening);
+       while (highest_fd >= 0 && !fd_table[highest_fd].flags.open)
+               highest_fd--;
+}
+
+
+void
+fdlist_init(void)
+{
+       static int initialized = 0;
+
+       if(!initialized)
+       {
+               /* Since we're doing this once .. */
+               fd_table = MyMalloc((MAXCONNECTIONS + 1) * sizeof(fde_t));
+               initialized = 1;
+       }
+}
+
+/* Called to open a given filedescriptor */
+void
+comm_open(int fd, unsigned int type, const char *desc)
+{
+       fde_t *F = &fd_table[fd];
+       s_assert(fd >= 0);
+
+       if(F->flags.open)
+       {
+               comm_close(fd);
+       }
+       s_assert(!F->flags.open);
+       F->fd = fd;
+       F->type = type;
+       F->flags.open = 1;
+#ifdef NOTYET
+       F->defer.until = 0;
+       F->defer.n = 0;
+       F->defer.handler = NULL;
+#endif
+       fdlist_update_biggest(fd, 1);
+       F->comm_index = -1;
+       F->list = FDLIST_NONE;
+       if(desc)
+               strlcpy(F->desc, desc, sizeof(F->desc));
+       number_fd++;
+}
+
+
+/* Called to close a given filedescriptor */
+void
+comm_close(int fd)
+{
+       fde_t *F = &fd_table[fd];
+       s_assert(F->flags.open);
+       /* All disk fd's MUST go through file_close() ! */
+       s_assert(F->type != FD_FILE);
+       if(F->type == FD_FILE)
+       {
+               s_assert(F->read_handler == NULL);
+               s_assert(F->write_handler == NULL);
+       }
+       comm_setselect(F->fd, FDLIST_NONE, COMM_SELECT_WRITE | COMM_SELECT_READ, NULL, NULL, 0);
+       comm_setflush(F->fd, 0, NULL, NULL);
+       
+       if (F->dns_query != NULL)
+       {
+               delete_resolver_queries(F->dns_query);
+               MyFree(F->dns_query);
+               F->dns_query = NULL;
+       }
+       
+       F->flags.open = 0;
+       fdlist_update_biggest(fd, 0);
+       number_fd--;
+       memset(F, '\0', sizeof(fde_t));
+       F->timeout = 0;
+       /* Unlike squid, we're actually closing the FD here! -- adrian */
+       close(fd);
+}
+
+
+/*
+ * comm_dump() - dump the list of active filedescriptors
+ */
+void
+comm_dump(struct Client *source_p)
+{
+       int i;
+
+       for (i = 0; i <= highest_fd; i++)
+       {
+               if(!fd_table[i].flags.open)
+                       continue;
+
+               sendto_one_numeric(source_p, RPL_STATSDEBUG, 
+                                  "F :fd %-3d desc '%s'",
+                                  i, fd_table[i].desc);
+       }
+}
+
+/*
+ * comm_note() - set the fd note
+ *
+ * Note: must be careful not to overflow fd_table[fd].desc when
+ *       calling.
+ */
+void
+comm_note(int fd, const char *format, ...)
+{
+       va_list args;
+
+       if(format)
+       {
+               va_start(args, format);
+               ircvsnprintf(fd_table[fd].desc, FD_DESC_SZ, format, args);
+               va_end(args);
+       }
+       else
+               fd_table[fd].desc[0] = '\0';
+}
+
+
diff --git a/libcharybdis/commio.h b/libcharybdis/commio.h
new file mode 100644 (file)
index 0000000..49aec91
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  commio.h: A header for the network subsystem.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: commio.h 1757 2006-07-25 23:34:45Z jilles $
+ */
+
+#ifndef INCLUDED_commio_h
+#define INCLUDED_commio_h
+
+#include "setup.h"
+#include "config.h"
+#include "ircd_defs.h"
+
+/* Callback for completed IO events */
+typedef void PF(int fd, void *);
+
+/* Callback for completed connections */
+/* int fd, int status, void * */
+typedef void CNCB(int fd, int, void *);
+
+#define FD_DESC_SZ 128         /* hostlen + comment */
+
+
+/* FD type values */
+enum
+{
+       FD_NONE,
+       FD_LOG,
+       FD_FILE,
+       FD_FILECLOSE,
+       FD_SOCKET,
+       FD_PIPE,
+       FD_UNKNOWN
+};
+
+enum
+{
+       COMM_OK,
+       COMM_ERR_BIND,
+       COMM_ERR_DNS,
+       COMM_ERR_TIMEOUT,
+       COMM_ERR_CONNECT,
+       COMM_ERROR,
+       COMM_ERR_MAX
+};
+
+typedef enum fdlist_t
+{
+       FDLIST_NONE,
+       FDLIST_SERVICE,
+       FDLIST_SERVER,
+       FDLIST_IDLECLIENT,
+       FDLIST_BUSYCLIENT,
+       FDLIST_MAX
+}
+fdlist_t;
+
+typedef struct _fde fde_t;
+
+
+extern int highest_fd;
+extern int number_fd;
+
+struct Client;
+
+struct _fde
+{
+       /* New-school stuff, again pretty much ripped from squid */
+       /*
+        * Yes, this gives us only one pending read and one pending write per
+        * filedescriptor. Think though: when do you think we'll need more?
+        */
+       int fd;                 /* So we can use the fde_t as a callback ptr */
+       int type;
+       fdlist_t list;          /* Which list this FD should sit on */
+       int comm_index;         /* where in the poll list we live */
+       char desc[FD_DESC_SZ];
+       PF *read_handler;
+       void *read_data;
+       PF *write_handler;
+       void *write_data;
+       PF *timeout_handler;
+       void *timeout_data;
+       time_t timeout;
+       PF *flush_handler;
+       void *flush_data;
+       time_t flush_timeout;
+       struct DNSQuery *dns_query;
+       struct
+       {
+               unsigned int open:1;
+               unsigned int close_request:1;
+               unsigned int write_daemon:1;
+               unsigned int closing:1;
+               unsigned int socket_eof:1;
+               unsigned int nolinger:1;
+               unsigned int nonblocking:1;
+               unsigned int ipc:1;
+               unsigned int called_connect:1;
+       }
+       flags;
+       struct
+       {
+               struct irc_sockaddr_storage hostaddr;
+               CNCB *callback;
+               void *data;
+               /* We'd also add the retry count here when we get to that -- adrian */
+       }
+       connect;
+       int pflags;
+};
+
+
+extern fde_t *fd_table;
+
+void fdlist_init(void);
+
+extern void comm_open(int, unsigned int, const char *);
+extern void comm_close(int);
+extern void comm_dump(struct Client *source_p);
+#ifndef __GNUC__
+extern void comm_note(int fd, const char *format, ...);
+#else
+extern void comm_note(int fd, const char *format, ...) __attribute__ ((format(printf, 2, 3)));
+#endif
+
+#define FB_EOF  0x01
+#define FB_FAIL 0x02
+
+
+/* Size of a read buffer */
+#define READBUF_SIZE    16384  /* used by src/packet.c and src/s_serv.c */
+
+/* Type of IO */
+#define        COMM_SELECT_READ                0x1
+#define        COMM_SELECT_WRITE               0x2
+#define COMM_SELECT_RETRY              0x4
+extern int readcalls;
+extern const char *const NONB_ERROR_MSG;
+extern const char *const SETBUF_ERROR_MSG;
+
+extern void comm_close_all(void);
+extern int comm_set_nb(int);
+extern int comm_set_buffers(int, int);
+
+extern int comm_get_sockerr(int);
+extern int ignoreErrno(int ierrno);
+
+extern void comm_settimeout(int fd, time_t, PF *, void *);
+extern void comm_setflush(int fd, time_t, PF *, void *);
+extern void comm_checktimeouts(void *);
+extern void comm_connect_tcp(int fd, const char *, u_short,
+                            struct sockaddr *, int, CNCB *, void *, int, int);
+extern const char *comm_errstr(int status);
+extern int comm_socket(int family, int sock_type, int proto, const char *note);
+extern int comm_accept(int fd, struct sockaddr *pn, socklen_t *addrlen);
+
+/* These must be defined in the network IO loop code of your choice */
+extern void comm_setselect(int fd, fdlist_t list, unsigned int type,
+                          PF * handler, void *client_data, time_t timeout);
+extern void init_netio(void);
+extern int read_message(time_t, unsigned char);
+extern int comm_select(unsigned long);
+extern int disable_sock_options(int);
+#ifdef IPV6
+extern void mangle_mapped_sockaddr(struct sockaddr *in);
+#else
+#define mangle_mapped_sockaddr(x) 
+#endif
+
+
+#endif /* INCLUDED_commio_h */
diff --git a/libcharybdis/devpoll.c b/libcharybdis/devpoll.c
new file mode 100644 (file)
index 0000000..64d9f08
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  s_bsd_devpoll.c: /dev/poll compatible network routines.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2001 Adrian Chadd <adrian@creative.net.au>
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: devpoll.c 390 2005-12-07 18:46:56Z nenolod $
+ */
+
+#include "config.h"
+
+#include "stdinc.h"
+#include <sys/devpoll.h>
+
+#include "libcharybdis.h"
+
+#define POLL_LENGTH    HARD_FDLIMIT
+
+
+static void devpoll_update_events(int, short, PF *);
+static int dpfd;
+static short fdmask[POLL_LENGTH];
+static void devpoll_update_events(int, short, PF *);
+static void devpoll_write_update(int, int);
+
+/* #define NOTYET 1 */
+
+/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
+/* Private functions */
+
+/*
+ * Write an update to the devpoll filter.
+ * See, we end up having to do a seperate (?) remove before we do an
+ * add of a new polltype, so we have to have this function seperate from
+ * the others.
+ */
+static void
+devpoll_write_update(int fd, int events)
+{
+       struct pollfd pollfds[1];       /* Just to be careful */
+       int retval;
+
+       /* Build the pollfd entry */
+       pollfds[0].revents = 0;
+       pollfds[0].fd = fd;
+       pollfds[0].events = events;
+
+       /* Write the thing to our poll fd */
+       retval = write(dpfd, &pollfds[0], sizeof(struct pollfd));
+       if(retval != sizeof(struct pollfd))
+               libcharybdis_log("devpoll_write_update: dpfd write failed %d: %s", errno, strerror(errno));
+       /* Done! */
+}
+
+void
+devpoll_update_events(int fd, short filter, PF * handler)
+{
+       int update_required = 0;
+       int cur_mask = fdmask[fd];
+       PF *cur_handler;
+       fdmask[fd] = 0;
+       switch (filter)
+       {
+       case COMM_SELECT_READ:
+               cur_handler = fd_table[fd].read_handler;
+               if(handler)
+                       fdmask[fd] |= POLLRDNORM;
+               else
+                       fdmask[fd] &= ~POLLRDNORM;
+               if(fd_table[fd].write_handler)
+                       fdmask[fd] |= POLLWRNORM;
+               break;
+       case COMM_SELECT_WRITE:
+               cur_handler = fd_table[fd].write_handler;
+               if(handler)
+                       fdmask[fd] |= POLLWRNORM;
+               else
+                       fdmask[fd] &= ~POLLWRNORM;
+               if(fd_table[fd].read_handler)
+                       fdmask[fd] |= POLLRDNORM;
+               break;
+       default:
+#ifdef NOTYET
+               libcharybdis_log("devpoll_update_events called with unknown filter: %hd", filter);
+#endif
+               return;
+               break;
+       }
+
+       if(cur_handler == NULL && handler != NULL)
+               update_required++;
+       else if(cur_handler != NULL && handler == NULL)
+               update_required++;
+       if(cur_mask != fdmask[fd])
+               update_required++;
+       if(update_required)
+       {
+               /*
+                * Ok, we can call devpoll_write_update() here now to re-build the
+                * fd struct. If we end up with nothing on this fd, it won't write
+                * anything.
+                */
+               if(fdmask[fd])
+               {
+                       devpoll_write_update(fd, POLLREMOVE);
+                       devpoll_write_update(fd, fdmask[fd]);
+               }
+               else
+                       devpoll_write_update(fd, POLLREMOVE);
+       }
+}
+
+
+
+
+
+/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
+/* Public functions */
+
+
+/*
+ * init_netio
+ *
+ * This is a needed exported function which will be called to initialise
+ * the network loop code.
+ */
+void
+init_netio(void)
+{
+       memset(&fdmask, 0, sizeof(fdmask));
+       dpfd = open("/dev/poll", O_RDWR);
+       if(dpfd < 0)
+       {
+               fprintf(stderr,
+                    "init_netio: Couldn't open /dev/poll - %d: %s\n",
+                    errno, strerror(errno));
+               exit(115);      /* Whee! */
+       }
+}
+
+/*
+ * comm_setselect
+ *
+ * This is a needed exported function which will be called to register
+ * and deregister interest in a pending IO state for a given FD.
+ */
+void
+comm_setselect(int fd, fdlist_t list, unsigned int type, PF * handler,
+              void *client_data, time_t timeout)
+{
+       fde_t *F = &fd_table[fd];
+       s_assert(fd >= 0);
+       s_assert(F->flags.open);
+
+       /* Update the list, even though we're not using it .. */
+       F->list = list;
+
+       if(type & COMM_SELECT_READ)
+       {
+               devpoll_update_events(fd, COMM_SELECT_READ, handler);
+               F->read_handler = handler;
+               F->read_data = client_data;
+       }
+       if(type & COMM_SELECT_WRITE)
+       {
+               devpoll_update_events(fd, COMM_SELECT_WRITE, handler);
+               F->write_handler = handler;
+               F->write_data = client_data;
+       }
+       if(timeout)
+               F->timeout = CurrentTime + (timeout / 1000);
+}
+
+/*
+ * Check all connections for new connections and input data that is to be
+ * processed. Also check for connections with data queued and whether we can
+ * write it out.
+ */
+
+/*
+ * comm_select
+ *
+ * Called to do the new-style IO, courtesy of squid (like most of this
+ * new IO code). This routine handles the stuff we've hidden in
+ * comm_setselect and fd_table[] and calls callbacks for IO ready
+ * events.
+ */
+
+int
+comm_select(unsigned long delay)
+{
+       int num, i;
+       struct pollfd pollfds[POLL_LENGTH];
+       struct dvpoll dopoll;
+
+       do
+       {
+               for (;;)
+               {
+                       dopoll.dp_timeout = delay;
+                       dopoll.dp_nfds = POLL_LENGTH;
+                       dopoll.dp_fds = &pollfds[0];
+                       num = ioctl(dpfd, DP_POLL, &dopoll);
+                       if(num >= 0)
+                               break;
+                       if(ignoreErrno(errno))
+                               break;
+                       set_time();
+                       return COMM_ERROR;
+               }
+
+               set_time();
+               if(num == 0)
+                       continue;
+
+               for (i = 0; i < num; i++)
+               {
+                       int fd = dopoll.dp_fds[i].fd;
+                       PF *hdl = NULL;
+                       fde_t *F = &fd_table[fd];
+                       if((dopoll.dp_fds[i].
+                           revents & (POLLRDNORM | POLLIN | POLLHUP |
+                                      POLLERR))
+                          && (dopoll.dp_fds[i].events & (POLLRDNORM | POLLIN)))
+                       {
+                               if((hdl = F->read_handler) != NULL)
+                               {
+                                       F->read_handler = NULL;
+                                       hdl(fd, F->read_data);
+                                       /*
+                                        * this call used to be with a NULL pointer, BUT
+                                        * in the devpoll case we only want to update the
+                                        * poll set *if* the handler changes state (active ->
+                                        * NULL or vice versa.)
+                                        */
+                                       devpoll_update_events(fd,
+                                                             COMM_SELECT_READ, F->read_handler);
+                               }
+                               else
+                                       libcharybdis_log("comm_select: Unhandled read event: fdmask: %x",
+                                            fdmask[fd]);
+                       }
+
+                       if(F->flags.open == 0)
+                               continue;       /* Read handler closed us..go on to do something more useful */
+                       if((dopoll.dp_fds[i].
+                           revents & (POLLWRNORM | POLLOUT | POLLHUP |
+                                      POLLERR))
+                          && (dopoll.dp_fds[i].events & (POLLWRNORM | POLLOUT)))
+                       {
+                               if((hdl = F->write_handler) != NULL)
+                               {
+                                       F->write_handler = NULL;
+                                       hdl(fd, F->write_data);
+                                       /* See above similar code in the read case */
+                                       devpoll_update_events(fd,
+                                                             COMM_SELECT_WRITE, F->write_handler);
+                               }
+                               else
+                                       libcharybdis_log("comm_select: Unhandled write event: fdmask: %x",
+                                            fdmask[fd]);
+
+                       }
+                       if(dopoll.dp_fds[i].revents & POLLNVAL)
+                       {
+                               libcharybdis_log("revents was Invalid for %d", fd);
+                       }
+               }
+               return COMM_OK;
+       }
+       while (0);
+       /* XXX Get here, we broke! */
+       return 0;
+}
+
diff --git a/libcharybdis/epoll.c b/libcharybdis/epoll.c
new file mode 100644 (file)
index 0000000..4435c51
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  epoll.c: Linux epoll compatible network routines.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2001 Adrian Chadd <adrian@creative.net.au>
+ *  Copyright (C) 2002-2005 ircd-ratbox development team
+ *  Copyright (C) 2002 Aaron Sethman <androsyn@ratbox.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 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: epoll.c 390 2005-12-07 18:46:56Z nenolod $
+ */
+
+#include "config.h"
+#include "stdinc.h"
+#include <sys/epoll.h>
+
+#include "libcharybdis.h"
+
+static int ep;                 /* epoll file descriptor */
+static struct epoll_event *pfd;
+static int pfd_size;
+
+
+#ifndef HAVE_EPOLL_CTL /* bah..glibc doesn't support epoll yet.. */
+#include <sys/epoll.h>
+#include <sys/syscall.h>
+
+_syscall1(int, epoll_create, int, maxfds);
+_syscall4(int, epoll_ctl, int, epfd, int, op, int, fd, struct epoll_event *, events);
+_syscall4(int, epoll_wait, int, epfd, struct epoll_event *, pevents,
+                int, maxevents, int, timeout);
+
+#endif /* HAVE_EPOLL_CTL */
+
+
+/*
+ * init_netio
+ *
+ * This is a needed exported function which will be called to initialise
+ * the network loop code.
+ */
+void
+init_netio(void)
+{
+       pfd_size = getdtablesize();
+       ep = epoll_create(pfd_size);
+       pfd = MyMalloc(sizeof(struct epoll_event) * pfd_size);
+       if(ep < 0)
+       {
+               fprintf(stderr, "init_netio: Couldn't open epoll fd!\n");
+               exit(115);      /* Whee! */
+       }
+       comm_note(ep, "epoll file descriptor");
+}
+
+/*
+ * comm_setselect
+ *
+ * This is a needed exported function which will be called to register
+ * and deregister interest in a pending IO state for a given FD.
+ */
+void
+comm_setselect(int fd, fdlist_t list, unsigned int type, PF * handler,
+              void *client_data, time_t timeout)
+{
+       struct epoll_event ep_event;
+       fde_t *F = &fd_table[fd];
+       int old_flags = F->pflags;
+       int op = -1;
+       
+       s_assert(fd >= 0);
+       s_assert(F->flags.open);
+       
+       /* Update the list, even though we're not using it .. */
+       F->list = list;
+       if(type & COMM_SELECT_READ)
+       {
+               if(handler != NULL)
+                       F->pflags |= EPOLLIN;
+               else
+                       F->pflags &= ~EPOLLIN;
+               F->read_handler = handler;
+               F->read_data = client_data;
+       }
+
+       if(type & COMM_SELECT_WRITE)
+       {
+               if(handler != NULL)
+                       F->pflags |= EPOLLOUT;
+               else
+                       F->pflags &= ~EPOLLOUT;
+               F->write_handler = handler;
+               F->write_data = client_data;
+       }
+
+       if(timeout)
+               F->timeout = CurrentTime + (timeout / 1000);
+
+       if(old_flags == 0 && F->pflags == 0)
+               return;
+       else if(F->pflags <= 0)
+               op = EPOLL_CTL_DEL;
+       else if(old_flags == 0 && F->pflags > 0)
+               op = EPOLL_CTL_ADD;
+       else if(F->pflags != old_flags)
+               op = EPOLL_CTL_MOD;
+
+       if(op == -1)
+               return;
+
+
+       ep_event.events = F->pflags;
+       ep_event.data.ptr = F;
+
+       if(epoll_ctl(ep, op, fd, &ep_event) != 0)
+       {
+               libcharybdis_log("comm_setselect(): epoll_ctl failed: %s", strerror(errno));
+               abort();
+       }
+
+
+}
+
+/*
+ * comm_select
+ *
+ * Called to do the new-style IO, courtesy of squid (like most of this
+ * new IO code). This routine handles the stuff we've hidden in
+ * comm_setselect and fd_table[] and calls callbacks for IO ready
+ * events.
+ */
+
+int
+comm_select(unsigned long delay)
+{
+       int num, i, flags, old_flags, op;
+       struct epoll_event ep_event;
+       void *data;
+
+       num = epoll_wait(ep, pfd, pfd_size, delay);
+       set_time();
+       if(num < 0 && !ignoreErrno(errno))
+       {
+               return COMM_ERROR;
+       }
+
+       if(num == 0)
+               return COMM_OK;
+       for (i = 0; i < num; i++)
+       {
+               PF *hdl;
+               fde_t *F = pfd[i].data.ptr;
+               old_flags = F->pflags;
+               if(pfd[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR))
+               {
+                       hdl = F->read_handler;
+                       data = F->read_data;
+                       F->read_handler = NULL;
+                       F->read_data = NULL;
+                       if(hdl) {
+                               hdl(F->fd, data);
+                       }
+                       else
+                               libcharybdis_log("epoll.c: NULL read handler called");
+
+               }
+
+
+               if(F->flags.open == 0)
+                       continue;
+               if(pfd[i].events & (EPOLLOUT | EPOLLHUP | EPOLLERR))
+               {
+                       hdl = F->write_handler;
+                       data = F->write_data;
+                       F->write_handler = NULL;
+                       F->write_data = NULL;
+
+                       if(hdl) {
+                               hdl(F->fd, data);
+                       }
+                       else
+                               libcharybdis_log("epoll.c: NULL write handler called");
+               }
+               
+               if(F->flags.open == 0)
+                       continue;               
+               
+               flags = 0;
+               
+               if(F->read_handler != NULL)
+                       flags |= EPOLLIN;
+               if(F->write_handler != NULL)
+                       flags |= EPOLLOUT;
+               
+               if(old_flags != flags)
+               {
+                       if(flags == 0)
+                               op = EPOLL_CTL_DEL;                     
+                       else
+                               op = EPOLL_CTL_MOD;
+                       F->pflags = ep_event.events = flags;
+                       ep_event.data.ptr = F;
+                       if(epoll_ctl(ep, op, F->fd, &ep_event) != 0)
+                       {
+                               libcharybdis_log("comm_setselect(): epoll_ctl failed: %s", strerror(errno));
+                       }
+               }
+                                       
+       }
+       return COMM_OK;
+}
+
diff --git a/libcharybdis/event.c b/libcharybdis/event.c
new file mode 100644 (file)
index 0000000..8568d70
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  event.c: Event functions.
+ *
+ *  Copyright (C) 1998-2000 Regents of the University of California
+ *  Copyright (C) 2001-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development team
+ *
+ *  Code borrowed from the squid web cache by Adrian Chadd.
+ *  Original header:
+ *
+ *  DEBUG: section 41   Event Processing
+ *  AUTHOR: Henrik Nordstrom
+ *
+ *  SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
+ *  ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by the
+ *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
+ *  the Regents of the University of California.  Please see the
+ *  COPYRIGHT file for full details.  Squid incorporates software
+ *  developed and/or copyrighted by other sources.  Please see the
+ *  CREDITS file for full details.
+ *
+ *  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: event.c 498 2006-01-15 16:40:33Z jilles $
+ */
+
+/*
+ * How its used:
+ *
+ * Should be pretty self-explanatory. Events are added to the static
+ * array event_table with a frequency time telling eventRun how often
+ * to execute it.
+ */
+
+#include "stdinc.h"
+#include "config.h"
+
+#include "ircd.h"
+#include "event.h"
+#include "client.h"
+#include "send.h"
+#include "memory.h"
+#include "s_log.h"
+#include "numeric.h"
+
+static const char *last_event_ran = NULL;
+struct ev_entry event_table[MAX_EVENTS];
+static time_t event_time_min = -1;
+
+/*
+ * void eventAdd(const char *name, EVH *func, void *arg, time_t when)
+ *
+ * Input: Name of event, function to call, arguments to pass, and frequency
+ *       of the event.
+ * Output: None
+ * Side Effects: Adds the event to the event list.
+ */
+void
+eventAdd(const char *name, EVH * func, void *arg, time_t when)
+{
+       int i;
+
+       /* find first inactive index */
+       for (i = 0; i < MAX_EVENTS; i++)
+       {
+               if(event_table[i].active == 0)
+               {
+                       event_table[i].func = func;
+                       event_table[i].name = name;
+                       event_table[i].arg = arg;
+                       event_table[i].when = CurrentTime + when;
+                       event_table[i].frequency = when;
+                       event_table[i].active = 1;
+
+                       if((event_table[i].when < event_time_min) || (event_time_min == -1))
+                               event_time_min = event_table[i].when;
+
+                       return;
+               }
+       }
+
+       /* erk! couldnt add to event table */
+       sendto_realops_snomask(SNO_DEBUG, L_ALL, "Unable to add event [%s] to event table", name);
+
+}
+
+void
+eventAddOnce(const char *name, EVH *func, void *arg, time_t when)
+{
+       int i;
+
+       /* find first inactive index */
+       for (i = 0; i < MAX_EVENTS; i++)
+       {
+               if(event_table[i].active == 0)
+               {
+                       event_table[i].func = func;
+                       event_table[i].name = name;
+                       event_table[i].arg = arg;
+                       event_table[i].when = CurrentTime + when;
+                       event_table[i].frequency = 0;
+                       event_table[i].active = 1;
+
+                       if ((event_table[i].when < event_time_min) || (event_time_min == -1))
+                               event_time_min = event_table[i].when;
+
+                       return;
+               }
+       }
+
+       /* erk! couldnt add to event table */
+       sendto_realops_snomask(SNO_DEBUG, L_ALL,
+                            "Unable to add event [%s] to event table", name);
+}
+
+/*
+ * void eventDelete(EVH *func, void *arg)
+ *
+ * Input: Function handler, argument that was passed.
+ * Output: None
+ * Side Effects: Removes the event from the event list
+ */
+void
+eventDelete(EVH * func, void *arg)
+{
+       int i;
+
+       i = eventFind(func, arg);
+
+       if(i == -1)
+               return;
+
+       event_table[i].name = NULL;
+       event_table[i].func = NULL;
+       event_table[i].arg = NULL;
+       event_table[i].active = 0;
+}
+
+/* 
+ * void eventAddIsh(const char *name, EVH *func, void *arg, time_t delta_isa)
+ *
+ * Input: Name of event, function to call, arguments to pass, and frequency
+ *       of the event.
+ * Output: None
+ * Side Effects: Adds the event to the event list within +- 1/3 of the
+ *              specified frequency.
+ */
+void
+eventAddIsh(const char *name, EVH * func, void *arg, time_t delta_ish)
+{
+       if(delta_ish >= 3.0)
+       {
+               const time_t two_third = (2 * delta_ish) / 3;
+               delta_ish = two_third + ((rand() % 1000) * two_third) / 1000;
+               /*
+                * XXX I hate the above magic, I don't even know if its right.
+                * Grr. -- adrian
+                */
+       }
+       eventAdd(name, func, arg, delta_ish);
+}
+
+/*
+ * void eventRun(void)
+ *
+ * Input: None
+ * Output: None
+ * Side Effects: Runs pending events in the event list
+ */
+void
+eventRun(void)
+{
+       int i;
+
+       for (i = 0; i < MAX_EVENTS; i++)
+       {
+               if(event_table[i].active && (event_table[i].when <= CurrentTime))
+               {
+                       last_event_ran = event_table[i].name;
+                       event_table[i].func(event_table[i].arg);
+                       event_time_min = -1;
+
+                       /* event is scheduled more than once */
+                       if(event_table[i].frequency)
+                               event_table[i].when = CurrentTime + event_table[i].frequency;
+                       else
+                       {
+                               event_table[i].name = NULL;
+                               event_table[i].func = NULL;
+                               event_table[i].arg = NULL;
+                               event_table[i].active = 0;
+                       }
+               }
+       }
+}
+
+
+/*
+ * time_t eventNextTime(void)
+ * 
+ * Input: None
+ * Output: Specifies the next time eventRun() should be run
+ * Side Effects: None
+ */
+time_t
+eventNextTime(void)
+{
+       int i;
+
+       if(event_time_min == -1)
+       {
+               for (i = 0; i < MAX_EVENTS; i++)
+               {
+                       if(event_table[i].active &&
+                          ((event_table[i].when < event_time_min) || (event_time_min == -1)))
+                               event_time_min = event_table[i].when;
+               }
+       }
+
+       return event_time_min;
+}
+
+/*
+ * void eventInit(void)
+ *
+ * Input: None
+ * Output: None
+ * Side Effects: Initializes the event system. 
+ */
+void
+eventInit(void)
+{
+       last_event_ran = NULL;
+       memset((void *) event_table, 0, sizeof(event_table));
+}
+
+/*
+ * int eventFind(EVH *func, void *arg)
+ *
+ * Input: Event function and the argument passed to it
+ * Output: Index to the slow in the event_table
+ * Side Effects: None
+ */
+int
+eventFind(EVH * func, void *arg)
+{
+       int i;
+
+       for (i = 0; i < MAX_EVENTS; i++)
+       {
+               if((event_table[i].func == func) &&
+                  (event_table[i].arg == arg) && event_table[i].active)
+                       return i;
+       }
+
+       return -1;
+}
+
+/* 
+ * void show_events(struct Client *source_p)
+ *
+ * Input: Client requesting the event
+ * Output: List of events
+ * Side Effects: None
+ */
+void
+show_events(struct Client *source_p)
+{
+       int i;
+
+       if(last_event_ran)
+               sendto_one_numeric(source_p, RPL_STATSDEBUG, 
+                                  "E :Last event to run: %s",
+                                  last_event_ran);
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "E :Operation                    Next Execution");
+
+       for (i = 0; i < MAX_EVENTS; i++)
+       {
+               if(event_table[i].active)
+               {
+                       sendto_one_numeric(source_p, RPL_STATSDEBUG, 
+                                          "E :%-28s %-4d seconds",
+                                          event_table[i].name, 
+                                          (int)(event_table[i].when - CurrentTime));
+               }
+       }
+}
+
+/* 
+ * void set_back_events(time_t by)
+ * Input: Time to set back events by.
+ * Output: None.
+ * Side-effects: Sets back all events by "by" seconds.
+ */
+void
+set_back_events(time_t by)
+{
+       int i;
+
+       for (i = 0; i < MAX_EVENTS; i++)
+       {
+               if(event_table[i].when > by)
+                       event_table[i].when -= by;
+               else
+                       event_table[i].when = 0;
+       }
+}
+
+void
+eventUpdate(const char *name, time_t freq)
+{
+       int i;
+
+       for(i = 0; i < MAX_EVENTS; i++)
+       {
+               if(event_table[i].active && 
+                  !irccmp(event_table[i].name, name))
+               {
+                       event_table[i].frequency = freq;
+
+                       /* update when its scheduled to run if its higher
+                        * than the new frequency
+                        */
+                       if((CurrentTime + freq) < event_table[i].when)
+                               event_table[i].when = CurrentTime + freq;
+
+                       return;
+               }
+       }
+}
+
+
diff --git a/libcharybdis/event.h b/libcharybdis/event.h
new file mode 100644 (file)
index 0000000..7e70cac
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  event.h: The ircd event header.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: event.h 380 2005-12-07 15:08:37Z nenolod $
+ */
+
+#ifndef INCLUDED_event_h
+#define INCLUDED_event_h
+
+/*
+ * How many event entries we need to allocate at a time in the block
+ * allocator. 16 should be plenty at a time.
+ */
+#define        MAX_EVENTS      50
+
+
+typedef void EVH(void *);
+
+/* The list of event processes */
+struct ev_entry
+{
+       EVH *func;
+       void *arg;
+       const char *name;
+       time_t frequency;
+       time_t when;
+       int active;
+};
+
+extern void eventAdd(const char *name, EVH * func, void *arg, time_t when);
+extern void eventAddOnce(const char *name, EVH * func, void *arg, time_t when);
+extern void eventAddIsh(const char *name, EVH * func, void *arg, time_t delta_ish);
+extern void eventRun(void);
+extern time_t eventNextTime(void);
+extern void eventInit(void);
+extern void eventDelete(EVH * func, void *);
+extern int eventFind(EVH * func, void *);
+extern void set_back_events(time_t);
+
+void eventUpdate(const char *name, time_t freq);
+
+extern void show_events(struct Client *source_p);
+
+#endif /* INCLUDED_event_h */
diff --git a/libcharybdis/kqueue.c b/libcharybdis/kqueue.c
new file mode 100644 (file)
index 0000000..e9fced4
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  kqueue.c: FreeBSD kqueue compatible network routines.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2001 Adrian Chadd <adrian@creative.net.au>
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: kqueue.c 398 2005-12-12 18:12:46Z nenolod $
+ */
+
+#include "stdinc.h"
+#include <sys/event.h>
+
+#include "libcharybdis.h"
+
+#define KE_LENGTH MAX_CLIENTS
+
+/* jlemon goofed up and didn't add EV_SET until fbsd 4.3 */
+
+#ifndef EV_SET
+#define EV_SET(kevp, a, b, c, d, e, f) do {     \
+        (kevp)->ident = (a);                    \
+        (kevp)->filter = (b);                   \
+        (kevp)->flags = (c);                    \
+        (kevp)->fflags = (d);                   \
+        (kevp)->data = (e);                     \
+        (kevp)->udata = (f);                    \
+} while(0)
+#endif
+
+static void kq_update_events(fde_t *, short, PF *);
+static int kq;
+static struct timespec zero_timespec;
+
+static struct kevent *kqlst;   /* kevent buffer */
+static int kqmax;              /* max structs to buffer */
+static int kqoff;              /* offset into the buffer */
+
+
+/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
+/* Private functions */
+
+void
+kq_update_events(fde_t * F, short filter, PF * handler)
+{
+       PF *cur_handler;
+       int kep_flags;
+
+       switch (filter)
+       {
+       case EVFILT_READ:
+               cur_handler = F->read_handler;
+               break;
+       case EVFILT_WRITE:
+               cur_handler = F->write_handler;
+               break;
+       default:
+               /* XXX bad! -- adrian */
+               return;
+               break;
+       }
+
+       if((cur_handler == NULL && handler != NULL) || (cur_handler != NULL && handler == NULL))
+       {
+               struct kevent *kep;
+
+               kep = kqlst + kqoff;
+
+               if(handler != NULL)
+               {
+                       if(filter == EVFILT_WRITE)
+                               kep_flags = (EV_ADD | EV_ENABLE | EV_ONESHOT);
+                       else
+                               kep_flags = (EV_ADD | EV_ENABLE);
+               } 
+               else            
+               {
+                       /* lets definately not poll stuff that isn't real --
+                        * some kqueue implementations hate doing this... and
+                        * it's intended to delete AND disable at the same time.
+                        *
+                        * don't believe me? read kevent(4). --nenolod
+                        */
+                       kep_flags = (EV_DELETE | EV_DISABLE);
+               }
+
+               EV_SET(kep, (uintptr_t) F->fd, filter, kep_flags, 0, 0, (void *) F);
+
+               if(kqoff == kqmax)
+               {
+                       int ret;
+
+                       ret = kevent(kq, kqlst, kqoff, NULL, 0, &zero_timespec);
+                       /* jdc -- someone needs to do error checking... */
+                       if(ret == -1)
+                       {
+                               libcharybdis_log("kq_update_events(): kevent(): %s", strerror(errno));
+                               return;
+                       }
+                       kqoff = 0;
+               }
+               else
+               {
+                       kqoff++;
+               }
+       }
+}
+
+
+
+/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
+/* Public functions */
+
+
+/*
+ * init_netio
+ *
+ * This is a needed exported function which will be called to initialise
+ * the network loop code.
+ */
+void
+init_netio(void)
+{
+       kq = kqueue();
+       if(kq < 0)
+       {
+               libcharybdis_log("init_netio: Couldn't open kqueue fd!\n");
+               exit(115);      /* Whee! */
+       }
+       kqmax = getdtablesize();
+       kqlst = MyMalloc(sizeof(struct kevent) * kqmax);
+       zero_timespec.tv_sec = 0;
+       zero_timespec.tv_nsec = 0;
+}
+
+/*
+ * comm_setselect
+ *
+ * This is a needed exported function which will be called to register
+ * and deregister interest in a pending IO state for a given FD.
+ */
+void
+comm_setselect(int fd, fdlist_t list, unsigned int type, PF * handler,
+              void *client_data, time_t timeout)
+{
+       fde_t *F = &fd_table[fd];
+       s_assert(fd >= 0);
+       s_assert(F->flags.open);
+
+       /* Update the list, even though we're not using it .. */
+       F->list = list;
+
+       if(type & COMM_SELECT_READ)
+       {
+               kq_update_events(F, EVFILT_READ, handler);
+               F->read_handler = handler;
+               F->read_data = client_data;
+       }
+       if(type & COMM_SELECT_WRITE)
+       {
+               kq_update_events(F, EVFILT_WRITE, handler);
+               F->write_handler = handler;
+               F->write_data = client_data;
+       }
+       if(timeout)
+               F->timeout = CurrentTime + (timeout / 1000);
+
+}
+
+/*
+ * Check all connections for new connections and input data that is to be
+ * processed. Also check for connections with data queued and whether we can
+ * write it out.
+ */
+
+/*
+ * comm_select
+ *
+ * Called to do the new-style IO, courtesy of squid (like most of this
+ * new IO code). This routine handles the stuff we've hidden in
+ * comm_setselect and fd_table[] and calls callbacks for IO ready
+ * events.
+ */
+
+int
+comm_select(unsigned long delay)
+{
+       int num, i;
+       static struct kevent ke[KE_LENGTH];
+       struct timespec poll_time;
+
+       /*
+        * remember we are doing NANOseconds here, not micro/milli. God knows
+        * why jlemon used a timespec, but hey, he wrote the interface, not I
+        *   -- Adrian
+        */
+
+       poll_time.tv_sec = delay / 1000;
+
+       poll_time.tv_nsec = (delay % 1000) * 1000000;
+
+       for (;;)
+       {
+               num = kevent(kq, kqlst, kqoff, ke, KE_LENGTH, &poll_time);
+               kqoff = 0;
+
+               if(num >= 0)
+                       break;
+
+               if(ignoreErrno(errno))
+                       break;
+
+               set_time();
+
+               return COMM_ERROR;
+
+               /* NOTREACHED */
+       }
+
+       set_time();
+
+       if(num == 0)
+               return COMM_OK; /* No error.. */
+
+       for (i = 0; i < num; i++)
+       {
+               int fd = (int) ke[i].ident;
+               PF *hdl = NULL;
+               fde_t *F = &fd_table[fd];
+
+               if(ke[i].flags & EV_ERROR)
+               {
+                       errno = (int) ke[i].data;
+                       /* XXX error == bad! -- adrian */
+                       continue;       /* XXX! */
+               }
+
+               switch (ke[i].filter)
+               {
+
+               case EVFILT_READ:
+
+                       if((hdl = F->read_handler) != NULL)
+                       {
+                               F->read_handler = NULL;
+                               hdl(fd, F->read_data);
+                       }
+
+                       break;
+
+               case EVFILT_WRITE:
+
+                       if((hdl = F->write_handler) != NULL)
+                       {
+                               F->write_handler = NULL;
+                               hdl(fd, F->write_data);
+                       }
+                       break;
+
+               default:
+                       /* Bad! -- adrian */
+                       break;
+               }
+       }
+       return COMM_OK;
+}
+
diff --git a/libcharybdis/libcharybdis.c b/libcharybdis/libcharybdis.c
new file mode 100644 (file)
index 0000000..2cef3a9
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ *  charybdis: A slightly useful ircd.
+ *  libcharybdis.c: library entrypoint
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development team
+ *  Copyright (C) 2005 William Pitcock and Jilles Tjoelker
+ *
+ *  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: libcharybdis.c 386 2005-12-07 16:21:24Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "libcharybdis.h"
+
+static void (*log_callback)(const char *str) = NULL;
+static void (*restart_callback)(const char *str) = NULL;
+static void (*die_callback)(const char *str) = NULL;
+static char errbuf[BUFSIZE * 2];
+
+void libcharybdis_log(const char *str, ...)
+{
+       va_list args;
+
+       if (log_callback == NULL)
+               return;
+
+       va_start(args, str);
+       ircvsnprintf(errbuf, BUFSIZE * 2, str, args);
+       va_end(args);
+
+       log_callback(errbuf);
+}
+
+void libcharybdis_restart(const char *str, ...)
+{
+       va_list args;
+
+       if (restart_callback == NULL)
+               return;
+
+       va_start(args, str);
+       ircvsnprintf(errbuf, BUFSIZE * 2, str, args);
+       va_end(args);
+
+       restart_callback(errbuf);
+}
+
+void libcharybdis_die(const char *str, ...)
+{
+       va_list args;
+
+       if (die_callback == NULL)
+               return;
+
+       va_start(args, str);
+       ircvsnprintf(errbuf, BUFSIZE * 2, str, args);
+       va_end(args);
+
+       die_callback(errbuf);
+}
+
+void libcharybdis_init(void (*log_cb)(const char *str),
+       void (*restart_cb)(const char *str), void (*die_cb)(const char *str))
+{
+       log_callback = log_cb;
+       restart_callback = restart_cb;
+       die_callback = die_cb;
+
+       fdlist_init();
+       init_netio();
+       eventInit();
+       initBlockHeap();
+       init_dlink_nodes();
+       linebuf_init();
+}
diff --git a/libcharybdis/libcharybdis.h b/libcharybdis/libcharybdis.h
new file mode 100644 (file)
index 0000000..1ac9bd5
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ *  charybdis: A slightly useful ircd.
+ *  libcharybdis.h: library entrypoint
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development team
+ *  Copyright (C) 2005 William Pitcock and Jilles Tjoelker
+ *
+ *  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: libcharybdis.h 388 2005-12-07 16:34:40Z nenolod $
+ */
+
+#ifndef _LIBCHARYBDIS_H
+#define _LIBCHARYBDIS_H
+
+#include "stdinc.h"
+#include "res.h"
+#include "numeric.h"
+#include "tools.h"
+#include "memory.h"
+#include "balloc.h"
+#include "linebuf.h"
+#include "sprintf_irc.h"
+#include "commio.h"
+#include "event.h"
+
+extern void libcharybdis_log(const char *str, ...);
+extern void libcharybdis_restart(const char *str, ...);
+extern void libcharybdis_die(const char *str, ...);
+extern void libcharybdis_init(void (*)(const char *),
+       void (*)(const char *), void (*)(const char *));
+
+#endif
diff --git a/libcharybdis/linebuf.c b/libcharybdis/linebuf.c
new file mode 100644 (file)
index 0000000..8ac6a31
--- /dev/null
@@ -0,0 +1,686 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  linebuf.c: Maintains linebuffers.
+ *
+ *  Copyright (C) 2001-2002 Adrian Chadd <adrian@creative.net.au>
+ *  Copyright (C) 2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: linebuf.c 1110 2006-03-29 22:55:25Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "client.h"
+#include "linebuf.h"
+#include "memory.h"
+#include "event.h"
+#include "balloc.h"
+#include "hook.h"
+#include "commio.h"
+#include "sprintf_irc.h"
+
+#ifdef STRING_WITH_STRINGS
+# include <string.h>
+# include <strings.h>
+#else
+# ifdef HAVE_STRING_H
+#  include <string.h>
+# else
+#  ifdef HAVE_STRINGS_H
+#   include <strings.h>
+#  endif
+# endif
+#endif
+
+extern BlockHeap *linebuf_heap;
+
+static int bufline_count = 0;
+
+
+/*
+ * linebuf_init
+ *
+ * Initialise the linebuf mechanism
+ */
+
+
+void
+linebuf_init(void)
+{
+       linebuf_heap = BlockHeapCreate(sizeof(buf_line_t), LINEBUF_HEAP_SIZE);
+}
+
+static buf_line_t *
+linebuf_allocate(void)
+{
+       buf_line_t *t;
+       t = BlockHeapAlloc(linebuf_heap);
+       t->refcount = 0;
+       return (t);
+
+}
+
+static void
+linebuf_free(buf_line_t * p)
+{
+       BlockHeapFree(linebuf_heap, p);
+}
+
+/*
+ * linebuf_new_line
+ *
+ * Create a new line, and link it to the given linebuf.
+ * It will be initially empty.
+ */
+static buf_line_t *
+linebuf_new_line(buf_head_t * bufhead)
+{
+       buf_line_t *bufline;
+       dlink_node *node;
+
+       bufline = linebuf_allocate();
+       if(bufline == NULL)
+               return NULL;
+       ++bufline_count;
+
+
+       node = make_dlink_node();
+
+       bufline->len = 0;
+       bufline->terminated = 0;
+       bufline->flushing = 0;
+       bufline->raw = 0;
+
+       /* Stick it at the end of the buf list */
+       dlinkAddTail(bufline, node, &bufhead->list);
+       bufline->refcount++;
+
+       /* And finally, update the allocated size */
+       bufhead->alloclen++;
+       bufhead->numlines++;
+
+       return bufline;
+}
+
+
+/*
+ * linebuf_done_line
+ *
+ * We've finished with the given line, so deallocate it
+ */
+static void
+linebuf_done_line(buf_head_t * bufhead, buf_line_t * bufline, dlink_node * node)
+{
+       /* Remove it from the linked list */
+       dlinkDestroy(node, &bufhead->list);
+
+       /* Update the allocated size */
+       bufhead->alloclen--;
+       bufhead->len -= bufline->len;
+       s_assert(bufhead->len >= 0);
+       bufhead->numlines--;
+
+       bufline->refcount--;
+       s_assert(bufline->refcount >= 0);
+
+       if(bufline->refcount == 0)
+       {
+               /* and finally, deallocate the buf */
+               --bufline_count;
+               s_assert(bufline_count >= 0);
+               linebuf_free(bufline);
+       }
+}
+
+
+/*
+ * skip to end of line or the crlfs, return the number of bytes ..
+ */
+static inline int
+linebuf_skip_crlf(char *ch, int len)
+{
+       int orig_len = len;
+
+       /* First, skip until the first non-CRLF */
+       for (; len; len--, ch++)
+       {
+               if(*ch == '\r')
+                       break;
+               else if(*ch == '\n')
+                       break;
+       }
+
+       /* Then, skip until the last CRLF */
+       for (; len; len--, ch++)
+       {
+               if((*ch != '\r') && (*ch != '\n'))
+                       break;
+       }
+       s_assert(orig_len > len);
+       return (orig_len - len);
+}
+
+
+
+/*
+ * linebuf_newbuf
+ *
+ * Initialise the new buffer
+ */
+void
+linebuf_newbuf(buf_head_t * bufhead)
+{
+       /* not much to do right now :) */
+       memset(bufhead, 0, sizeof(buf_head_t));
+}
+
+/*
+ * client_flush_input
+ *
+ * inputs      - pointer to client
+ * output      - none
+ * side effects - all input line bufs are flushed 
+ */
+void
+client_flush_input(struct Client *client_p)
+{
+       /* This way, it can be called for remote client as well */
+
+       if(client_p->localClient == NULL)
+               return;
+
+       linebuf_donebuf(&client_p->localClient->buf_recvq);
+}
+
+
+/*
+ * linebuf_donebuf
+ *
+ * Flush all the lines associated with this buffer
+ */
+void
+linebuf_donebuf(buf_head_t * bufhead)
+{
+       while (bufhead->list.head != NULL)
+       {
+               linebuf_done_line(bufhead,
+                                 (buf_line_t *) bufhead->list.head->data, bufhead->list.head);
+       }
+}
+
+/*
+ * linebuf_copy_line
+ *
+ * Okay..this functions comments made absolutely no sense.
+ * 
+ * Basically what we do is this.  Find the first chunk of text
+ * and then scan for a CRLF.  If we didn't find it, but we didn't
+ * overflow our buffer..we wait for some more data.
+ * If we found a CRLF, we replace them with a \0 character.
+ * If we overflowed, we copy the most our buffer can handle, terminate
+ * it with a \0 and return.
+ *
+ * The return value is the amount of data we consumed.  This could
+ * be different than the size of the linebuffer, as when we discard
+ * the overflow, we don't want to process it again.
+ *
+ * This still sucks in my opinion, but it seems to work.
+ *
+ * -Aaron
+ */
+static int
+linebuf_copy_line(buf_head_t * bufhead, buf_line_t * bufline, char *data, int len)
+{
+       int cpylen = 0;         /* how many bytes we've copied */
+       char *ch = data;        /* Pointer to where we are in the read data */
+       char *bufch = bufline->buf + bufline->len;
+       int clen = 0;           /* how many bytes we've processed,
+                                  and don't ever want to see again.. */
+
+       /* If its full or terminated, ignore it */
+
+       bufline->raw = 0;
+       s_assert(bufline->len < BUF_DATA_SIZE);
+       if(bufline->terminated == 1)
+               return 0;
+
+       clen = cpylen = linebuf_skip_crlf(ch, len);
+       if(clen == -1)
+               return -1;
+
+       /* This is the ~overflow case..This doesn't happen often.. */
+       if(cpylen > (BUF_DATA_SIZE - bufline->len - 1))
+       {
+               memcpy(bufch, ch, (BUF_DATA_SIZE - bufline->len - 1));
+               bufline->buf[BUF_DATA_SIZE - 1] = '\0';
+               bufch = bufline->buf + BUF_DATA_SIZE - 2;
+               while (cpylen && (*bufch == '\r' || *bufch == '\n'))
+               {
+                       *bufch = '\0';
+                       cpylen--;
+                       bufch--;
+               }
+               bufline->terminated = 1;
+               bufline->len = BUF_DATA_SIZE - 1;
+               bufhead->len += BUF_DATA_SIZE - 1;
+               return clen;
+       }
+
+       memcpy(bufch, ch, cpylen);
+       bufch += cpylen;
+       *bufch = '\0';
+       bufch--;
+
+       if(*bufch != '\r' && *bufch != '\n')
+       {
+               /* No linefeed, bail for the next time */
+               bufhead->len += cpylen;
+               bufline->len += cpylen;
+               bufline->terminated = 0;
+               return clen;
+       }
+
+       /* Yank the CRLF off this, replace with a \0 */
+       while (cpylen && (*bufch == '\r' || *bufch == '\n'))
+       {
+               *bufch = '\0';
+               cpylen--;
+               bufch--;
+       }
+
+       bufline->terminated = 1;
+       bufhead->len += cpylen;
+       bufline->len += cpylen;
+       return clen;
+}
+
+/*
+ * linebuf_copy_raw
+ *
+ * Copy as much data as possible directly into a linebuf,
+ * splitting at \r\n, but without altering any data.
+ *
+ */
+static int
+linebuf_copy_raw(buf_head_t * bufhead, buf_line_t * bufline, char *data, int len)
+{
+       int cpylen = 0;         /* how many bytes we've copied */
+       char *ch = data;        /* Pointer to where we are in the read data */
+       char *bufch = bufline->buf + bufline->len;
+       int clen = 0;           /* how many bytes we've processed,
+                                  and don't ever want to see again.. */
+
+       /* If its full or terminated, ignore it */
+
+       bufline->raw = 1;
+       s_assert(bufline->len < BUF_DATA_SIZE);
+       if(bufline->terminated == 1)
+               return 0;
+
+       clen = cpylen = linebuf_skip_crlf(ch, len);
+       if(clen == -1)
+               return -1;
+
+       /* This is the overflow case..This doesn't happen often.. */
+       if(cpylen > (BUF_DATA_SIZE - bufline->len - 1))
+       {
+               clen = BUF_DATA_SIZE - bufline->len - 1;
+               memcpy(bufch, ch, clen);
+               bufline->buf[BUF_DATA_SIZE - 1] = '\0';
+               bufch = bufline->buf + BUF_DATA_SIZE - 2;
+               bufline->terminated = 1;
+               bufline->len = BUF_DATA_SIZE - 1;
+               bufhead->len += BUF_DATA_SIZE - 1;
+               return clen;
+       }
+
+       memcpy(bufch, ch, cpylen);
+       bufch += cpylen;
+       *bufch = '\0';
+       bufch--;
+
+       if(*bufch != '\r' && *bufch != '\n')
+       {
+               /* No linefeed, bail for the next time */
+               bufhead->len += cpylen;
+               bufline->len += cpylen;
+               bufline->terminated = 0;
+               return clen;
+       }
+
+       bufline->terminated = 1;
+       bufhead->len += cpylen;
+       bufline->len += cpylen;
+       return clen;
+}
+
+
+/*
+ * linebuf_parse
+ *
+ * Take a given buffer and break out as many buffers as we can.
+ * If we find a CRLF, we terminate that buffer and create a new one.
+ * If we don't find a CRLF whilst parsing a buffer, we don't mark it
+ * 'finished', so the next loop through we can continue appending ..
+ *
+ * A few notes here, which you'll need to understand before continuing.
+ *
+ * - right now I'm only dealing with single sized buffers. Later on,
+ *   I might consider chaining buffers together to get longer "lines"
+ *   but seriously, I don't see the advantage right now.
+ *
+ * - This *is* designed to turn into a reference-counter-protected setup
+ *   to dodge copious copies.
+ */
+int
+linebuf_parse(buf_head_t * bufhead, char *data, int len, int raw)
+{
+       buf_line_t *bufline;
+       int cpylen;
+       int linecnt = 0;
+
+       /* First, if we have a partial buffer, try to squeze data into it */
+       if(bufhead->list.tail != NULL)
+       {
+               /* Check we're doing the partial buffer thing */
+               bufline = bufhead->list.tail->data;
+               s_assert(!bufline->flushing);
+               /* just try, the worst it could do is *reject* us .. */
+               if(!raw)
+                       cpylen = linebuf_copy_line(bufhead, bufline, data, len);
+               else
+                       cpylen = linebuf_copy_raw(bufhead, bufline, data, len);
+                       
+               if(cpylen == -1)
+                       return -1;
+
+               linecnt++;
+               /* If we've copied the same as what we've got, quit now */
+               if(cpylen == len)
+                       return linecnt; /* all the data done so soon? */
+
+               /* Skip the data and update len .. */
+               len -= cpylen;
+               s_assert(len >= 0);
+               data += cpylen;
+       }
+
+       /* Next, the loop */
+       while (len > 0)
+       {
+               /* We obviously need a new buffer, so .. */
+               bufline = linebuf_new_line(bufhead);
+
+               /* And parse */
+               if(!raw)
+                       cpylen = linebuf_copy_line(bufhead, bufline, data, len);
+               else
+                       cpylen = linebuf_copy_raw(bufhead, bufline, data, len);
+               
+               if(cpylen == -1)
+                       return -1;
+
+               len -= cpylen;
+               s_assert(len >= 0);
+               data += cpylen;
+               linecnt++;
+       }
+       return linecnt;
+}
+
+
+/*
+ * linebuf_get
+ *
+ * get the next buffer from our line. For the time being it will copy
+ * data into the given buffer and free the underlying linebuf.
+ */
+int
+linebuf_get(buf_head_t * bufhead, char *buf, int buflen, int partial, int raw)
+{
+       buf_line_t *bufline;
+       int cpylen;
+       char *start, *ch;
+
+       /* make sure we have a line */
+       if(bufhead->list.head == NULL)
+               return 0;       /* Obviously not.. hrm. */
+
+       bufline = bufhead->list.head->data;
+
+       /* make sure that the buffer was actually *terminated */
+       if(!(partial || bufline->terminated))
+               return 0;       /* Wait for more data! */
+
+       /* make sure we've got the space, including the NULL */
+       cpylen = bufline->len;
+       s_assert(cpylen + 1 <= buflen);
+
+       /* Copy it */
+       start = bufline->buf;
+
+       /* if we left extraneous '\r\n' characters in the string,
+        * and we don't want to read the raw data, clean up the string.
+        */
+       if(bufline->raw && !raw)
+       {
+               /* skip leading EOL characters */
+               while (cpylen && (*start == '\r' || *start == '\n'))
+               {
+                       start++;
+                       cpylen--;
+               }
+               /* skip trailing EOL characters */
+               ch = &start[cpylen - 1];
+               while (cpylen && (*ch == '\r' || *ch == '\n'))
+               {
+                       ch--;
+                       cpylen--;
+               }
+       }
+       memcpy(buf, start, cpylen + 1);
+
+       /* convert CR/LF to NULL */
+       if(bufline->raw && !raw)
+               buf[cpylen] = '\0';
+
+       s_assert(cpylen >= 0);
+
+       /* Deallocate the line */
+       linebuf_done_line(bufhead, bufline, bufhead->list.head);
+
+       /* return how much we copied */
+       return cpylen;
+}
+
+/*
+ * linebuf_attach
+ *
+ * attach the lines in a buf_head_t to another buf_head_t
+ * without copying the data (using refcounts).
+ */
+void
+linebuf_attach(buf_head_t * bufhead, buf_head_t * new)
+{
+       dlink_node *ptr;
+       buf_line_t *line;
+
+       DLINK_FOREACH(ptr, new->list.head)
+       {
+               line = ptr->data;
+               dlinkAddTailAlloc(line, &bufhead->list);
+
+               /* Update the allocated size */
+               bufhead->alloclen++;
+               bufhead->len += line->len;
+               bufhead->numlines++;
+
+               line->refcount++;
+       }
+}
+
+/*
+ * linebuf_putmsg
+ *
+ * Similar to linebuf_put, but designed for use by send.c.
+ *
+ * prefixfmt is used as a format for the varargs, and is inserted first.
+ * Then format/va_args is appended to the buffer.
+ */
+void
+linebuf_putmsg(buf_head_t * bufhead, const char *format, va_list * va_args,
+              const char *prefixfmt, ...)
+{
+       buf_line_t *bufline;
+       int len = 0;
+       va_list prefix_args;
+
+       /* make sure the previous line is terminated */
+#ifndef NDEBUG
+       if(bufhead->list.tail)
+       {
+               bufline = bufhead->list.tail->data;
+               s_assert(bufline->terminated);
+       }
+#endif
+       /* Create a new line */
+       bufline = linebuf_new_line(bufhead);
+
+       if(prefixfmt != NULL)
+       {
+               va_start(prefix_args, prefixfmt);
+               len = ircvsnprintf(bufline->buf, BUF_DATA_SIZE, prefixfmt, prefix_args);
+               va_end(prefix_args);
+       }
+
+       if(va_args != NULL)
+       {
+               len += ircvsnprintf((bufline->buf + len), (BUF_DATA_SIZE - len), format, *va_args);
+       }
+
+       bufline->terminated = 1;
+
+       /* Truncate the data if required */
+       if(len > 510)
+       {
+               len = 510;
+               bufline->buf[len++] = '\r';
+               bufline->buf[len++] = '\n';
+       }
+       else if(len == 0)
+       {
+               bufline->buf[len++] = '\r';
+               bufline->buf[len++] = '\n';
+               bufline->buf[len] = '\0';
+       }
+       else
+       {
+               /* Chop trailing CRLF's .. */
+               while ((bufline->buf[len] == '\r')
+                      || (bufline->buf[len] == '\n') || (bufline->buf[len] == '\0'))
+               {
+                       len--;
+               }
+
+               bufline->buf[++len] = '\r';
+               bufline->buf[++len] = '\n';
+               bufline->buf[++len] = '\0';
+       }
+
+       bufline->len = len;
+       bufhead->len += len;
+}
+
+
+
+/*
+ * linebuf_flush
+ *
+ * Flush data to the buffer. It tries to write as much data as possible
+ * to the given socket. Any return values are passed straight through.
+ * If there is no data in the socket, EWOULDBLOCK is set as an errno
+ * rather than returning 0 (which would map to an EOF..)
+ *
+ * Notes: XXX We *should* have a clue here when a non-full buffer is arrived.
+ *        and tag it so that we don't re-schedule another write until
+ *        we have a CRLF.
+ */
+
+int
+linebuf_flush(int fd, buf_head_t * bufhead)
+{
+       buf_line_t *bufline;
+       int retval;
+       /* Check we actually have a first buffer */
+       if(bufhead->list.head == NULL)
+       {
+               /* nope, so we return none .. */
+               errno = EWOULDBLOCK;
+               return -1;
+       }
+
+       bufline = bufhead->list.head->data;
+
+       /* And that its actually full .. */
+       if(!bufline->terminated)
+       {
+               errno = EWOULDBLOCK;
+               return -1;
+       }
+
+       /* Check we're flushing the first buffer */
+       if(!bufline->flushing)
+       {
+               bufline->flushing = 1;
+               bufhead->writeofs = 0;
+       }
+
+       /* Now, try writing data */
+       retval = send(fd, bufline->buf + bufhead->writeofs, bufline->len - bufhead->writeofs, 0);
+
+       if(retval <= 0)
+               return retval;
+
+       /* we've got data, so update the write offset */
+       bufhead->writeofs += retval;
+
+       /* if we've written everything *and* the CRLF, deallocate and update
+          bufhead */
+       if(bufhead->writeofs == bufline->len)
+       {
+               bufhead->writeofs = 0;
+               s_assert(bufhead->len >= 0);
+               linebuf_done_line(bufhead, bufline, bufhead->list.head);
+       }
+
+       /* Return line length */
+       return retval;
+}
+
+
+
+/*
+ * count linebufs for stats z
+ */
+
+void
+count_linebuf_memory(size_t * count, size_t * linebuf_memory_used)
+{
+       BlockHeapUsage(linebuf_heap, count, NULL, linebuf_memory_used);
+}
diff --git a/libcharybdis/linebuf.h b/libcharybdis/linebuf.h
new file mode 100644 (file)
index 0000000..5444fe3
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  linebuf.h: A header for the linebuf code.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: linebuf.h 376 2005-12-07 15:00:41Z nenolod $
+ */
+
+#ifndef __LINEBUF_H__
+#define __LINEBUF_H__
+
+#include "tools.h"
+
+/* How big we want a buffer - 510 data bytes, plus space for a '\0' */
+#define BUF_DATA_SIZE          511
+
+#define LINEBUF_COMPLETE        0
+#define LINEBUF_PARTIAL         1
+#define LINEBUF_PARSED          0
+#define LINEBUF_RAW             1
+
+struct _buf_line;
+struct _buf_head;
+
+typedef struct _buf_line buf_line_t;
+typedef struct _buf_head buf_head_t;
+
+struct _buf_line
+{
+       char buf[BUF_DATA_SIZE + 2];
+       unsigned int terminated;        /* Whether we've terminated the buffer */
+       unsigned int flushing;  /* Whether we're flushing .. */
+       unsigned int raw;       /* Whether this linebuf may hold 8-bit data */
+       int len;                /* How much data we've got */
+       int refcount;           /* how many linked lists are we in? */
+       struct _buf_line *next; /* next in free list */
+};
+
+struct _buf_head
+{
+       dlink_list list;        /* the actual dlink list */
+       int len;                /* length of all the data */
+       int alloclen;           /* Actual allocated data length */
+       int writeofs;           /* offset in the first line for the write */
+       int numlines;           /* number of lines */
+};
+
+/* they should be functions, but .. */
+#define linebuf_len(x)         ((x)->len)
+#define linebuf_alloclen(x)    ((x)->alloclen)
+#define linebuf_numlines(x)    ((x)->numlines)
+
+extern void linebuf_init(void);
+/* declared as static */
+/* extern buf_line_t *linebuf_new_line(buf_head_t *); */
+/* extern void linebuf_done_line(buf_head_t *, buf_line_t *, dlink_node *); */
+/* extern int linebuf_skip_crlf(char *, int); */
+/* extern void linebuf_terminate_crlf(buf_head_t *, buf_line_t *); */
+extern void linebuf_newbuf(buf_head_t *);
+extern void client_flush_input(struct Client *);
+extern void linebuf_donebuf(buf_head_t *);
+extern int linebuf_parse(buf_head_t *, char *, int, int);
+extern int linebuf_get(buf_head_t *, char *, int, int, int);
+extern void linebuf_putmsg(buf_head_t *, const char *, va_list *, const char *, ...);
+extern int linebuf_flush(int, buf_head_t *);
+extern void linebuf_attach(buf_head_t *, buf_head_t *);
+extern void count_linebuf_memory(size_t *, size_t *);
+#endif
diff --git a/libcharybdis/memory.c b/libcharybdis/memory.c
new file mode 100644 (file)
index 0000000..c2c5c11
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  memory.c: Memory utilities.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: memory.c 388 2005-12-07 16:34:40Z nenolod $
+ */
+
+
+#define WE_ARE_MEMORY_C
+
+#include "libcharybdis.h"
+
+/*
+ * MyMalloc - allocate memory, call outofmemory on failure
+ */
+void *
+MyMalloc(size_t size)
+{
+       void *ret = calloc(1, size);
+       if(ret == NULL)
+               outofmemory();
+       return ret;
+}
+
+/*
+ * MyRealloc - reallocate memory, call outofmemory on failure
+ */
+void *
+MyRealloc(void *x, size_t y)
+{
+       void *ret = realloc(x, y);
+
+       if(ret == NULL)
+               outofmemory();
+       return ret;
+}
+
+/*
+ * outofmemory()
+ *
+ * input        - NONE
+ * output       - NONE
+ * side effects - simply try to report there is a problem. Abort if it was called more than once
+ */
+void
+outofmemory()
+{
+       static int was_here = 0;
+
+       if(was_here)
+               libcharybdis_die("Out of Memory!");
+
+       was_here = 1;
+
+       libcharybdis_restart("Aiee! Out of memory... >_<!");
+}
diff --git a/libcharybdis/memory.h b/libcharybdis/memory.h
new file mode 100644 (file)
index 0000000..5e7d06b
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  memory.h: A header for the memory functions.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: memory.h 382 2005-12-07 15:15:59Z nenolod $
+ */
+
+#ifndef _I_MEMORY_H
+#define _I_MEMORY_H
+
+#include "ircd_defs.h"
+#include "setup.h"
+#include "balloc.h"
+
+/* Needed to use uintptr_t for some pointer manipulation. */
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#else /* No inttypes.h */
+#ifndef HAVE_UINTPTR_T
+typedef unsigned long uintptr_t;
+#endif
+#endif
+
+extern void outofmemory(void);
+
+extern void *MyMalloc(size_t size);
+extern void *MyRealloc(void *x, size_t y);
+
+/* forte (and maybe others) dont like double declarations, 
+ * so we dont declare the inlines unless GNUC
+ */
+/* darwin doesnt like these.. */
+#ifndef __APPLE__
+
+#ifdef __GNUC__
+extern inline void *
+MyMalloc(size_t size)
+{
+       void *ret = calloc(1, size);
+       if(ret == NULL)
+               outofmemory();
+       return (ret);
+}
+
+extern inline void *
+MyRealloc(void *x, size_t y)
+{
+       void *ret = realloc(x, y);
+
+       if(ret == NULL)
+               outofmemory();
+       return (ret);
+}
+
+#endif /* __GNUC__ */
+#endif /* __APPLE__ */
+
+#define MyFree(x) do { if(x) free(x); } while (0)
+
+#endif /* _I_MEMORY_H */
diff --git a/libcharybdis/poll.c b/libcharybdis/poll.c
new file mode 100644 (file)
index 0000000..5929b71
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  s_bsd_poll.c: POSIX poll() compatible network routines.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2001 Adrian Chadd <adrian@creative.net.au>
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: poll.c 390 2005-12-07 18:46:56Z nenolod $
+ */
+
+#include "config.h"
+#include "stdinc.h"
+#include <sys/poll.h>
+
+#include "libcharybdis.h"
+
+/* I hate linux -- adrian */
+#ifndef POLLRDNORM
+#define POLLRDNORM POLLIN
+#endif
+#ifndef POLLWRNORM
+#define POLLWRNORM POLLOUT
+#endif
+
+struct _pollfd_list
+{
+       struct pollfd pollfds[MAXCONNECTIONS];
+       int maxindex;           /* highest FD number */
+};
+
+typedef struct _pollfd_list pollfd_list_t;
+
+pollfd_list_t pollfd_list;
+static void poll_update_pollfds(int, short, PF *);
+static unsigned long last_count = 0; 
+static unsigned long empty_count = 0;
+/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
+/* Private functions */
+
+/*
+ * find a spare slot in the fd list. We can optimise this out later!
+ *   -- adrian
+ */
+static inline int
+poll_findslot(void)
+{
+       int i;
+       for (i = 0; i < MAXCONNECTIONS; i++)
+       {
+               if(pollfd_list.pollfds[i].fd == -1)
+               {
+                       /* MATCH!!#$*&$ */
+                       return i;
+               }
+       }
+       s_assert(1 == 0);
+       /* NOTREACHED */
+       return -1;
+}
+
+/*
+ * set and clear entries in the pollfds[] array.
+ */
+static void
+poll_update_pollfds(int fd, short event, PF * handler)
+{
+       fde_t *F = &fd_table[fd];
+       int comm_index;
+
+       if(F->comm_index < 0)
+       {
+               F->comm_index = poll_findslot();
+       }
+       comm_index = F->comm_index;
+
+       /* Update the events */
+       if(handler)
+       {
+               F->list = FDLIST_IDLECLIENT;
+               pollfd_list.pollfds[comm_index].events |= event;
+               pollfd_list.pollfds[comm_index].fd = fd;
+               /* update maxindex here */
+               if(comm_index > pollfd_list.maxindex)
+                       pollfd_list.maxindex = comm_index;
+       }
+       else
+       {
+               if(comm_index >= 0)
+               {
+                       pollfd_list.pollfds[comm_index].events &= ~event;
+                       if(pollfd_list.pollfds[comm_index].events == 0)
+                       {
+                               pollfd_list.pollfds[comm_index].fd = -1;
+                               pollfd_list.pollfds[comm_index].revents = 0;
+                               F->comm_index = -1;
+                               F->list = FDLIST_NONE;
+
+                               /* update pollfd_list.maxindex here */
+                               if(comm_index == pollfd_list.maxindex)
+                                       while (pollfd_list.maxindex >= 0 &&
+                                              pollfd_list.pollfds[pollfd_list.maxindex].fd == -1)
+                                               pollfd_list.maxindex--;
+                       }
+               }
+       }
+}
+
+
+/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
+/* Public functions */
+
+
+/*
+ * init_netio
+ *
+ * This is a needed exported function which will be called to initialise
+ * the network loop code.
+ */
+void
+init_netio(void)
+{
+       int fd;
+
+       for (fd = 0; fd < MAXCONNECTIONS; fd++)
+       {
+               pollfd_list.pollfds[fd].fd = -1;
+       }
+       pollfd_list.maxindex = 0;
+}
+
+/*
+ * comm_setselect
+ *
+ * This is a needed exported function which will be called to register
+ * and deregister interest in a pending IO state for a given FD.
+ */
+void
+comm_setselect(int fd, fdlist_t list, unsigned int type, PF * handler,
+              void *client_data, time_t timeout)
+{
+       fde_t *F = &fd_table[fd];
+       s_assert(fd >= 0);
+       s_assert(F->flags.open);
+
+       if(type & COMM_SELECT_READ)
+       {
+               F->read_handler = handler;
+               F->read_data = client_data;
+               poll_update_pollfds(fd, POLLRDNORM, handler);
+       }
+       if(type & COMM_SELECT_WRITE)
+       {
+               F->write_handler = handler;
+               F->write_data = client_data;
+               poll_update_pollfds(fd, POLLWRNORM, handler);
+       }
+       if(timeout)
+               F->timeout = CurrentTime + (timeout / 1000);
+}
+
+static void
+irc_sleep(unsigned long useconds)
+{     
+#ifdef HAVE_NANOSLEEP    
+        struct timespec t;
+        t.tv_sec = useconds / (unsigned long) 1000000;
+        t.tv_nsec = (useconds % (unsigned long) 1000000) * 1000;
+        nanosleep(&t, (struct timespec *) NULL);
+#else    
+        struct timeval t;        
+        t.tv_sec = 0;    
+        t.tv_usec = useconds;
+        select(0, NULL, NULL, NULL, &t);
+#endif
+        return;
+}
+
+/* int comm_select_fdlist(unsigned long delay)
+ * Input: The maximum time to delay.
+ * Output: Returns -1 on error, 0 on success.
+ * Side-effects: Deregisters future interest in IO and calls the handlers
+ *               if an event occurs for an FD.
+ * Comments: Check all connections for new connections and input data
+ * that is to be processed. Also check for connections with data queued
+ * and whether we can write it out.
+ * Called to do the new-style IO, courtesy of squid (like most of this
+ * new IO code). This routine handles the stuff we've hidden in
+ * comm_setselect and fd_table[] and calls callbacks for IO ready
+ * events.
+ */
+int
+comm_select(unsigned long delay)
+{
+       int num;
+       int fd;
+       int ci;
+       unsigned long ndelay;
+       PF *hdl;
+
+       if(last_count > 0)
+       {
+               empty_count = 0;
+               ndelay = 0;
+       }
+       else {
+               ndelay = ++empty_count * 15000 ;
+               if(ndelay > delay * 1000)
+                       ndelay = delay * 1000;  
+       }
+       
+       for (;;)
+       {
+               /* XXX kill that +1 later ! -- adrian */
+               if(ndelay > 0)
+                       irc_sleep(ndelay); 
+               last_count = num = poll(pollfd_list.pollfds, pollfd_list.maxindex + 1, 0);
+               if(num >= 0)
+                       break;
+               if(ignoreErrno(errno))
+                       continue;
+               /* error! */
+               set_time();
+               return -1;
+               /* NOTREACHED */
+       }
+
+       /* update current time again, eww.. */
+       set_time();
+
+       if(num == 0)
+               return 0;
+       /* XXX we *could* optimise by falling out after doing num fds ... */
+       for (ci = 0; ci < pollfd_list.maxindex + 1; ci++)
+       {
+               fde_t *F;
+               int revents;
+               if(((revents = pollfd_list.pollfds[ci].revents) == 0) ||
+                  (pollfd_list.pollfds[ci].fd) == -1)
+                       continue;
+               fd = pollfd_list.pollfds[ci].fd;
+               F = &fd_table[fd];
+               if(revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR))
+               {
+                       hdl = F->read_handler;
+                       F->read_handler = NULL;
+                       poll_update_pollfds(fd, POLLRDNORM, NULL);
+                       if(hdl)
+                               hdl(fd, F->read_data);
+               }
+               if(revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR))
+               {
+                       hdl = F->write_handler;
+                       F->write_handler = NULL;
+                       poll_update_pollfds(fd, POLLWRNORM, NULL);
+                       if(hdl)
+                               hdl(fd, F->write_data);
+               }
+       }
+       return 0;
+}
+
diff --git a/libcharybdis/ports.c b/libcharybdis/ports.c
new file mode 100644 (file)
index 0000000..ffb8955
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ *  charybdis: A slightly useful ircd.
+ *  ports.c: Solaris ports compatible network routines.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2001 Adrian Chadd <adrian@creative.net.au>
+ *  Copyright (C) 2002-2004 ircd-ratbox development team
+ *  Copyright (C) 2005 Edward Brocklesby.
+ *  Copyright (C) 2005 William Pitcock and Jilles Tjoelker
+ *
+ *  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$
+ */
+
+#include "stdinc.h"
+#include <port.h>
+#include <time.h>
+
+#include "libcharybdis.h"
+
+#define PE_LENGTH      128
+
+static void pe_update_events(fde_t *, short, PF *);
+static int pe;
+static struct timespec zero_timespec;
+
+static port_event_t *pelst;    /* port buffer */
+static int pemax;              /* max structs to buffer */
+
+int 
+ircd_setup_fd(int fd)
+{
+        return 0;
+}
+        
+
+void
+pe_update_events(fde_t * F, short filter, PF * handler)
+{
+       PF *cur_handler = NULL;
+
+       if (filter == POLLRDNORM)
+               cur_handler = F->read_handler;
+       else if (filter == POLLWRNORM)
+               cur_handler = F->write_handler;
+
+       if (!cur_handler && handler)
+               port_associate(pe, PORT_SOURCE_FD, F->fd, filter, F);
+       else if (cur_handler && !handler)
+               port_dissociate(pe, PORT_SOURCE_FD, F->fd);
+}
+
+/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
+/* Public functions */
+
+
+/*
+ * init_netio
+ *
+ * This is a needed exported function which will be called to initialise
+ * the network loop code.
+ */
+void
+init_netio(void)
+{
+       if((pe = port_create()) < 0) {
+               libcharybdis_log("init_netio: Couldn't open port fd!\n");
+               exit(115);      /* Whee! */
+       }
+       pemax = getdtablesize();
+       pelst = MyMalloc(sizeof(port_event_t) * pemax);
+       zero_timespec.tv_sec = 0;
+       zero_timespec.tv_nsec = 0;
+}
+
+/*
+ * ircd_setselect
+ *
+ * This is a needed exported function which will be called to register
+ * and deregister interest in a pending IO state for a given FD.
+ */
+void
+ircd_setselect(int fd, fdlist_t list, unsigned int type, PF * handler,
+              void *client_data)
+{
+       fde_t *F = &fd_table[fd];
+       s_assert(fd >= 0);
+       s_assert(F->flags.open);
+
+       /* Update the list, even though we're not using it .. */
+       F->list = list;
+
+       if(type & IRCD_SELECT_READ) {
+               pe_update_events(F, POLLRDNORM, handler);
+               F->read_handler = handler;
+               F->read_data = client_data;
+       }
+       if(type & IRCD_SELECT_WRITE) {
+               pe_update_events(F, POLLWRNORM, handler);
+               F->write_handler = handler;
+               F->write_data = client_data;
+       }
+}
+
+/*
+ * ircd_select
+ *
+ * Called to do the new-style IO, courtesy of squid (like most of this
+ * new IO code). This routine handles the stuff we've hidden in
+ * ircd_setselect and fd_table[] and calls callbacks for IO ready
+ * events.
+ */
+
+int
+ircd_select(unsigned long delay)
+{
+       int              i, fd;
+       uint             nget = 1;
+       struct  timespec         poll_time;
+       struct  timer_data      *tdata;
+
+       poll_time.tv_sec = delay / 1000;
+       poll_time.tv_nsec = (delay % 1000) * 1000000;
+
+       i = port_getn(pe, pelst, pemax, &nget, &poll_time);
+       ircd_set_time();
+
+       if (i == -1)
+               return COMM_ERROR;
+
+       for (i = 0; i < nget; i++) {
+               switch(pelst[i].portev_source) {
+               case PORT_SOURCE_FD:
+                       fd = pelst[i].portev_object;
+                       PF *hdl = NULL;
+                       fde_t *F = &fd_table[fd];
+
+                       if ((pelst[i].portev_events & POLLRDNORM) && (hdl = F->read_handler)) {
+                               F->read_handler = NULL;
+                               hdl(fd, F->read_data);
+                       }
+                       if ((pelst[i].portev_events & POLLWRNORM) && (hdl = F->write_handler)) {
+                               F->write_handler = NULL;
+                               hdl(fd, F->write_data);
+                       }
+                       break;
+
+               case PORT_SOURCE_TIMER:
+                       tdata = pelst[i].portev_user;
+                       tdata->td_cb(tdata->td_udata);
+
+                       if (!tdata->td_repeat)
+                               free(tdata);
+
+                       break;
+               }
+       }
+       return COMM_OK;
+}
diff --git a/libcharybdis/select.c b/libcharybdis/select.c
new file mode 100644 (file)
index 0000000..0f8ff27
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  select.c: select() compatible network routines.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2001 Adrian Chadd <adrian@creative.net.au>
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: select.c 390 2005-12-07 18:46:56Z nenolod $
+ */
+
+#include "config.h"
+
+#include "libcharybdis.h"
+
+#if HARD_FDLIMIT_ >= FD_SETSIZE
+#error HARD_FDLIMIT_ must be less than FD_SETSIZE(try using poll instead of select)
+#endif
+/*
+ * Note that this is only a single list - multiple lists is kinda pointless
+ * under select because the list size is a function of the highest FD :-)
+ *   -- adrian
+ */
+
+fd_set select_readfds;
+fd_set select_writefds;
+
+/*
+ * You know, I'd rather have these local to comm_select but for some
+ * reason my gcc decides that I can't modify them at all..
+ *   -- adrian
+ */
+fd_set tmpreadfds;
+fd_set tmpwritefds;
+
+static void select_update_selectfds(int fd, short event, PF * handler);
+
+/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
+/* Private functions */
+
+/*
+ * set and clear entries in the select array ..
+ */
+static void
+select_update_selectfds(int fd, short event, PF * handler)
+{
+       /* Update the read / write set */
+       if(event & COMM_SELECT_READ)
+       {
+               if(handler)
+                       FD_SET(fd, &select_readfds);
+               else
+                       FD_CLR(fd, &select_readfds);
+       }
+       if(event & COMM_SELECT_WRITE)
+       {
+               if(handler)
+                       FD_SET(fd, &select_writefds);
+               else
+                       FD_CLR(fd, &select_writefds);
+       }
+}
+
+
+/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
+/* Public functions */
+
+
+/*
+ * init_netio
+ *
+ * This is a needed exported function which will be called to initialise
+ * the network loop code.
+ */
+void
+init_netio(void)
+{
+       FD_ZERO(&select_readfds);
+       FD_ZERO(&select_writefds);
+}
+
+/*
+ * comm_setselect
+ *
+ * This is a needed exported function which will be called to register
+ * and deregister interest in a pending IO state for a given FD.
+ */
+void
+comm_setselect(int fd, fdlist_t list, unsigned int type, PF * handler,
+              void *client_data, time_t timeout)
+{
+       fde_t *F = &fd_table[fd];
+       s_assert(fd >= 0);
+       s_assert(F->flags.open);
+
+       if(type & COMM_SELECT_READ)
+       {
+               F->read_handler = handler;
+               F->read_data = client_data;
+               select_update_selectfds(fd, COMM_SELECT_READ, handler);
+       }
+       if(type & COMM_SELECT_WRITE)
+       {
+               F->write_handler = handler;
+               F->write_data = client_data;
+               select_update_selectfds(fd, COMM_SELECT_WRITE, handler);
+       }
+       if(timeout)
+               F->timeout = CurrentTime + (timeout / 1000);
+}
+
+/*
+ * Check all connections for new connections and input data that is to be
+ * processed. Also check for connections with data queued and whether we can
+ * write it out.
+ */
+
+/*
+ * comm_select
+ *
+ * Do IO events
+ */
+
+int
+comm_select(unsigned long delay)
+{
+       int num;
+       int fd;
+       PF *hdl;
+       fde_t *F;
+       struct timeval to;
+
+       /* Copy over the read/write sets so we don't have to rebuild em */
+       memcpy(&tmpreadfds, &select_readfds, sizeof(fd_set));
+       memcpy(&tmpwritefds, &select_writefds, sizeof(fd_set));
+
+       for (;;)
+       {
+               to.tv_sec = 0;
+               to.tv_usec = delay * 1000;
+               num = select(highest_fd + 1, &tmpreadfds, &tmpwritefds, NULL, &to);
+               if(num >= 0)
+                       break;
+               if(ignoreErrno(errno))
+                       continue;
+               set_time();
+               /* error! */
+               return -1;
+               /* NOTREACHED */
+       }
+       set_time();
+
+       if(num == 0)
+               return 0;
+
+       /* XXX we *could* optimise by falling out after doing num fds ... */
+       for (fd = 0; fd < highest_fd + 1; fd++)
+       {
+               F = &fd_table[fd];
+
+               if(FD_ISSET(fd, &tmpreadfds))
+               {
+                       hdl = F->read_handler;
+                       F->read_handler = NULL;
+                       if(hdl)
+                               hdl(fd, F->read_data);
+               }
+
+               if(F->flags.open == 0)
+                       continue;       /* Read handler closed us..go on */
+
+               if(FD_ISSET(fd, &tmpwritefds))
+               {
+                       hdl = F->write_handler;
+                       F->write_handler = NULL;
+                       if(hdl)
+                               hdl(fd, F->write_data);
+               }
+
+               if(F->read_handler == NULL)
+                       select_update_selectfds(fd, COMM_SELECT_READ, NULL);
+               if(F->write_handler == NULL)
+                       select_update_selectfds(fd, COMM_SELECT_WRITE, NULL);
+       }
+       return 0;
+}
+
diff --git a/libcharybdis/snprintf.c b/libcharybdis/snprintf.c
new file mode 100644 (file)
index 0000000..f71d5a6
--- /dev/null
@@ -0,0 +1,981 @@
+/*
+ * libString, Copyright (C) 1999 Patrick Alken
+ * This library comes with absolutely NO WARRANTY
+ *
+ * Should you choose to use and/or modify this source code, please
+ * do so under the terms of the GNU General Public License under which
+ * this library is distributed.
+ *
+ * $Id: snprintf.c 382 2005-12-07 15:15:59Z nenolod $
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <ctype.h>
+#include "setup.h"
+#include "sprintf_irc.h"
+
+/*
+ *  This table is arranged in chronological order from 0-999,
+ * however the numbers are written backwards, so the number 100
+ * is expressed in this table as "001".
+ *  It's purpose is to ensure fast conversions from integers to
+ * ASCII strings. When an integer variable is encountered, a
+ * simple hash algorithm is used to determine where to look
+ * in this array for the corresponding string.
+ *  This outperforms continually dividing by 10 and using the
+ * digit obtained as a character, because we can now divide by
+ * 1000 and use the remainder directly, thus cutting down on
+ * the number of costly divisions needed. For an integer's worst
+ * case, 2 divisions are needed because it can only go up to
+ * 32767, so after 2 divisions by 1000, and some algebra, we will
+ * be left with 327 which we can get from this table. This is much
+ * better than the 5 divisions by 10 that we would need if we did
+ * it the conventional way. Of course, if we made this table go
+ * from 0-9999, only 1 division would be needed.
+ *  Longs and unsigned ints of course, are another matter :-).
+ *
+ * Patrick Alken <wnder@underworld.net>
+ */
+
+/*
+ * Set this to the number of indices (numbers) in our table
+ */
+#define TABLE_MAX    1000
+
+static const char *IntTable[] = {
+       "000", "100", "200", "300", "400",
+       "500", "600", "700", "800", "900",
+       "010", "110", "210", "310", "410",
+       "510", "610", "710", "810", "910",
+       "020", "120", "220", "320", "420",
+       "520", "620", "720", "820", "920",
+       "030", "130", "230", "330", "430",
+       "530", "630", "730", "830", "930",
+       "040", "140", "240", "340", "440",
+       "540", "640", "740", "840", "940",
+       "050", "150", "250", "350", "450",
+       "550", "650", "750", "850", "950",
+       "060", "160", "260", "360", "460",
+       "560", "660", "760", "860", "960",
+       "070", "170", "270", "370", "470",
+       "570", "670", "770", "870", "970",
+       "080", "180", "280", "380", "480",
+       "580", "680", "780", "880", "980",
+       "090", "190", "290", "390", "490",
+       "590", "690", "790", "890", "990",
+       "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"
+};
+
+/*
+ * Since we calculate the right-most digits for %d %u etc first,
+ * we need a temporary buffer to store them in until we get
+ * to the left-most digits
+ */
+
+#define TEMPBUF_MAX  20
+
+static char TempBuffer[TEMPBUF_MAX];
+
+/*
+vSnprintf()
+ Backend to Snprintf() - performs the construction of 'dest'
+using the string 'format' and the given arguments. Also makes sure
+not more than 'bytes' characters are copied to 'dest'
+
+ We always allow room for a terminating \0 character, so at most,
+bytes - 1 characters will be written to dest.
+
+Return: Number of characters written, NOT including the terminating
+        \0 character which is *always* placed at the end of the string
+
+NOTE: This function handles the following flags only:
+        %s %d %c %u %ld %lu
+      In addition, this function performs *NO* precision, padding,
+      or width formatting. If it receives an unknown % character,
+      it will call vsprintf() to complete the remainder of the
+      string.
+*/
+
+int
+ircvsnprintf(char *dest, const size_t bytes, const char *format, va_list args)
+{
+       char ch;
+       int written = 0;        /* bytes written so far */
+       int maxbytes = bytes - 1;
+
+       while ((ch = *format++) && (written < maxbytes))
+       {
+               if(ch == '%')
+               {
+                       /*
+                        * Advance past the %
+                        */
+                       ch = *format++;
+
+                       /*
+                        * Put the most common cases first - %s %d etc
+                        */
+
+                       if(ch == 's')
+                       {
+                               const char *str = va_arg(args, const char *);
+
+                               while ((*dest = *str))
+                               {
+                                       ++dest;
+                                       ++str;
+
+                                       if(++written >= maxbytes)
+                                               break;
+                               }
+
+                               continue;
+                       }
+
+                       if(ch == 'd')
+                       {
+                               int num = va_arg(args, int);
+                               int quotient;
+                               const char *str;
+                               char *digitptr = TempBuffer;
+
+                               /*
+                                * We have to special-case "0" unfortunately
+                                */
+                               if(num == 0)
+                               {
+                                       *dest++ = '0';
+                                       ++written;
+                                       continue;
+                               }
+
+                               if(num < 0)
+                               {
+                                       *dest++ = '-';
+                                       if(++written >= maxbytes)
+                                               continue;
+
+                                       num = -num;
+                               }
+
+                               do
+                               {
+                                       quotient = num / TABLE_MAX;
+
+                                       /*
+                                        * We'll start with the right-most digits of 'num'.
+                                        * Dividing by TABLE_MAX cuts off all but the X
+                                        * right-most digits, where X is such that:
+                                        *
+                                        *     10^X = TABLE_MAX
+                                        *
+                                        * For example, if num = 1200, and TABLE_MAX = 1000,
+                                        * quotient will be 1. Multiplying this by 1000 and
+                                        * subtracting from 1200 gives: 1200 - (1 * 1000) = 200.
+                                        * We then go right to slot 200 in our array and behold!
+                                        * The string "002" (200 backwards) is conveniently
+                                        * waiting for us. Then repeat the process with the
+                                        * digits left.
+                                        *
+                                        * The reason we need to have the integers written
+                                        * backwards, is because we don't know how many digits
+                                        * there are. If we want to express the number 12130
+                                        * for example, our first pass would leave us with 130,
+                                        * whose slot in the array yields "031", which we
+                                        * plug into our TempBuffer[]. The next pass gives us
+                                        * 12, whose slot yields "21" which we append to
+                                        * TempBuffer[], leaving us with "03121". This is the
+                                        * exact number we want, only backwards, so it is
+                                        * a simple matter to reverse the string. If we used
+                                        * straightfoward numbers, we would have a TempBuffer
+                                        * looking like this: "13012" which would be a nightmare
+                                        * to deal with.
+                                        */
+
+                                       str = IntTable[num - (quotient * TABLE_MAX)];
+
+                                       while ((*digitptr = *str))
+                                       {
+                                               ++digitptr;
+                                               ++str;
+                                       }
+                               }
+                               while ((num = quotient) != 0);
+
+                               /*
+                                * If the last quotient was a 1 or 2 digit number, there
+                                * will be one or more leading zeroes in TempBuffer[] -
+                                * get rid of them.
+                                */
+                               while (*(digitptr - 1) == '0')
+                                       --digitptr;
+
+                               while (digitptr != TempBuffer)
+                               {
+                                       *dest++ = *--digitptr;
+                                       if(++written >= maxbytes)
+                                               break;
+                               }
+
+                               continue;
+                       }       /* if (ch == 'd') */
+
+                       if(ch == 'c')
+                       {
+                               *dest++ = va_arg(args, int);
+
+                               ++written;
+
+                               continue;
+                       }       /* if (ch == 'c') */
+
+                       if(ch == 'u')
+                       {
+                               unsigned int num = va_arg(args, unsigned int);
+                               unsigned int quotient;
+                               const char *str;
+                               char *digitptr = TempBuffer;
+
+                               if(num == 0)
+                               {
+                                       *dest++ = '0';
+                                       ++written;
+                                       continue;
+                               }
+
+                               do
+                               {
+                                       quotient = num / TABLE_MAX;
+
+                                       /*
+                                        * Very similar to case 'd'
+                                        */
+
+                                       str = IntTable[num - (quotient * TABLE_MAX)];
+
+                                       while ((*digitptr = *str))
+                                       {
+                                               ++digitptr;
+                                               ++str;
+                                       }
+                               }
+                               while ((num = quotient) != 0);
+
+                               while (*(digitptr - 1) == '0')
+                                       --digitptr;
+
+                               while (digitptr != TempBuffer)
+                               {
+                                       *dest++ = *--digitptr;
+                                       if(++written >= maxbytes)
+                                               break;
+                               }
+
+                               continue;
+                       }       /* if (ch == 'u') */
+
+                       if(ch == 'l')
+                       {
+                               if(*format == 'u')
+                               {
+                                       unsigned long num = va_arg(args, unsigned long);
+                                       unsigned long quotient;
+                                       const char *str;
+                                       char *digitptr = TempBuffer;
+
+                                       ++format;
+
+                                       if(num == 0)
+                                       {
+                                               *dest++ = '0';
+                                               ++written;
+                                               continue;
+                                       }
+
+                                       do
+                                       {
+                                               quotient = num / TABLE_MAX;
+
+                                               /*
+                                                * Very similar to case 'u'
+                                                */
+
+                                               str = IntTable[num - (quotient * TABLE_MAX)];
+
+                                               while ((*digitptr = *str))
+                                               {
+                                                       ++digitptr;
+                                                       ++str;
+                                               }
+                                       }
+                                       while ((num = quotient) != 0);
+
+                                       while (*(digitptr - 1) == '0')
+                                               --digitptr;
+
+                                       while (digitptr != TempBuffer)
+                                       {
+                                               *dest++ = *--digitptr;
+                                               if(++written >= maxbytes)
+                                                       break;
+                                       }
+
+                                       continue;
+                               } else  /* if (*format == 'u') */
+
+                               if(*format == 'd')
+                               {
+                                       long num = va_arg(args, long);
+                                       long quotient;
+                                       const char *str;
+                                       char *digitptr = TempBuffer;
+
+                                       ++format;
+
+                                       if(num == 0)
+                                       {
+                                               *dest++ = '0';
+                                               ++written;
+                                               continue;
+                                       }
+
+                                       if(num < 0)
+                                       {
+                                               *dest++ = '-';
+                                               if(++written >= maxbytes)
+                                                       continue;
+
+                                               num = -num;
+                                       }
+
+                                       do
+                                       {
+                                               quotient = num / TABLE_MAX;
+
+                                               str = IntTable[num - (quotient * TABLE_MAX)];
+
+                                               while ((*digitptr = *str))
+                                               {
+                                                       ++digitptr;
+                                                       ++str;
+                                               }
+                                       }
+                                       while ((num = quotient) != 0);
+
+                                       while (*(digitptr - 1) == '0')
+                                               --digitptr;
+
+                                       while (digitptr != TempBuffer)
+                                       {
+                                               *dest++ = *--digitptr;
+                                               if(++written >= maxbytes)
+                                                       break;
+                                       }
+
+                                       continue;
+                               } else  /* if (*format == 'd') */
+                               {
+                                       int ret;
+                                       format -= 2;
+                                       #ifdef HAVE_VSNPRINTF
+                                               ret = vsnprintf(dest, maxbytes - written, format, args);
+                                       #else
+                                               ret = vsprintf(dest, format, args);
+                                       #endif
+                                       dest += ret;
+                                       written += ret;
+                                       break;
+                               }
+                               
+                               
+                       }       /* if (ch == 'l') */
+
+                       if(ch != '%')
+                       {
+                               int ret;
+
+                               /*
+                                * The character might be invalid, or be a precision, 
+                                * padding, or width specification - call vsprintf()
+                                * to finish off the string
+                                */
+
+                               format -= 2;
+                                #ifdef HAVE_VSNPRINTF
+                                       ret = vsnprintf(dest, maxbytes - written, format, args);
+                                #else
+                                       ret = vsprintf(dest, format, args);
+                               #endif
+                               dest += ret;
+                               written += ret;
+
+                               break;
+                       }       /* if (ch != '%') */
+               }               /* if (ch == '%') */
+
+               *dest++ = ch;
+               ++written;
+       }                       /* while ((ch = *format++) && (written < maxbytes)) */
+
+       /*
+        * Terminate the destination buffer with a \0
+        */
+       *dest = '\0';
+
+       return (written);
+}                              /* vSnprintf() */
+
+/*
+ircvsprintf()
+ Backend to Sprintf() - performs the construction of 'dest'
+using the string 'format' and the given arguments.
+
+ We always place a \0 character onto the end of 'dest'.
+
+Return: Number of characters written, NOT including the terminating
+        \0 character which is *always* placed at the end of the string
+
+NOTE: This function handles the following flags only:
+        %s %d %c %u %ld %lu
+      In addition, this function performs *NO* precision, padding,
+      or width formatting. If it receives an unknown % character,
+      it will call vsprintf() to complete the remainder of the
+      string.
+*/
+
+int
+ircvsprintf(char *dest, const char *format, va_list args)
+{
+       char ch;
+       int written = 0;        /* bytes written so far */
+
+       while ((ch = *format++))
+       {
+               if(ch == '%')
+               {
+                       /*
+                        * Advance past the %
+                        */
+                       ch = *format++;
+
+                       /*
+                        * Put the most common cases first - %s %d etc
+                        */
+
+                       if(ch == 's')
+                       {
+                               const char *str = va_arg(args, const char *);
+
+                               while ((*dest = *str))
+                               {
+                                       ++dest;
+                                       ++str;
+
+                                       ++written;
+                               }
+
+                               continue;
+                       }       /* if (ch == 's') */
+                       
+                       
+                       if(ch == 'd')
+                       {
+                               int num = va_arg(args, int);
+                               int quotient;
+                               const char *str;
+                               char *digitptr = TempBuffer;
+
+                               /*
+                                * We have to special-case "0" unfortunately
+                                */
+                               if(num == 0)
+                               {
+                                       *dest++ = '0';
+                                       ++written;
+                                       continue;
+                               }
+
+                               if(num < 0)
+                               {
+                                       *dest++ = '-';
+                                       ++written;
+
+                                       num = -num;
+                               }
+
+                               do
+                               {
+                                       quotient = num / TABLE_MAX;
+
+                                       /*
+                                        * We'll start with the right-most digits of 'num'.
+                                        * Dividing by TABLE_MAX cuts off all but the X
+                                        * right-most digits, where X is such that:
+                                        *
+                                        *     10^X = TABLE_MAX
+                                        *
+                                        * For example, if num = 1200, and TABLE_MAX = 1000,
+                                        * quotient will be 1. Multiplying this by 1000 and
+                                        * subtracting from 1200 gives: 1200 - (1 * 1000) = 200.
+                                        * We then go right to slot 200 in our array and behold!
+                                        * The string "002" (200 backwards) is conveniently
+                                        * waiting for us. Then repeat the process with the
+                                        * digits left.
+                                        *
+                                        * The reason we need to have the integers written
+                                        * backwards, is because we don't know how many digits
+                                        * there are. If we want to express the number 12130
+                                        * for example, our first pass would leave us with 130,
+                                        * whose slot in the array yields "031", which we
+                                        * plug into our TempBuffer[]. The next pass gives us
+                                        * 12, whose slot yields "21" which we append to
+                                        * TempBuffer[], leaving us with "03121". This is the
+                                        * exact number we want, only backwards, so it is
+                                        * a simple matter to reverse the string. If we used
+                                        * straightfoward numbers, we would have a TempBuffer
+                                        * looking like this: "13012" which would be a nightmare
+                                        * to deal with.
+                                        */
+
+                                       str = IntTable[num - (quotient * TABLE_MAX)];
+
+                                       while ((*digitptr = *str))
+                                       {
+                                               ++digitptr;
+                                               ++str;
+                                       }
+                               }
+                               while ((num = quotient) != 0);
+
+                               /*
+                                * If the last quotient was a 1 or 2 digit number, there
+                                * will be one or more leading zeroes in TempBuffer[] -
+                                * get rid of them.
+                                */
+                               while (*(digitptr - 1) == '0')
+                                       --digitptr;
+
+                               while (digitptr != TempBuffer)
+                               {
+                                       *dest++ = *--digitptr;
+                                       ++written;
+                               }
+
+                               continue;
+                       }       /* if (ch == 'd') */
+
+                       if(ch == 'c')
+                       {
+                               *dest++ = va_arg(args, int);
+
+                               ++written;
+
+                               continue;
+                       }       /* if (ch == 'c') */
+
+                       if(ch == 'u')
+                       {
+                               unsigned int num = va_arg(args, unsigned int);
+                               unsigned int quotient;
+                               const char *str;
+                               char *digitptr = TempBuffer;
+
+                               if(num == 0)
+                               {
+                                       *dest++ = '0';
+                                       ++written;
+                                       continue;
+                               }
+
+                               do
+                               {
+                                       quotient = num / TABLE_MAX;
+
+                                       /*
+                                        * Very similar to case 'd'
+                                        */
+
+                                       str = IntTable[num - (quotient * TABLE_MAX)];
+
+                                       while ((*digitptr = *str))
+                                       {
+                                               ++digitptr;
+                                               ++str;
+                                       }
+                               }
+                               while ((num = quotient) != 0);
+
+                               while (*(digitptr - 1) == '0')
+                                       --digitptr;
+
+                               while (digitptr != TempBuffer)
+                               {
+                                       *dest++ = *--digitptr;
+                                       ++written;
+                               }
+
+                               continue;
+                       }       /* if (ch == 'u') */
+
+                       if(ch == 'l')
+                       {
+                               if(*format == 'u')
+                               {
+                                       unsigned long num = va_arg(args, unsigned long);
+                                       unsigned long quotient;
+                                       const char *str;
+                                       char *digitptr = TempBuffer;
+
+                                       ++format;
+
+                                       if(num == 0)
+                                       {
+                                               *dest++ = '0';
+                                               ++written;
+                                               continue;
+                                       }
+
+                                       do
+                                       {
+                                               quotient = num / TABLE_MAX;
+
+                                               /*
+                                                * Very similar to case 'u'
+                                                */
+
+                                               str = IntTable[num - (quotient * TABLE_MAX)];
+
+                                               while ((*digitptr = *str))
+                                               {
+                                                       ++digitptr;
+                                                       ++str;
+                                               }
+                                       }
+                                       while ((num = quotient) != 0);
+
+                                       while (*(digitptr - 1) == '0')
+                                               --digitptr;
+
+                                       while (digitptr != TempBuffer)
+                                       {
+                                               *dest++ = *--digitptr;
+                                               ++written;
+                                       }
+
+                                       continue;
+                               }       /* if (*format == 'u') */
+
+                               if(*format == 'd')
+                               {
+                                       long num = va_arg(args, long);
+                                       long quotient;
+                                       const char *str;
+                                       char *digitptr = TempBuffer;
+
+                                       ++format;
+
+                                       if(num == 0)
+                                       {
+                                               *dest++ = '0';
+                                               ++written;
+                                               continue;
+                                       }
+
+                                       if(num < 0)
+                                       {
+                                               *dest++ = '-';
+                                               ++written;
+
+                                               num = -num;
+                                       }
+
+                                       do
+                                       {
+                                               quotient = num / TABLE_MAX;
+
+                                               str = IntTable[num - (quotient * TABLE_MAX)];
+
+                                               while ((*digitptr = *str))
+                                               {
+                                                       ++digitptr;
+                                                       ++str;
+                                               }
+                                       }
+                                       while ((num = quotient) != 0);
+
+                                       while (*(digitptr - 1) == '0')
+                                               --digitptr;
+
+                                       while (digitptr != TempBuffer)
+                                       {
+                                               *dest++ = *--digitptr;
+                                               ++written;
+                                       }
+
+                                       continue;
+                               }       /* if (*format == 'd') */
+
+                               continue;
+                       }       /* if (ch == 'l') */
+
+                       if(ch != '%')
+                       {
+                               int ret;
+
+                               format -= 2;
+                               ret = vsprintf(dest, format, args);
+                               dest += ret;
+                               written += ret;
+
+                               break;
+                       }       /* if (ch != '%') */
+               }               /* if (ch == '%') */
+
+               *dest++ = ch;
+               ++written;
+       }                       /* while ((ch = *format++)) */
+
+       /*
+        * Terminate the destination buffer with a \0
+        */
+       *dest = '\0';
+
+       return (written);
+}                              /* vSprintf() */
+
+/*
+ircsnprintf()
+ Optimized version of snprintf().
+
+Inputs: dest   - destination string
+        bytes  - number of bytes to copy
+        format - formatted string
+        args   - args to 'format'
+
+Return: number of characters copied, NOT including the terminating
+        NULL which is always placed at the end of the string
+*/
+
+int
+ircsnprintf(char *dest, const size_t bytes, const char *format, ...)
+{
+       va_list args;
+       int count;
+
+       va_start(args, format);
+
+       count = ircvsnprintf(dest, bytes, format, args);
+
+       va_end(args);
+
+       return (count);
+}                              /* Snprintf() */
+
+/*
+ircsprintf()
+ Optimized version of sprintf()
+
+Inputs: dest   - destination string
+        format - formatted string
+        args   - arguments to 'format'
+
+Return: number of characters copied, NOT including the terminating
+        NULL which is always placed at the end of the string
+*/
+
+int
+ircsprintf(char *dest, const char *format, ...)
+{
+       va_list args;
+       int count;
+
+       va_start(args, format);
+
+       count = ircvsprintf(dest, format, args);
+
+       va_end(args);
+
+       return (count);
+}                              /* Sprintf() */
diff --git a/libcharybdis/tools.c b/libcharybdis/tools.c
new file mode 100644 (file)
index 0000000..b6e15db
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  tools.c: Various functions needed here and there.
+ *
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: tools.c 1110 2006-03-29 22:55:25Z nenolod $
+ *
+ *  Here is the original header:
+ *
+ *  Useful stuff, ripped from places ..
+ *  adrian chadd <adrian@creative.net.au>
+ *
+ * When you update these functions make sure you update the ones in tools.h
+ * as well!!!
+ */
+
+#include "stdinc.h"
+#define TOOLS_C
+#include "tools.h"
+#include "balloc.h"
+#include "s_user.h"
+
+#ifndef NDEBUG
+/*
+ * frob some memory. debugging time.
+ * -- adrian
+ */
+void
+mem_frob(void *data, int len)
+{
+       unsigned long x = 0xdeadbeef;
+       unsigned char *b = (unsigned char *)&x;
+       int i;
+       char *cdata = data;
+       for (i = 0; i < len; i++)
+       {
+               *cdata = b[i % 4];
+               cdata++;
+       }
+}
+#endif
+
+/*
+ * init_dlink_nodes
+ *
+ */
+extern BlockHeap *dnode_heap;
+void
+init_dlink_nodes(void)
+{
+       dnode_heap = BlockHeapCreate(sizeof(dlink_node), DNODE_HEAP_SIZE);
+       if(dnode_heap == NULL)
+               outofmemory();
+}
+
+/*
+ * make_dlink_node
+ *
+ * inputs      - NONE
+ * output      - pointer to new dlink_node
+ * side effects        - NONE
+ */
+dlink_node *
+make_dlink_node(void)
+{
+       return(BlockHeapAlloc(dnode_heap));
+}
+
+/*
+ * free_dlink_node
+ *
+ * inputs      - pointer to dlink_node
+ * output      - NONE
+ * side effects        - free given dlink_node 
+ */
+void
+free_dlink_node(dlink_node * ptr)
+{
+       assert(ptr != NULL);
+
+       BlockHeapFree(dnode_heap, ptr);
+}
+
+/*
+ * find_umode_slot
+ *
+ * inputs       - NONE
+ * outputs      - an available umode bitmask or
+ *                0 if no umodes are available
+ * side effects - NONE
+ */
+unsigned int
+find_umode_slot(void)
+{
+       unsigned int all_umodes = 0, my_umode = 0, i;
+
+       for (i = 0; i < 128; i++)
+               all_umodes |= user_modes[i];
+
+       for (my_umode = 1; my_umode && (all_umodes & my_umode);
+               my_umode <<= 1);
+
+       return my_umode;
+}
diff --git a/libcharybdis/tools.h b/libcharybdis/tools.h
new file mode 100644 (file)
index 0000000..0d8dcdd
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  tools.h: Header for the various tool functions.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development 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: tools.h 382 2005-12-07 15:15:59Z nenolod $
+ */
+
+#ifndef __TOOLS_H__
+#define __TOOLS_H__
+
+
+/*
+ * double-linked-list stuff
+ */
+typedef struct _dlink_node dlink_node;
+typedef struct _dlink_list dlink_list;
+
+struct _dlink_node
+{
+       void *data;
+       dlink_node *prev;
+       dlink_node *next;
+
+};
+
+struct _dlink_list
+{
+       dlink_node *head;
+       dlink_node *tail;
+       unsigned long length;
+};
+
+dlink_node *make_dlink_node(void);
+void free_dlink_node(dlink_node * lp);
+void init_dlink_nodes(void);
+
+#ifndef NDEBUG
+void mem_frob(void *data, int len);
+#else
+#define mem_frob(x, y)
+#endif
+
+/* This macros are basically swiped from the linux kernel
+ * they are simple yet effective
+ */
+
+/*
+ * Walks forward of a list.  
+ * pos is your node
+ * head is your list head
+ */
+#define DLINK_FOREACH(pos, head) for (pos = (head); pos != NULL; pos = pos->next)
+
+/*
+ * Walks forward of a list safely while removing nodes 
+ * pos is your node
+ * n is another list head for temporary storage
+ * head is your list head
+ */
+#define DLINK_FOREACH_SAFE(pos, n, head) for (pos = (head), n = pos ? pos->next : NULL; pos != NULL; pos = n, n = pos ? pos->next : NULL)
+
+#define DLINK_FOREACH_PREV(pos, head) for (pos = (head); pos != NULL; pos = pos->prev)
+
+
+/* Returns the list length */
+#define dlink_list_length(list) (list)->length
+#define dlink_move_list(oldlist, newlist, node)
+
+#define dlinkAddAlloc(data, list) dlinkAdd(data, make_dlink_node(), list)
+#define dlinkAddTailAlloc(data, list) dlinkAddTail(data, make_dlink_node(), list)
+#define dlinkDestroy(node, list) do { dlinkDelete(node, list); free_dlink_node(node); } while(0)
+
+
+/*
+ * The functions below are included for the sake of inlining
+ * hopefully this will speed up things just a bit
+ * 
+ */
+
+/* 
+ * dlink_ routines are stolen from squid, except for dlinkAddBefore,
+ * which is mine.
+ *   -- adrian
+ */
+
+/* I hate C sometimes */
+#if defined __OPTIMIZE__ && !defined __OPTIMIZE_SIZE__ && !defined __NO_INLINE__
+#define INLINE_FUNC extern inline
+#define NEED_INLINES
+#else
+#undef INLINE_FUNC
+#define INLINE_FUNC
+#endif
+
+#ifdef TOOLS_C
+#undef INLINE_FUNC
+#define INLINE_FUNC
+#endif 
+    
+void dlinkMoveNode(dlink_node * m, dlink_list * oldlist, dlink_list * newlist);
+void dlinkAdd(void *data, dlink_node * m, dlink_list * list);
+void dlinkAddBefore(dlink_node * b, void *data, dlink_node * m, dlink_list * list);
+void dlinkMoveTail(dlink_node *m, dlink_list *list);
+void dlinkAddTail(void *data, dlink_node * m, dlink_list * list);
+void dlinkDelete(dlink_node * m, dlink_list * list);
+dlink_node *dlinkFindDelete(void *data, dlink_list *list);
+int dlinkFindDestroy(void *data, dlink_list *list);
+dlink_node *dlinkFind(void *data, dlink_list *list);
+void dlinkMoveList(dlink_list * from, dlink_list * to);
+unsigned int find_umode_slot(void);
+
+#if defined(NEED_INLINES) || defined(TOOLS_C)
+INLINE_FUNC void
+dlinkMoveNode(dlink_node * m, dlink_list * oldlist, dlink_list * newlist)
+{
+       /* Assumption: If m->next == NULL, then list->tail == m
+        *      and:   If m->prev == NULL, then list->head == m
+        */
+       assert(m != NULL);
+       assert(oldlist != NULL);
+       assert(newlist != NULL);
+
+       if(m->next)
+               m->next->prev = m->prev;
+       else
+               oldlist->tail = m->prev;
+
+       if(m->prev)
+               m->prev->next = m->next;
+       else
+               oldlist->head = m->next;
+
+       m->prev = NULL;
+       m->next = newlist->head;
+       if(newlist->head != NULL)
+               newlist->head->prev = m;
+       else if(newlist->tail == NULL)
+               newlist->tail = m;
+       newlist->head = m;
+
+       oldlist->length--;
+       newlist->length++;
+}
+
+INLINE_FUNC void
+dlinkAdd(void *data, dlink_node * m, dlink_list * list)
+{
+       assert(data != NULL);
+       assert(m != NULL);
+       assert(list != NULL);
+       m->data = data;
+       m->prev = NULL;
+       m->next = list->head;
+
+       /* Assumption: If list->tail != NULL, list->head != NULL */
+       if(list->head != NULL)
+               list->head->prev = m;
+       else if(list->tail == NULL)
+               list->tail = m;
+
+       list->head = m;
+       list->length++;
+}
+
+INLINE_FUNC void
+dlinkAddBefore(dlink_node * b, void *data, dlink_node * m, dlink_list * list)
+{
+       assert(b != NULL);
+       assert(data != NULL);
+       assert(m != NULL);
+       assert(list != NULL);
+
+       /* Shortcut - if its the first one, call dlinkAdd only */
+       if(b == list->head)
+       {
+               dlinkAdd(data, m, list);
+       }
+       else
+       {
+               m->data = data;
+               b->prev->next = m;
+               m->prev = b->prev;
+               b->prev = m;
+               m->next = b;
+               list->length++;
+       }
+}
+
+INLINE_FUNC void
+dlinkMoveTail(dlink_node *m, dlink_list *list)
+{
+       if(list->tail == m)
+               return;
+       
+       /* From here assume that m->next != NULL as that can only 
+        * be at the tail and assume that the node is on the list
+        */
+       
+       m->next->prev = m->prev;
+
+       if(m->prev != NULL)
+               m->prev->next = m->next;
+       else
+               list->head = m->next;
+
+       list->tail->next = m;
+       m->prev = list->tail;
+       m->next = NULL;
+       list->tail = m;
+}
+
+INLINE_FUNC void
+dlinkAddTail(void *data, dlink_node * m, dlink_list * list)
+{
+       assert(m != NULL);
+       assert(list != NULL);
+       assert(data != NULL);
+       m->data = data;
+       m->next = NULL;
+       m->prev = list->tail;
+
+       /* Assumption: If list->tail != NULL, list->head != NULL */
+       if(list->tail != NULL)
+               list->tail->next = m;
+       else if(list->head == NULL)
+               list->head = m;
+
+       list->tail = m;
+       list->length++;
+}
+
+/* Execution profiles show that this function is called the most
+ * often of all non-spontaneous functions. So it had better be
+ * efficient. */
+INLINE_FUNC void
+dlinkDelete(dlink_node * m, dlink_list * list)
+{
+       assert(m != NULL);
+       assert(list != NULL);
+
+       /* Assumption: If m->next == NULL, then list->tail == m
+        *      and:   If m->prev == NULL, then list->head == m
+        */
+       if(m->next)
+               m->next->prev = m->prev;
+       else
+               list->tail = m->prev;
+
+       if(m->prev)
+               m->prev->next = m->next;
+       else
+               list->head = m->next;
+
+       m->next = m->prev = NULL;
+       list->length--;
+}
+
+INLINE_FUNC dlink_node *
+dlinkFindDelete(void *data, dlink_list *list)
+{
+       dlink_node *m;
+       assert(list != NULL);
+       assert(data != NULL);
+
+       DLINK_FOREACH(m, list->head)
+       {
+               if(m->data != data)
+                       continue;
+
+               if(m->next)
+                       m->next->prev = m->prev;
+               else
+                       list->tail = m->prev;
+
+               if(m->prev)
+                       m->prev->next = m->next;
+               else
+                       list->head = m->next;
+
+               m->next = m->prev = NULL;
+               list->length--;
+               return m;
+       }
+
+       return NULL;
+}
+
+INLINE_FUNC int
+dlinkFindDestroy(void *data, dlink_list *list)
+{
+       void *ptr;
+
+       assert(list != NULL);
+       assert(data != NULL);
+
+       ptr = dlinkFindDelete(data, list);
+
+       if(ptr != NULL)
+       {
+               free_dlink_node(ptr);
+               return 1;
+       }
+       return 0;
+}
+
+/*
+ * dlinkFind
+ * inputs      - list to search 
+ *             - data
+ * output      - pointer to link or NULL if not found
+ * side effects        - Look for ptr in the linked listed pointed to by link.
+ */
+INLINE_FUNC dlink_node *
+dlinkFind(void *data, dlink_list *list)
+{
+       dlink_node *ptr;
+       assert(list != NULL);
+       assert(data != NULL);
+
+       DLINK_FOREACH(ptr, list->head)
+       {
+               if(ptr->data == data)
+                       return (ptr);
+       }
+       return (NULL);
+}
+
+INLINE_FUNC void
+dlinkMoveList(dlink_list * from, dlink_list * to)
+{
+       assert(from != NULL);
+       assert(to != NULL);
+
+       /* There are three cases */
+       /* case one, nothing in from list */
+       if(from->head == NULL)
+               return;
+
+       /* case two, nothing in to list */
+       if(to->head == NULL)
+       {
+               to->head = from->head;
+               to->tail = from->tail;
+               from->head = from->tail = NULL;
+               to->length = from->length;
+               from->length = 0;
+               return;
+       }
+
+       /* third case play with the links */
+       from->tail->next = to->head;
+       to->head->prev = from->tail;
+       to->head = from->head;
+       from->head = from->tail = NULL;
+       to->length += from->length;
+       from->length = 0;
+}
+#endif
+
+#endif /* __TOOLS_H__ */
diff --git a/modules/.cvsignore b/modules/.cvsignore
new file mode 100644 (file)
index 0000000..2d2cb41
--- /dev/null
@@ -0,0 +1,2 @@
+Makefile
+static_modules.c
\ No newline at end of file
diff --git a/modules/.depend b/modules/.depend
new file mode 100644 (file)
index 0000000..ec042c8
--- /dev/null
@@ -0,0 +1,1101 @@
+core/m_die.so: core/m_die.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/client.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../libcharybdis/linebuf.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/res.h ../include/snomask.h \
+  ../include/client.h ../include/ircd.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/irc_string.h ../include/numeric.h ../libcharybdis/commio.h \
+  ../include/config.h ../include/s_log.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/send.h ../include/msg.h ../include/parse.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../include/hook.h ../include/s_newconf.h
+m_error.so: core/m_error.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/common.h ../include/ircd.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/numeric.h \
+  ../include/send.h ../include/msg.h ../libcharybdis/memory.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../include/hook.h ../include/s_log.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h
+m_join.so: core/m_join.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../include/client.h ../libcharybdis/linebuf.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/res.h \
+  ../include/snomask.h ../include/client.h ../include/common.h \
+  ../include/hash.h ../libcharybdis/tools.h ../include/irc_string.h \
+  ../include/ircd.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/setup.h ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/numeric.h ../include/send.h ../include/s_serv.h \
+  ../include/s_conf.h ../include/class.h ../include/common.h \
+  ../include/patricia.h ../include/irc_string.h ../include/ircd.h \
+  ../include/numeric.h ../include/s_newconf.h ../include/msg.h \
+  ../include/parse.h ../include/modules.h ../include/parse.h \
+  ../include/msg.h ../include/hook.h ../include/sprintf_irc.h \
+  ../include/packet.h
+core/m_kick.so: core/m_kick.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../include/client.h ../libcharybdis/linebuf.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/res.h \
+  ../include/snomask.h ../include/client.h ../include/irc_string.h \
+  ../include/ircd.h ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/numeric.h ../include/send.h \
+  ../include/msg.h ../include/modules.h ../include/parse.h \
+  ../include/msg.h ../include/hook.h ../include/parse.h ../include/hash.h \
+  ../include/packet.h ../include/s_serv.h
+core/m_kill.so: core/m_kill.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/hash.h ../libcharybdis/tools.h ../include/ircd.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/numeric.h \
+  ../include/sprintf_irc.h ../include/s_log.h ../include/s_serv.h \
+  ../include/s_conf.h ../include/class.h ../include/common.h \
+  ../include/patricia.h ../include/irc_string.h ../include/ircd.h \
+  ../include/numeric.h ../include/send.h ../include/whowas.h \
+  ../include/irc_string.h ../include/msg.h ../include/parse.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../include/hook.h ../include/s_newconf.h
+core/m_message.so: core/m_message.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/ircd.h ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/numeric.h ../include/common.h \
+  ../include/s_conf.h ../include/class.h ../include/common.h \
+  ../include/patricia.h ../include/irc_string.h ../include/ircd.h \
+  ../include/numeric.h ../include/s_serv.h ../include/msg.h \
+  ../include/parse.h ../include/modules.h ../include/parse.h \
+  ../include/msg.h ../include/hook.h ../include/channel.h \
+  ../include/irc_string.h ../include/hash.h ../include/class.h \
+  ../include/packet.h ../include/send.h ../libcharybdis/event.h \
+  ../include/patricia.h ../include/s_newconf.h
+core/m_mode.so: core/m_mode.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../libcharybdis/balloc.h ../include/setup.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/ircd_defs.h ../include/send.h ../libcharybdis/balloc.h \
+  ../include/channel.h ../include/client.h ../libcharybdis/linebuf.h \
+  ../include/channel.h ../include/res.h ../include/snomask.h \
+  ../include/client.h ../include/hash.h ../libcharybdis/tools.h \
+  ../include/irc_string.h ../include/ircd.h ../libcharybdis/memory.h \
+  ../include/numeric.h ../include/s_user.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/s_serv.h ../include/s_log.h ../include/send.h \
+  ../include/msg.h ../include/parse.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h \
+  ../include/packet.h ../include/sprintf_irc.h ../include/s_newconf.h
+core/m_nick.so: core/m_nick.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/hash.h ../libcharybdis/tools.h ../include/irc_string.h \
+  ../include/ircd.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/setup.h ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/numeric.h ../include/s_conf.h ../include/class.h \
+  ../include/common.h ../include/patricia.h ../include/irc_string.h \
+  ../include/ircd.h ../include/numeric.h ../include/s_stats.h \
+  ../include/s_user.h ../include/whowas.h ../include/s_serv.h \
+  ../include/send.h ../include/channel.h ../include/s_log.h \
+  ../include/msg.h ../include/parse.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h \
+  ../include/common.h ../include/packet.h ../include/scache.h \
+  ../include/s_newconf.h ../include/monitor.h
+core/m_part.so: core/m_part.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../include/client.h ../libcharybdis/linebuf.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/res.h \
+  ../include/snomask.h ../include/client.h ../include/common.h \
+  ../include/hash.h ../libcharybdis/tools.h ../include/irc_string.h \
+  ../include/ircd.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/setup.h ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/numeric.h ../include/send.h ../include/s_serv.h \
+  ../include/msg.h ../include/parse.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h \
+  ../include/s_conf.h ../include/class.h ../include/common.h \
+  ../include/patricia.h ../include/irc_string.h ../include/ircd.h \
+  ../include/numeric.h ../include/packet.h
+core/m_quit.so: core/m_quit.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/ircd.h ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/numeric.h ../include/s_serv.h \
+  ../include/send.h ../include/msg.h ../include/parse.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../include/hook.h ../include/s_conf.h ../include/class.h \
+  ../include/common.h ../include/patricia.h ../include/irc_string.h \
+  ../include/ircd.h ../include/numeric.h ../include/sprintf_irc.h
+core/m_server.so: core/m_server.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/client.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../libcharybdis/linebuf.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/res.h ../include/snomask.h \
+  ../include/client.h ../include/common.h ../libcharybdis/event.h \
+  ../include/hash.h ../libcharybdis/tools.h ../include/irc_string.h \
+  ../include/ircd.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/setup.h ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/numeric.h ../include/s_conf.h ../include/class.h \
+  ../include/common.h ../include/patricia.h ../include/irc_string.h \
+  ../include/ircd.h ../include/numeric.h ../include/s_newconf.h \
+  ../include/s_log.h ../include/s_serv.h ../include/s_stats.h \
+  ../include/scache.h ../include/send.h ../include/msg.h \
+  ../include/parse.h ../include/modules.h ../include/parse.h \
+  ../include/msg.h ../include/hook.h
+core/m_sjoin.so: core/m_sjoin.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../include/client.h ../libcharybdis/linebuf.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/res.h \
+  ../include/snomask.h ../include/client.h ../include/hash.h \
+  ../libcharybdis/tools.h ../include/irc_string.h \
+  ../include/sprintf_irc.h ../include/ircd.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/numeric.h ../include/send.h \
+  ../include/common.h ../include/msg.h ../include/parse.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../include/hook.h ../include/s_serv.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h
+core/m_squit.so: core/m_squit.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/common.h ../include/irc_string.h ../include/ircd.h \
+  ../libcharybdis/tools.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/setup.h ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/numeric.h ../include/s_conf.h ../include/class.h \
+  ../include/common.h ../include/patricia.h ../include/irc_string.h \
+  ../include/ircd.h ../include/numeric.h ../include/s_log.h \
+  ../include/s_serv.h ../include/send.h ../include/msg.h \
+  ../include/parse.h ../include/modules.h ../include/parse.h \
+  ../include/msg.h ../include/hook.h ../include/hash.h \
+  ../include/s_newconf.h
+m_accept.so: m_accept.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/hash.h ../libcharybdis/tools.h ../include/ircd.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/numeric.h \
+  ../include/s_conf.h ../include/class.h ../include/common.h \
+  ../include/patricia.h ../include/irc_string.h ../include/ircd.h \
+  ../include/numeric.h ../include/s_serv.h ../include/send.h \
+  ../include/msg.h ../include/parse.h ../include/sprintf_irc.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../include/hook.h
+m_admin.so: m_admin.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/ircd.h ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/numeric.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/s_serv.h ../include/send.h ../include/msg.h \
+  ../include/parse.h ../include/hook.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h
+m_away.so: m_away.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/irc_string.h ../include/ircd.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/numeric.h \
+  ../include/send.h ../include/msg.h ../include/parse.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../include/hook.h ../include/s_conf.h ../include/class.h \
+  ../include/common.h ../include/patricia.h ../include/irc_string.h \
+  ../include/ircd.h ../include/numeric.h ../include/s_serv.h \
+  ../include/packet.h
+m_cap.so: m_cap.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/class.h ../libcharybdis/tools.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/irc_string.h ../include/ircd.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/numeric.h ../include/msg.h \
+  ../include/parse.h ../include/modules.h ../include/parse.h \
+  ../include/msg.h ../include/hook.h ../include/s_serv.h \
+  ../include/s_user.h
+m_capab.so: m_capab.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/irc_string.h ../include/s_serv.h ../include/s_conf.h \
+  ../include/class.h ../libcharybdis/tools.h ../include/common.h \
+  ../include/patricia.h ../include/irc_string.h ../include/ircd.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/numeric.h \
+  ../include/msg.h ../include/parse.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h
+m_challenge.so: m_challenge.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/ircd_defs.h \
+  ../include/send.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/tools.h ../libcharybdis/memory.h ../include/client.h \
+  ../libcharybdis/linebuf.h ../include/channel.h ../include/res.h \
+  ../include/snomask.h ../include/client.h ../include/ircd.h \
+  ../libcharybdis/tools.h ../libcharybdis/memory.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h \
+  ../include/numeric.h ../include/send.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/msg.h ../include/parse.h ../include/irc_string.h \
+  ../include/s_log.h ../include/s_user.h ../include/cache.h \
+  ../include/s_newconf.h
+m_chghost.so: m_chghost.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/send.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../include/channel.h ../include/client.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/common.h ../include/config.h ../include/ircd.h \
+  ../libcharybdis/tools.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/setup.h ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/numeric.h ../libcharybdis/memory.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/s_newconf.h ../include/s_serv.h ../include/hash.h \
+  ../include/msg.h ../include/parse.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h \
+  ../include/sprintf_irc.h ../include/whowas.h ../include/monitor.h
+m_close.so: m_close.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/client.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../libcharybdis/linebuf.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/res.h ../include/snomask.h \
+  ../include/client.h ../include/ircd.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/numeric.h \
+  ../libcharybdis/commio.h ../include/config.h ../include/send.h \
+  ../include/msg.h ../include/parse.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h
+m_cmessage.so: m_cmessage.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/channel.h ../include/numeric.h ../include/msg.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/hook.h \
+  ../include/hash.h ../libcharybdis/tools.h ../include/send.h \
+  ../include/s_conf.h ../include/class.h ../include/common.h \
+  ../include/patricia.h ../include/irc_string.h ../include/ircd.h \
+  ../include/numeric.h
+m_connect.so: m_connect.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/ircd.h ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/irc_string.h ../include/numeric.h \
+  ../libcharybdis/commio.h ../include/config.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/s_newconf.h ../include/s_log.h ../include/s_serv.h \
+  ../include/send.h ../include/msg.h ../include/parse.h ../include/hash.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../include/hook.h
+m_dline.so: m_dline.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../include/class.h ../libcharybdis/tools.h \
+  ../include/client.h ../libcharybdis/linebuf.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/res.h ../include/snomask.h \
+  ../include/client.h ../include/common.h ../include/irc_string.h \
+  ../include/sprintf_irc.h ../include/ircd.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/hostmask.h ../include/numeric.h \
+  ../libcharybdis/commio.h ../include/config.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/s_newconf.h ../include/s_log.h ../include/send.h \
+  ../include/hash.h ../include/s_serv.h ../include/msg.h \
+  ../include/parse.h ../include/modules.h ../include/parse.h \
+  ../include/msg.h ../include/hook.h
+m_encap.so: m_encap.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/send.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../include/channel.h ../include/client.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/common.h ../include/config.h ../include/ircd.h \
+  ../libcharybdis/tools.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/setup.h ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/numeric.h ../libcharybdis/memory.h ../include/s_serv.h \
+  ../include/hash.h ../include/msg.h ../include/parse.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../include/hook.h ../include/sprintf_irc.h
+m_etrace.so: m_etrace.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/class.h \
+  ../libcharybdis/tools.h ../include/hook.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/hash.h ../include/common.h ../include/irc_string.h \
+  ../include/ircd.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/setup.h ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/numeric.h ../libcharybdis/commio.h ../include/config.h \
+  ../include/s_serv.h ../include/s_conf.h ../include/class.h \
+  ../include/common.h ../include/patricia.h ../include/irc_string.h \
+  ../include/ircd.h ../include/numeric.h ../include/s_newconf.h \
+  ../include/send.h ../include/msg.h ../include/parse.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../include/hook.h
+m_gline.so: m_gline.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/s_gline.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../include/channel.h ../include/client.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/common.h ../include/config.h ../include/irc_string.h \
+  ../include/sprintf_irc.h ../include/ircd.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/hostmask.h \
+  ../include/numeric.h ../libcharybdis/commio.h ../include/config.h \
+  ../include/s_conf.h ../include/class.h ../include/common.h \
+  ../include/patricia.h ../include/irc_string.h ../include/ircd.h \
+  ../include/numeric.h ../include/s_newconf.h ../include/scache.h \
+  ../include/send.h ../include/msg.h ../include/s_serv.h \
+  ../include/hash.h ../include/parse.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h \
+  ../include/s_log.h
+m_help.so: m_help.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/ircd.h ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/msg.h ../include/numeric.h \
+  ../include/send.h ../include/s_conf.h ../include/class.h \
+  ../include/common.h ../include/patricia.h ../include/irc_string.h \
+  ../include/ircd.h ../include/numeric.h ../include/s_log.h \
+  ../include/parse.h ../include/modules.h ../include/parse.h \
+  ../include/msg.h ../include/hook.h ../include/hash.h ../include/cache.h
+m_info.so: m_info.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/m_info.h ../include/channel.h ../include/ircd_defs.h \
+  ../include/s_log.h ../include/send.h ../include/client.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/common.h ../include/irc_string.h ../include/ircd.h \
+  ../libcharybdis/tools.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/setup.h ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/hook.h ../include/numeric.h ../include/s_serv.h \
+  ../include/s_user.h ../include/send.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/msg.h ../include/parse.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h
+m_invite.so: m_invite.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/common.h ../include/channel.h ../include/ircd_defs.h \
+  ../include/s_log.h ../include/send.h ../include/client.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/hash.h ../libcharybdis/tools.h ../include/irc_string.h \
+  ../include/ircd.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/setup.h ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/numeric.h ../include/send.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/s_serv.h ../include/msg.h ../include/parse.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../include/hook.h ../include/packet.h
+m_ison.so: m_ison.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/ircd.h \
+  ../libcharybdis/tools.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/setup.h ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/numeric.h ../include/send.h ../include/msg.h \
+  ../include/parse.h ../include/modules.h ../include/parse.h \
+  ../include/msg.h ../include/hook.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/s_serv.h ../include/hash.h
+m_kline.so: m_kline.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../include/class.h ../libcharybdis/tools.h \
+  ../include/client.h ../libcharybdis/linebuf.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/res.h ../include/snomask.h \
+  ../include/client.h ../include/common.h ../include/irc_string.h \
+  ../include/sprintf_irc.h ../include/ircd.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/hostmask.h ../include/numeric.h \
+  ../libcharybdis/commio.h ../include/config.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/s_newconf.h ../include/s_log.h ../include/send.h \
+  ../include/hash.h ../include/s_serv.h ../include/msg.h \
+  ../include/parse.h ../include/modules.h ../include/parse.h \
+  ../include/msg.h ../include/hook.h ../libcharybdis/event.h
+m_knock.so: m_knock.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/sprintf_irc.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/ircd_defs.h \
+  ../include/s_log.h ../include/send.h ../include/client.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/hash.h ../libcharybdis/tools.h ../include/irc_string.h \
+  ../include/ircd.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/setup.h ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/numeric.h ../include/send.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/msg.h ../include/parse.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h \
+  ../include/s_serv.h
+m_links.so: m_links.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/irc_string.h ../include/ircd.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/numeric.h \
+  ../include/s_serv.h ../include/send.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/msg.h ../include/parse.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h ../include/hook.h \
+  ../include/cache.h
+m_list_safelist.so: m_list_safelist.c ../include/stdinc.h \
+  ../include/config.h ../include/setup.h ../include/defaults.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/ircd_defs.h \
+  ../include/s_log.h ../include/send.h ../include/client.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/hash.h ../libcharybdis/tools.h ../include/irc_string.h \
+  ../include/ircd.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/setup.h ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/numeric.h ../include/s_conf.h ../include/class.h \
+  ../include/common.h ../include/patricia.h ../include/irc_string.h \
+  ../include/ircd.h ../include/numeric.h ../include/s_serv.h \
+  ../include/send.h ../include/msg.h ../include/parse.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../include/hook.h ../libcharybdis/event.h
+m_locops.so: m_locops.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/ircd.h ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/irc_string.h ../include/numeric.h \
+  ../include/send.h ../include/s_user.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/s_newconf.h ../include/hash.h ../include/msg.h \
+  ../include/parse.h ../include/modules.h ../include/parse.h \
+  ../include/msg.h ../include/hook.h ../include/s_serv.h
+m_lusers.so: m_lusers.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/ircd.h ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/numeric.h ../include/s_serv.h \
+  ../include/s_user.h ../include/send.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/msg.h ../include/parse.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h
+m_map.so: m_map.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/hook.h \
+  ../include/numeric.h ../include/send.h ../include/s_conf.h \
+  ../include/class.h ../libcharybdis/tools.h ../include/common.h \
+  ../include/patricia.h ../include/irc_string.h ../include/ircd.h \
+  ../include/numeric.h ../include/sprintf_irc.h
+m_monitor.so: m_monitor.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/client.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../libcharybdis/linebuf.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/res.h ../include/snomask.h \
+  ../include/client.h ../include/msg.h ../include/parse.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/hook.h \
+  ../include/monitor.h ../include/numeric.h ../include/s_conf.h \
+  ../include/class.h ../libcharybdis/tools.h ../include/common.h \
+  ../include/patricia.h ../include/irc_string.h ../include/ircd.h \
+  ../include/numeric.h
+m_motd.so: m_motd.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../libcharybdis/tools.h ../include/ircd.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/send.h \
+  ../include/numeric.h ../include/hook.h ../include/msg.h \
+  ../include/s_serv.h ../include/parse.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h \
+  ../include/s_conf.h ../include/class.h ../include/common.h \
+  ../include/patricia.h ../include/irc_string.h ../include/ircd.h \
+  ../include/numeric.h ../include/cache.h
+m_names.so: m_names.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/sprintf_irc.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/ircd_defs.h \
+  ../include/s_log.h ../include/send.h ../include/client.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/common.h ../include/hash.h ../libcharybdis/tools.h \
+  ../include/irc_string.h ../include/ircd.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/numeric.h ../include/send.h \
+  ../include/s_serv.h ../include/s_conf.h ../include/class.h \
+  ../include/common.h ../include/patricia.h ../include/irc_string.h \
+  ../include/ircd.h ../include/numeric.h ../include/msg.h \
+  ../include/parse.h ../include/modules.h ../include/parse.h \
+  ../include/msg.h ../include/hook.h
+m_oper.so: m_oper.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/client.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../libcharybdis/linebuf.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/res.h ../include/snomask.h \
+  ../include/client.h ../include/common.h ../include/irc_string.h \
+  ../include/ircd.h ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/numeric.h ../libcharybdis/commio.h \
+  ../include/config.h ../include/s_conf.h ../include/class.h \
+  ../include/common.h ../include/patricia.h ../include/irc_string.h \
+  ../include/ircd.h ../include/numeric.h ../include/s_newconf.h \
+  ../include/s_log.h ../include/s_user.h ../include/send.h \
+  ../include/msg.h ../include/parse.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h \
+  ../include/packet.h ../include/cache.h
+m_operspy.so: m_operspy.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/send.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../include/channel.h ../include/client.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/common.h ../include/config.h ../include/ircd.h \
+  ../libcharybdis/tools.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/setup.h ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/numeric.h ../libcharybdis/memory.h ../include/s_serv.h \
+  ../include/hash.h ../include/msg.h ../include/parse.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../include/hook.h ../include/sprintf_irc.h
+m_pass.so: m_pass.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/irc_string.h ../include/send.h ../include/numeric.h \
+  ../include/ircd.h ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/msg.h ../include/parse.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../include/hook.h ../include/s_serv.h ../include/hash.h \
+  ../include/s_conf.h ../include/class.h ../include/common.h \
+  ../include/patricia.h ../include/irc_string.h ../include/ircd.h \
+  ../include/numeric.h
+m_ping.so: m_ping.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/ircd.h ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/numeric.h ../include/send.h \
+  ../include/irc_string.h ../include/msg.h ../include/parse.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../include/hook.h ../include/hash.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/s_serv.h
+m_pong.so: m_pong.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/ircd.h \
+  ../libcharybdis/tools.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/s_log.h ../include/ircd_defs.h ../include/send.h \
+  ../include/setup.h ../libcharybdis/balloc.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../include/s_user.h ../include/client.h \
+  ../libcharybdis/linebuf.h ../include/channel.h ../include/res.h \
+  ../include/snomask.h ../include/client.h ../include/hash.h \
+  ../include/hook.h ../include/numeric.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/send.h ../include/channel.h ../include/irc_string.h \
+  ../include/msg.h ../include/parse.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h
+m_post.so: m_post.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/ircd.h ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/numeric.h ../include/s_serv.h \
+  ../include/send.h ../include/msg.h ../include/parse.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../include/hook.h ../include/s_conf.h ../include/class.h \
+  ../include/common.h ../include/patricia.h ../include/irc_string.h \
+  ../include/ircd.h ../include/numeric.h
+m_rehash.so: m_rehash.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/channel.h ../include/common.h ../include/irc_string.h \
+  ../include/ircd.h ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/s_gline.h ../include/s_serv.h \
+  ../include/numeric.h ../include/res.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/s_newconf.h ../include/s_log.h ../include/send.h \
+  ../include/msg.h ../include/parse.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h \
+  ../include/hostmask.h ../include/reject.h ../include/hash.h \
+  ../include/cache.h
+m_restart.so: m_restart.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/common.h ../include/irc_string.h ../include/sprintf_irc.h \
+  ../include/ircd.h ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/numeric.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/s_newconf.h ../include/restart.h ../include/s_log.h \
+  ../include/send.h ../include/msg.h ../include/parse.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../include/hook.h
+m_resv.so: m_resv.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/channel.h ../include/ircd.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/numeric.h \
+  ../include/s_serv.h ../include/send.h ../include/msg.h \
+  ../include/parse.h ../include/modules.h ../include/parse.h \
+  ../include/msg.h ../include/hook.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/s_newconf.h ../include/hash.h ../include/s_log.h \
+  ../include/sprintf_irc.h
+m_sasl.so: m_sasl.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/hash.h ../libcharybdis/tools.h ../include/send.h \
+  ../include/msg.h ../include/modules.h ../include/parse.h \
+  ../include/msg.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/setup.h ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/hook.h ../include/numeric.h ../include/s_serv.h
+m_scan.so: m_scan.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/class.h \
+  ../libcharybdis/tools.h ../include/hook.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/hash.h ../include/common.h ../include/irc_string.h \
+  ../include/ircd.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/setup.h ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/numeric.h ../libcharybdis/commio.h ../include/config.h \
+  ../include/s_serv.h ../include/s_conf.h ../include/class.h \
+  ../include/common.h ../include/patricia.h ../include/irc_string.h \
+  ../include/ircd.h ../include/numeric.h ../include/s_newconf.h \
+  ../include/s_user.h ../include/send.h ../include/msg.h \
+  ../include/parse.h ../include/modules.h ../include/parse.h \
+  ../include/msg.h ../include/hook.h
+m_services.so: m_services.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/send.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../include/channel.h ../include/client.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/common.h ../include/config.h ../include/ircd.h \
+  ../libcharybdis/tools.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/setup.h ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/numeric.h ../libcharybdis/memory.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/s_serv.h ../include/hash.h ../include/msg.h \
+  ../include/parse.h ../include/modules.h ../include/parse.h \
+  ../include/msg.h ../include/hook.h ../include/sprintf_irc.h \
+  ../include/whowas.h ../include/monitor.h
+m_set.so: m_set.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../libcharybdis/event.h ../include/irc_string.h \
+  ../include/sprintf_irc.h ../include/ircd.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/numeric.h \
+  ../libcharybdis/commio.h ../include/config.h ../include/s_serv.h \
+  ../include/send.h ../include/common.h ../include/channel.h \
+  ../include/s_conf.h ../include/class.h ../include/common.h \
+  ../include/patricia.h ../include/irc_string.h ../include/ircd.h \
+  ../include/numeric.h ../include/s_newconf.h ../include/msg.h \
+  ../include/parse.h ../include/modules.h ../include/parse.h \
+  ../include/msg.h ../include/hook.h
+m_signon.so: m_signon.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/send.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../include/channel.h ../include/client.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/common.h ../include/config.h ../include/ircd.h \
+  ../libcharybdis/tools.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/setup.h ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/numeric.h ../libcharybdis/memory.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/s_serv.h ../include/hash.h ../include/msg.h \
+  ../include/parse.h ../include/modules.h ../include/parse.h \
+  ../include/msg.h ../include/hook.h ../include/sprintf_irc.h \
+  ../include/whowas.h ../include/monitor.h ../include/s_stats.h \
+  ../include/snomask.h ../include/irc_string.h
+m_snote.so: m_snote.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/class.h \
+  ../libcharybdis/tools.h ../include/hook.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/hash.h ../include/common.h ../include/irc_string.h \
+  ../include/ircd.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/setup.h ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/numeric.h ../libcharybdis/commio.h ../include/config.h \
+  ../include/s_serv.h ../include/s_conf.h ../include/class.h \
+  ../include/common.h ../include/patricia.h ../include/irc_string.h \
+  ../include/ircd.h ../include/numeric.h ../include/s_newconf.h \
+  ../include/s_user.h ../include/send.h ../include/msg.h \
+  ../include/parse.h ../include/modules.h ../include/parse.h \
+  ../include/msg.h ../include/hook.h
+m_sshortcut.so: m_sshortcut.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/common.h ../include/ircd.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/irc_string.h ../include/numeric.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/s_log.h ../include/s_serv.h ../include/send.h \
+  ../include/msg.h ../include/parse.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h
+m_stats.so: m_stats.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/class.h ../libcharybdis/tools.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/common.h ../include/irc_string.h ../include/ircd.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/listener.h \
+  ../include/s_gline.h ../include/msg.h ../include/hostmask.h \
+  ../include/numeric.h ../include/scache.h ../include/send.h \
+  ../libcharybdis/commio.h ../include/config.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/s_serv.h ../include/s_stats.h ../include/s_user.h \
+  ../libcharybdis/event.h ../libcharybdis/linebuf.h ../include/parse.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../include/hook.h ../include/hook.h ../include/s_newconf.h \
+  ../include/hash.h
+m_svinfo.so: m_svinfo.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/common.h ../include/irc_string.h ../include/ircd.h \
+  ../libcharybdis/tools.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/setup.h ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/numeric.h ../include/send.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/s_log.h ../include/msg.h ../include/parse.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../include/hook.h
+m_tb.so: m_tb.c ../include/stdinc.h ../include/config.h ../include/setup.h \
+  ../include/defaults.h ../libcharybdis/tools.h ../include/send.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../include/channel.h ../include/client.h ../libcharybdis/linebuf.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/res.h \
+  ../include/snomask.h ../include/client.h ../include/common.h \
+  ../include/config.h ../include/ircd.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/msg.h ../include/modules.h ../include/parse.h \
+  ../include/msg.h ../include/hook.h ../include/hash.h \
+  ../include/s_serv.h
+m_testline.so: m_testline.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/send.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../include/client.h ../libcharybdis/linebuf.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/res.h \
+  ../include/snomask.h ../include/client.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/hook.h ../include/msg.h \
+  ../include/hostmask.h ../include/numeric.h ../include/s_conf.h \
+  ../include/class.h ../libcharybdis/tools.h ../include/common.h \
+  ../include/patricia.h ../include/irc_string.h ../include/ircd.h \
+  ../include/numeric.h ../include/s_newconf.h ../include/sprintf_irc.h
+m_testmask.so: m_testmask.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/common.h ../include/ircd.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/irc_string.h ../include/numeric.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/s_log.h ../include/s_serv.h ../include/send.h \
+  ../include/msg.h ../include/parse.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h
+m_time.so: m_time.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/ircd.h ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/numeric.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/s_serv.h ../include/send.h ../include/msg.h \
+  ../include/parse.h ../include/modules.h ../include/parse.h \
+  ../include/msg.h ../include/hook.h ../include/packet.h \
+  ../include/sprintf_irc.h
+m_topic.so: m_topic.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../include/client.h ../libcharybdis/linebuf.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/res.h \
+  ../include/snomask.h ../include/client.h ../include/hash.h \
+  ../libcharybdis/tools.h ../include/irc_string.h \
+  ../include/sprintf_irc.h ../include/ircd.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/numeric.h ../include/send.h \
+  ../include/s_conf.h ../include/class.h ../include/common.h \
+  ../include/patricia.h ../include/irc_string.h ../include/ircd.h \
+  ../include/numeric.h ../include/s_serv.h ../include/msg.h \
+  ../include/parse.h ../include/modules.h ../include/parse.h \
+  ../include/msg.h ../include/hook.h ../include/packet.h
+m_trace.so: m_trace.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/class.h \
+  ../libcharybdis/tools.h ../include/hook.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/hash.h ../include/common.h ../include/irc_string.h \
+  ../include/ircd.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/setup.h ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/numeric.h ../libcharybdis/commio.h ../include/config.h \
+  ../include/s_serv.h ../include/s_conf.h ../include/class.h \
+  ../include/common.h ../include/patricia.h ../include/irc_string.h \
+  ../include/ircd.h ../include/numeric.h ../include/s_newconf.h \
+  ../include/send.h ../include/msg.h ../include/parse.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../include/hook.h
+m_user.so: m_user.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/irc_string.h ../include/ircd.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/numeric.h \
+  ../include/s_user.h ../include/send.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/msg.h ../include/parse.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h \
+  ../include/sprintf_irc.h
+m_userhost.so: m_userhost.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/ircd.h ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/numeric.h ../include/s_serv.h \
+  ../include/send.h ../include/irc_string.h ../include/sprintf_irc.h \
+  ../include/msg.h ../include/parse.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h \
+  ../include/s_conf.h ../include/class.h ../include/common.h \
+  ../include/patricia.h ../include/irc_string.h ../include/ircd.h \
+  ../include/numeric.h
+m_users.so: m_users.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/ircd.h ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/numeric.h ../include/s_serv.h \
+  ../include/s_conf.h ../include/class.h ../include/common.h \
+  ../include/patricia.h ../include/irc_string.h ../include/ircd.h \
+  ../include/numeric.h ../include/send.h ../include/msg.h \
+  ../include/parse.h ../include/modules.h ../include/parse.h \
+  ../include/msg.h ../include/hook.h
+m_version.so: m_version.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/ircd.h ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/numeric.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/s_serv.h ../include/s_user.h ../include/send.h \
+  ../include/msg.h ../include/parse.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h
+m_wallops.so: m_wallops.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/ircd.h ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/irc_string.h ../include/numeric.h \
+  ../include/send.h ../include/s_user.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/s_newconf.h ../include/msg.h ../include/parse.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../include/hook.h ../include/s_serv.h
+m_who.so: m_who.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/common.h ../include/client.h ../include/ircd_defs.h \
+  ../include/s_log.h ../include/send.h ../libcharybdis/linebuf.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/res.h \
+  ../include/snomask.h ../include/client.h ../include/channel.h \
+  ../include/hash.h ../libcharybdis/tools.h ../include/ircd.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/numeric.h \
+  ../include/s_serv.h ../include/send.h ../include/irc_string.h \
+  ../include/sprintf_irc.h ../include/s_conf.h ../include/class.h \
+  ../include/common.h ../include/patricia.h ../include/irc_string.h \
+  ../include/ircd.h ../include/numeric.h ../include/s_log.h \
+  ../include/msg.h ../include/parse.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h \
+  ../include/packet.h ../include/s_newconf.h
+m_whois.so: m_whois.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/common.h ../include/client.h ../include/ircd_defs.h \
+  ../include/s_log.h ../include/send.h ../libcharybdis/linebuf.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/res.h \
+  ../include/snomask.h ../include/client.h ../include/hash.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/ircd.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/numeric.h \
+  ../include/s_conf.h ../include/class.h ../include/common.h \
+  ../include/patricia.h ../include/irc_string.h ../include/ircd.h \
+  ../include/numeric.h ../include/s_serv.h ../include/send.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/s_log.h \
+  ../include/msg.h ../include/parse.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h ../include/hook.h \
+  ../include/s_newconf.h
+m_whowas.so: m_whowas.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/whowas.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../include/client.h ../libcharybdis/linebuf.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/res.h ../include/snomask.h \
+  ../include/client.h ../include/common.h ../include/hash.h \
+  ../libcharybdis/tools.h ../include/irc_string.h ../include/ircd.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/numeric.h ../include/s_serv.h \
+  ../include/s_user.h ../include/send.h ../include/s_conf.h \
+  ../include/class.h ../include/common.h ../include/patricia.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/msg.h ../include/parse.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h
+m_unreject.so: m_unreject.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/s_conf.h ../include/class.h ../libcharybdis/tools.h \
+  ../include/common.h ../include/patricia.h ../include/irc_string.h \
+  ../include/ircd.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/setup.h ../libcharybdis/balloc.h ../libcharybdis/memory.h \
+  ../include/numeric.h ../include/hostmask.h ../include/reject.h \
+  ../include/msg.h ../include/modules.h ../include/parse.h \
+  ../include/msg.h ../include/hook.h ../include/send.h
+m_xline.so: m_xline.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/send.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../include/channel.h ../include/client.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/common.h ../include/config.h ../include/class.h \
+  ../libcharybdis/tools.h ../include/ircd.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/numeric.h ../libcharybdis/memory.h \
+  ../include/s_log.h ../include/s_serv.h ../include/whowas.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/hash.h \
+  ../include/msg.h ../include/parse.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../include/hook.h \
+  ../include/s_conf.h ../include/class.h ../include/common.h \
+  ../include/patricia.h ../include/irc_string.h ../include/ircd.h \
+  ../include/numeric.h ../include/s_newconf.h
+sno_routing.so: sno_routing.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/modules.h \
+  ../include/parse.h ../include/msg.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/ircd_defs.h \
+  ../include/send.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/tools.h ../libcharybdis/memory.h ../include/hook.h \
+  ../include/client.h ../libcharybdis/linebuf.h ../include/channel.h \
+  ../include/res.h ../include/snomask.h ../include/client.h \
+  ../include/hook.h ../include/ircd.h ../libcharybdis/tools.h \
+  ../include/send.h
diff --git a/modules/.indent.pro b/modules/.indent.pro
new file mode 100644 (file)
index 0000000..1b1a956
--- /dev/null
@@ -0,0 +1,49 @@
+/* $Id: .indent.pro 238 2005-09-21 05:26:03Z nenolod $ */
+
+/* copy this file to the source dir then run indent file.c */
+
+--gnu-style
+
+/* This is the indent before the brace not inside the block. */
+--brace-indent0
+
+/* Indent case: by 2 and braces inside case by 0(then by 0)... */
+--case-brace-indentation0
+--case-indentation2
+
+--indent-level8
+
+/* Put while() on the brace from do... */
+--cuddle-do-while
+
+/* Disable an annoying format... */
+--no-space-after-function-call-names
+
+/* Disable an annoying format... */
+--dont-break-procedure-type
+
+/* Disable an annoying format... */
+--no-space-after-casts
+
+--line-length200
+
+/* typedefs */
+-T boolean_t
+-T node_t
+-T list_t
+-T tld_t
+-T kline_t
+-T EVH
+-T sra_t
+-T server_t
+-T user_t
+-T channel_t
+-T chanuser_t
+-T myuser_t
+-T mychan_t
+-T chanacs_t
+-T CONFIGENTRY
+-T CONFIGFILE
+-T Block
+-T MemBlock
+-T BlockHeap
diff --git a/modules/Makefile.in b/modules/Makefile.in
new file mode 100644 (file)
index 0000000..dc9105e
--- /dev/null
@@ -0,0 +1,221 @@
+#
+# Makefile.in for ircd/modules
+#
+# $Id: Makefile.in 946 2006-03-06 03:43:02Z nenolod $
+#
+CC             = @CC@
+AR             = @AR@
+RANLIB         = @RANLIB@
+RM             = @RM@
+SED             = @SED@
+LEX            = @LEX@
+LEXLIB         = @LEXLIB@
+CFLAGS         = @IRC_CFLAGS@ -DIRCD_PREFIX=\"@prefix@\"
+PICFLAGS       = @PICFLAGS@
+MKDEP          = @MKDEP@ -DIRCD_PREFIX=\"@prefix@\"
+INSTALL                = @INSTALL@
+INSTALL_PROGRAM        = @INSTALL_PROGRAM@
+INSTALL_DATA   = @INSTALL_DATA@
+INSTALL_SUID    = @INSTALL_PROGRAM@ -o root -m 4755
+SEDOBJ         = @SEDOBJ@
+SHELL          = /bin/sh
+MV             = @MV@
+LD             = @LD@
+
+SSL_LIBS       = @SSL_LIBS@
+SSL_INCLUDES   = @SSL_INCLUDES@
+
+IRCDLIBS        = @LIBS@ $(SSL_LIBS)
+
+prefix          = @prefix@
+moduledir       = @moduledir@
+# Change this later! -- adrian
+automoduledir   = @moduledir@/autoload
+
+INCLUDES       = -I../include -I../libcharybdis -I../adns $(SSL_INCLUDES)
+CPPFLAGS       = ${INCLUDES} @CPPFLAGS@
+
+CORE_SRCS = \
+  core/m_die.c \
+  core/m_error.c \
+  core/m_join.c \
+  core/m_kick.c \
+  core/m_kill.c \
+  core/m_message.c \
+  core/m_mode.c \
+  core/m_nick.c \
+  core/m_part.c \
+  core/m_quit.c \
+  core/m_server.c \
+  core/m_sjoin.c \
+  core/m_squit.c
+
+TSRCS =                          \
+  m_accept.c \
+  m_admin.c \
+  m_away.c \
+  m_cap.c \
+  m_capab.c \
+  m_challenge.c \
+  m_chghost.c \
+  m_close.c \
+  m_cmessage.c \
+  m_connect.c \
+  m_dline.c \
+  m_encap.c \
+  m_etrace.c \
+  m_gline.c \
+  m_help.c \
+  m_info.c \
+  m_invite.c \
+  m_ison.c \
+  m_kline.c \
+  m_knock.c \
+  m_links.c \
+  m_list_safelist.c \
+  m_locops.c \
+  m_lusers.c \
+  m_map.c \
+  m_monitor.c \
+  m_motd.c \
+  m_names.c \
+  m_oper.c \
+  m_operspy.c \
+  m_pass.c \
+  m_ping.c \
+  m_pong.c \
+  m_post.c \
+  m_rehash.c \
+  m_restart.c \
+  m_resv.c \
+  m_sasl.c \
+  m_scan.c \
+  m_services.c \
+  m_set.c \
+  m_signon.c \
+  m_snote.c \
+  m_stats.c \
+  m_svinfo.c \
+  m_tb.c \
+  m_testline.c \
+  m_testmask.c \
+  m_time.c \
+  m_topic.c \
+  m_trace.c \
+  m_user.c \
+  m_userhost.c \
+  m_users.c \
+  m_version.c \
+  m_wallops.c \
+  m_who.c \
+  m_whois.c \
+  m_whowas.c \
+  m_unreject.c \
+  m_xline.c \
+  sno_routing.c
+
+SRCS = ${TSRCS}
+
+ALL_SRCS = $(CORE_SRCS) \
+           $(SRCS)
+
+SH_OBJS = ${SRCS:.c=.so}
+SH_CORE_OBJS = ${CORE_SRCS:.c=.so}
+
+HPUX_OBJS = ${SH_OBJS:.so=.sl}
+HPUX_CORE_OBJS = ${SH_CORE_OBJS:.so=.sl}
+
+S_OBJS = ${ALL_SRCS:.c=.o}
+
+DOLLAR = $$
+
+default:       build
+build: all
+all:   @MOD_TARGET@
+
+shared_modules: $(SH_CORE_OBJS) $(SH_OBJS)
+
+hpux_modules: $(HPUX_CORE_OBJS) $(HPUX_OBJS)
+
+hpux_shared: $(SH_CORE_OBJS) $(SH_OBJS)
+       ${MAKE} hpux_modules
+
+static_modules.c: static_modules.c.SH
+       /bin/sh ./static_modules.c.SH $(S_OBJS)
+       
+libmodules.a: $(S_OBJS) static_modules.o
+       $(RM) -f $@
+       $(AR) cqv $@ $(S_OBJS) static_modules.o
+       $(RANLIB) $@ 
+
+
+install-mkdirs:
+       @echo "ircd: setting up modular directory structure"
+       -@if test ! -d $(DESTDIR)$(moduledir); then \
+                mkdir $(DESTDIR)$(moduledir); \
+        fi
+       -@if test -d $(DESTDIR)$(moduledir)-old; then \
+               rm -rf $(DESTDIR)$(moduledir)-old; \
+       fi
+       -@if test -d $(DESTDIR)$(moduledir); then \
+               echo "ircd: backing up modules"; \
+               mv $(DESTDIR)$(moduledir) $(DESTDIR)$(moduledir)-old; \
+       fi
+
+       @mkdir -p -m 755 $(DESTDIR)$(moduledir)
+       @mkdir -p -m 755 $(DESTDIR)$(automoduledir)
+
+install: install_@MOD_TARGET@
+
+install_libmodules.a: libmodules.a
+# Ye olde noop here.   
+
+install_shared_modules: install-mkdirs
+       @echo "ircd: installing modules"
+       @for file in $(SH_CORE_OBJS); do \
+               $(INSTALL_DATA) $$file $(DESTDIR)$(moduledir); \
+       done
+       @for file in $(SH_OBJS); do \
+               $(INSTALL_DATA) $$file $(DESTDIR)$(automoduledir); \
+       done
+
+install_hpux_shared: install-mkdirs
+       @echo "ircd: installing modules"
+       @for file in $(HPUX_CORE_OBJS); do \
+               $(INSTALL_DATA) $$file $(DESTDIR)$(moduledir); \
+       done
+       @for file in $(HPUX_OBJS); do \
+               $(INSTALL_DATA) $$file $(DESTDIR)$(automoduledir); \
+       done
+
+.SUFFIXES: .sl .so .o
+
+.c.o:
+       ${CC} ${CPPFLAGS} ${CFLAGS} -DMODNAME=`basename $< .c`_mheader -c $< -o $@
+
+.c.so:
+       ${CC} ${PICFLAGS} ${CPPFLAGS} ${CFLAGS} $< -o $@
+
+.so.sl:
+       $(LD) -b $< -o $@
+
+.PHONY: depend clean distclean
+depend:
+       @$(RM) -f .depend
+       ${MKDEP} ${CPPFLAGS} ${ALL_SRCS} > .depend
+       @$(SED) -e '${SEDOBJ}' < .depend > .depend.tmp-1
+       @$(SED) -e 's/^m_\(die\|kick\|kill\|message\|mode\|nick\|part\|quit\|server\|sjoin\|squit\)/core\/m_\1/' .depend.tmp-1 > .depend.tmp
+       @$(MV) -f .depend.tmp .depend
+       @$(RM) -f .depend.tmp-1
+
+clean:
+       ${RM} -f *.so *.sl *~ *.o *.a
+       ${RM} -f core/*.so core/*.sl core/*~ core/*.o
+
+lint:
+       lint -aacgprxhH ${CPPFLAGS} -DIRCD_PREFIX=\"@prefix@\" $(ALL_SRCS) >../lint.out
+
+distclean: clean
+       ${RM} -f Makefile
+
+include .depend
diff --git a/modules/core/m_die.c b/modules/core/m_die.c
new file mode 100644 (file)
index 0000000..49f5bcf
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_die.c: Kills off this server.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_die.c 98 2005-09-11 03:37:47Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "client.h"
+#include "ircd.h"
+#include "irc_string.h"
+#include "numeric.h"
+#include "commio.h"
+#include "s_log.h"
+#include "s_conf.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_newconf.h"
+
+static int mo_die(struct Client *, struct Client *, int, const char **);
+
+static struct Message die_msgtab = {
+       "DIE", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_die, 0}}
+};
+
+mapi_clist_av1 die_clist[] = { &die_msgtab, NULL };
+
+DECLARE_MODULE_AV1(die, NULL, NULL, die_clist, NULL, NULL, "$Revision: 98 $");
+
+/*
+ * mo_die - DIE command handler
+ */
+static int
+mo_die(struct Client *client_p __unused, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+       dlink_node *ptr;
+
+       if(!IsOperDie(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "die");
+               return 0;
+       }
+
+       if(parc < 2 || EmptyString(parv[1]))
+       {
+               sendto_one(source_p, ":%s NOTICE %s :Need server name /die %s",
+                          me.name, source_p->name, me.name);
+               return 0;
+       }
+       else if(irccmp(parv[1], me.name))
+       {
+               sendto_one(source_p, ":%s NOTICE %s :Mismatch on /die %s",
+                          me.name, source_p->name, me.name);
+               return 0;
+       }
+
+       DLINK_FOREACH(ptr, lclient_list.head)
+       {
+               target_p = ptr->data;
+
+               sendto_one(target_p,
+                          ":%s NOTICE %s :Server Terminating. %s",
+                          me.name, target_p->name, get_client_name(source_p, HIDE_IP));
+       }
+
+       DLINK_FOREACH(ptr, serv_list.head)
+       {
+               target_p = ptr->data;
+
+               sendto_one(target_p, ":%s ERROR :Terminated by %s",
+                          me.name, get_client_name(source_p, HIDE_IP));
+       }
+
+       /*
+        * XXX we called flush_connections() here. Read server_reboot()
+        * for an explanation as to what we should do.
+        *     -- adrian
+        */
+       ilog(L_MAIN, "Server terminated by %s", get_oper_name(source_p));
+
+       /* this is a normal exit, tell the os it's ok */
+       unlink(pidFileName);
+       exit(0);
+       /* NOT REACHED */
+
+       return 0;
+}
diff --git a/modules/core/m_error.c b/modules/core/m_error.c
new file mode 100644 (file)
index 0000000..a58d1b1
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_error.c: Handles error messages from the other end.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_error.c 494 2006-01-15 16:08:28Z jilles $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "common.h"            /* FALSE */
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "msg.h"
+#include "memory.h"
+#include "modules.h"
+#include "s_log.h"
+#include "s_conf.h"
+
+static int m_error(struct Client *, struct Client *, int, const char **);
+static int ms_error(struct Client *, struct Client *, int, const char **);
+
+struct Message error_msgtab = {
+       "ERROR", 0, 0, 0, MFLG_SLOW | MFLG_UNREG,
+       {{m_error, 0}, mg_ignore, mg_ignore, {ms_error, 0}, mg_ignore, mg_ignore}
+};
+
+mapi_clist_av1 error_clist[] = {
+       &error_msgtab, NULL
+};
+
+DECLARE_MODULE_AV1(error, NULL, NULL, error_clist, NULL, NULL, "$Revision: 494 $");
+
+
+/*
+ * Note: At least at protocol level ERROR has only one parameter,
+ * although this is called internally from other functions
+ * --msa
+ *
+ *      parv[0] = sender prefix
+ *      parv[*] = parameters
+ */
+int
+m_error(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       const char *para;
+
+       para = (parc > 1 && *parv[1] != '\0') ? parv[1] : "<>";
+
+       ilog(L_SERVER, "Received ERROR message from %s: %s",
+            log_client_name(source_p, SHOW_IP), para);
+
+       if(IsAnyServer(client_p) && ConfigFileEntry.hide_error_messages < 2)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ADMIN,
+                                    "ERROR :from %s -- %s",
+                                    get_server_name(client_p, HIDE_IP), para);
+
+               if(!ConfigFileEntry.hide_error_messages)
+                       sendto_realops_snomask(SNO_GENERAL, L_OPER,
+                                            "ERROR :from %s -- %s",
+                                            get_server_name(client_p, HIDE_IP), para);
+       }
+
+       exit_client(client_p, source_p, source_p, "ERROR");
+
+       return 0;
+}
+
+static int
+ms_error(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       const char *para;
+
+       para = (parc > 1 && *parv[1] != '\0') ? parv[1] : "<>";
+
+       ilog(L_SERVER, "Received ERROR message from %s: %s",
+            log_client_name(source_p, SHOW_IP), para);
+
+       if(ConfigFileEntry.hide_error_messages == 2)
+               return 0;
+
+       if(client_p == source_p)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ADMIN, "ERROR :from %s -- %s",
+                                    get_server_name(client_p, HIDE_IP), para);
+
+               if(!ConfigFileEntry.hide_error_messages)
+                       sendto_realops_snomask(SNO_GENERAL, L_OPER,
+                                            "ERROR :from %s -- %s",
+                                            get_server_name(client_p, HIDE_IP), para);
+       }
+       else
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ADMIN, "ERROR :from %s via %s -- %s",
+                                    source_p->name, get_server_name(client_p, HIDE_IP), para);
+
+               if(!ConfigFileEntry.hide_error_messages)
+                       sendto_realops_snomask(SNO_GENERAL, L_OPER,
+                                            "ERROR :from %s via %s -- %s",
+                                            source_p->name,
+                                            get_server_name(client_p, HIDE_IP), para);
+       }
+
+       return 0;
+}
diff --git a/modules/core/m_join.c b/modules/core/m_join.c
new file mode 100644 (file)
index 0000000..de001cd
--- /dev/null
@@ -0,0 +1,932 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_join.c: Joins a channel.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_join.c 3131 2007-01-21 15:36:31Z jilles $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "channel.h"
+#include "client.h"
+#include "common.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "s_serv.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "sprintf_irc.h"
+#include "packet.h"
+
+static int m_join(struct Client *, struct Client *, int, const char **);
+static int ms_join(struct Client *, struct Client *, int, const char **);
+
+static int h_can_create_channel;
+static int h_channel_join;
+
+struct Message join_msgtab = {
+       "JOIN", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_join, 2}, {ms_join, 2}, mg_ignore, mg_ignore, {m_join, 2}}
+};
+
+mapi_clist_av1 join_clist[] = { &join_msgtab, NULL };
+
+mapi_hlist_av1 join_hlist[] = {
+       { "can_create_channel", &h_can_create_channel },
+       { "channel_join", &h_channel_join },
+       { NULL, NULL },
+};
+
+DECLARE_MODULE_AV1(join, NULL, NULL, join_clist, join_hlist, NULL, "$Revision: 3131 $");
+
+static void do_join_0(struct Client *client_p, struct Client *source_p);
+static int check_channel_name_loc(struct Client *source_p, const char *name);
+
+static void set_final_mode(struct Mode *mode, struct Mode *oldmode);
+static void remove_our_modes(struct Channel *chptr, struct Client *source_p);
+
+static char modebuf[MODEBUFLEN];
+static char parabuf[MODEBUFLEN];
+static char *mbuf;
+
+/* Check what we will forward to, without sending any notices to the user
+ * -- jilles
+ */
+static struct Channel *
+check_forward(struct Client *source_p, struct Channel *chptr,
+               char *key)
+{
+       int depth = 0, i;
+
+       /* User is +Q */
+       if (IsNoForward(source_p))
+               return NULL;
+
+       while (depth < 16)
+       {
+               chptr = find_channel(chptr->mode.forward);
+               /* Can only forward to existing channels */
+               if (chptr == NULL)
+                       return NULL;
+               /* Already on there, show original error message */
+               if (IsMember(source_p, chptr))
+                       return NULL;
+               /* Juped. Sending a warning notice would be unfair */
+               if (hash_find_resv(chptr->chname))
+                       return NULL;
+               /* Don't forward to +Q channel */
+               if (chptr->mode.mode & MODE_DISFORWARD)
+                       return NULL;
+               i = can_join(source_p, chptr, key);
+               if (i == 0)
+                       return chptr;
+               if (i != ERR_INVITEONLYCHAN && i != ERR_NEEDREGGEDNICK && i != ERR_THROTTLE && i != ERR_CHANNELISFULL)
+                       return NULL;
+               depth++;
+       }
+
+       return NULL;
+}
+
+/*
+ * m_join
+ *      parv[0] = sender prefix
+ *      parv[1] = channel
+ *      parv[2] = channel password (key)
+ */
+static int
+m_join(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       static char jbuf[BUFSIZE];
+       struct Channel *chptr = NULL;
+       struct ConfItem *aconf;
+       char *name;
+       char *key = NULL;
+       int i, flags = 0;
+       char *p = NULL, *p2 = NULL;
+       char *chanlist;
+       char *mykey;
+       int successful_join_count = 0;  /* Number of channels successfully joined */
+
+       jbuf[0] = '\0';
+
+       /* rebuild the list of channels theyre supposed to be joining.
+        * this code has a side effect of losing keys, but..
+        */
+       chanlist = LOCAL_COPY(parv[1]);
+       for(name = strtoken(&p, chanlist, ","); name; name = strtoken(&p, NULL, ","))
+       {
+               /* check the length and name of channel is ok */
+               if(!check_channel_name_loc(source_p, name) || (strlen(name) > LOC_CHANNELLEN))
+               {
+                       sendto_one_numeric(source_p, ERR_BADCHANNAME,
+                                          form_str(ERR_BADCHANNAME), (unsigned char *) name);
+                       continue;
+               }
+
+               /* join 0 parts all channels */
+               if(*name == '0' && !atoi(name))
+               {
+                       (void) strcpy(jbuf, "0");
+                       continue;
+               }
+
+               /* check it begins with # or &, and local chans are disabled */
+               else if(!IsChannelName(name))
+               {
+                       sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
+                                          form_str(ERR_NOSUCHCHANNEL), name);
+                       continue;
+               }
+
+               /* see if its resv'd */
+               if(!IsExemptResv(source_p) && (aconf = hash_find_resv(name)))
+               {
+                       sendto_one_numeric(source_p, ERR_BADCHANNAME,
+                                          form_str(ERR_BADCHANNAME), name);
+
+                       /* dont warn for opers */
+                       if(!IsExemptJupe(source_p) && !IsOper(source_p))
+                               sendto_realops_snomask(SNO_SPY, L_NETWIDE,
+                                                    "User %s (%s@%s) is attempting to join locally juped channel %s (%s)",
+                                                    source_p->name, source_p->username,
+                                                    source_p->host, name, aconf->passwd);
+                       /* dont update tracking for jupe exempt users, these
+                        * are likely to be spamtrap leaves
+                        */
+                       else if(IsExemptJupe(source_p))
+                               aconf->port--;
+
+                       continue;
+               }
+
+               if(splitmode && !IsOper(source_p) && (*name != '&') &&
+                  ConfigChannel.no_join_on_split)
+               {
+                       sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
+                                  me.name, source_p->name, name);
+                       continue;
+               }
+
+               if(*jbuf)
+                       (void) strcat(jbuf, ",");
+               (void) strlcat(jbuf, name, sizeof(jbuf));
+       }
+
+       if(parc > 2)
+       {
+               mykey = LOCAL_COPY(parv[2]);
+               key = strtoken(&p2, mykey, ",");
+       }
+
+       for(name = strtoken(&p, jbuf, ","); name;
+           key = (key) ? strtoken(&p2, NULL, ",") : NULL, name = strtoken(&p, NULL, ","))
+       {
+               hook_data_channel_activity hook_info;
+
+               /* JOIN 0 simply parts all channels the user is in */
+               if(*name == '0' && !atoi(name))
+               {
+                       if(source_p->user->channel.head == NULL)
+                               continue;
+
+                       do_join_0(&me, source_p);
+                       continue;
+               }
+
+               /* look for the channel */
+               if((chptr = find_channel(name)) != NULL)
+               {
+                       if(IsMember(source_p, chptr))
+                               continue;
+
+                       flags = 0;
+               }
+               else
+               {
+                       hook_data_client_approval moduledata;
+
+                       moduledata.client = source_p;
+                       moduledata.approved = 0;
+
+                       call_hook(h_can_create_channel, &moduledata);
+
+                       if(moduledata.approved != 0 && !IsOper(source_p))
+                       {
+                               sendto_one(source_p, form_str(moduledata.approved),
+                                          me.name, source_p->name, name);
+                               continue;
+                       }
+
+                       if(splitmode && !IsOper(source_p) && (*name != '&') &&
+                          ConfigChannel.no_create_on_split)
+                       {
+                               sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
+                                          me.name, source_p->name, name);
+                               continue;
+                       }
+
+                       flags = CHFL_CHANOP;
+               }
+
+               if((dlink_list_length(&source_p->user->channel) >=
+                   (unsigned long) ConfigChannel.max_chans_per_user) &&
+                  (!IsOper(source_p) ||
+                   (dlink_list_length(&source_p->user->channel) >=
+                    (unsigned long) ConfigChannel.max_chans_per_user * 3)))
+               {
+                       sendto_one(source_p, form_str(ERR_TOOMANYCHANNELS),
+                                  me.name, source_p->name, name);
+                       if(successful_join_count)
+                               source_p->localClient->last_join_time = CurrentTime;
+                       return 0;
+               }
+
+               if(flags == 0)  /* if channel doesn't exist, don't penalize */
+                       successful_join_count++;
+
+               if(chptr == NULL)       /* If I already have a chptr, no point doing this */
+               {
+                       chptr = get_or_create_channel(source_p, name, NULL);
+
+                       if(chptr == NULL)
+                       {
+                               sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
+                                          me.name, source_p->name, name);
+                               if(successful_join_count > 0)
+                                       successful_join_count--;
+                               continue;
+                       }
+               }
+
+               if(!IsOper(source_p) && !IsExemptSpambot(source_p))
+                       check_spambot_warning(source_p, name);
+
+               /* can_join checks for +i key, bans etc */
+               if((i = can_join(source_p, chptr, key)))
+               {
+                       if ((i != ERR_NEEDREGGEDNICK && i != ERR_THROTTLE && i != ERR_INVITEONLYCHAN && i != ERR_CHANNELISFULL) ||
+                           (!ConfigChannel.use_forward || (chptr = check_forward(source_p, chptr, key)) == NULL))
+                       {
+                               sendto_one(source_p, form_str(i), me.name, source_p->name, name);
+                               if(successful_join_count > 0)
+                                       successful_join_count--;
+                               continue;
+                       }
+                       sendto_one_numeric(source_p, ERR_LINKCHANNEL, form_str(ERR_LINKCHANNEL), name, chptr->chname);
+               }
+
+               /* add the user to the channel */
+               add_user_to_channel(chptr, source_p, flags);
+               if (chptr->mode.join_num &&
+                       CurrentTime - chptr->join_delta >= chptr->mode.join_time)
+               {
+                       chptr->join_count = 0;
+                       chptr->join_delta = CurrentTime;
+               }
+               chptr->join_count++;
+
+               /* we send the user their join here, because we could have to
+                * send a mode out next.
+                */
+               sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s",
+                                    source_p->name,
+                                    source_p->username, source_p->host, chptr->chname);
+
+               /* its a new channel, set +nt and burst. */
+               if(flags & CHFL_CHANOP)
+               {
+                       chptr->channelts = CurrentTime;
+                       chptr->mode.mode |= MODE_TOPICLIMIT;
+                       chptr->mode.mode |= MODE_NOPRIVMSGS;
+
+                       sendto_channel_local(ONLY_CHANOPS, chptr, ":%s MODE %s +nt",
+                                            me.name, chptr->chname);
+
+                       if(*chptr->chname == '#')
+                       {
+                               sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
+                                             ":%s SJOIN %ld %s +nt :@%s",
+                                             me.id, (long) chptr->channelts,
+                                             chptr->chname, source_p->id);
+                               sendto_server(client_p, chptr, NOCAPS, CAP_TS6,
+                                             ":%s SJOIN %ld %s +nt :@%s",
+                                             me.name, (long) chptr->channelts,
+                                             chptr->chname, source_p->name);
+                       }
+               }
+               else
+               {
+                       const char *modes = channel_modes(chptr, &me);
+
+                       sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
+                                     ":%s JOIN %ld %s %s",
+                                     use_id(source_p), (long) chptr->channelts,
+                                     chptr->chname, modes);
+
+                       sendto_server(client_p, chptr, NOCAPS, CAP_TS6,
+                                     ":%s SJOIN %ld %s %s :%s",
+                                     me.name, (long) chptr->channelts,
+                                     chptr->chname, modes, source_p->name);
+               }
+
+               del_invite(chptr, source_p);
+
+               if(chptr->topic != NULL)
+               {
+                       sendto_one(source_p, form_str(RPL_TOPIC), me.name,
+                                  source_p->name, chptr->chname, chptr->topic);
+
+                       sendto_one(source_p, form_str(RPL_TOPICWHOTIME),
+                                  me.name, source_p->name, chptr->chname,
+                                  chptr->topic_info, chptr->topic_time);
+               }
+
+               channel_member_names(chptr, source_p, 1);
+
+               if(successful_join_count)
+                       source_p->localClient->last_join_time = CurrentTime;
+
+               hook_info.client = source_p;
+               hook_info.chptr = chptr;
+               hook_info.key = key;
+               call_hook(h_channel_join, &hook_info);
+       }
+
+       return 0;
+}
+
+/*
+ * ms_join
+ *
+ * inputs      -
+ * output      - none
+ * side effects        - handles remote JOIN's sent by servers. In TSora
+ *               remote clients are joined using SJOIN, hence a 
+ *               JOIN sent by a server on behalf of a client is an error.
+ *               here, the initial code is in to take an extra parameter
+ *               and use it for the TimeStamp on a new channel.
+ */
+static int
+ms_join(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Channel *chptr;
+       static struct Mode mode, *oldmode;
+       const char *s;
+       const char *modes;
+       time_t oldts;
+       time_t newts;
+       int isnew;
+       int args = 0;
+       int keep_our_modes = YES;
+       int keep_new_modes = YES;
+       dlink_node *ptr, *next_ptr;
+
+       /* special case for join 0 */
+       if((parv[1][0] == '0') && (parv[1][1] == '\0') && parc == 2)
+       {
+               do_join_0(client_p, source_p);
+               return 0;
+       }
+
+       if(parc < 4)
+               return 0;
+
+       if(!IsChannelName(parv[2]) || !check_channel_name(parv[2]))
+               return 0;
+
+       /* joins for local channels cant happen. */
+       if(parv[2][0] == '&')
+               return 0;
+
+       mbuf = modebuf;
+       mode.key[0] = mode.forward[0] = '\0';
+       mode.mode = mode.limit = mode.join_num = mode.join_time = 0;
+
+       s = parv[3];
+       while(*s)
+       {
+               switch (*(s++))
+               {
+               case 'i':
+                       mode.mode |= MODE_INVITEONLY;
+                       break;
+               case 'n':
+                       mode.mode |= MODE_NOPRIVMSGS;
+                       break;
+               case 'p':
+                       mode.mode |= MODE_PRIVATE;
+                       break;
+               case 's':
+                       mode.mode |= MODE_SECRET;
+                       break;
+               case 'm':
+                       mode.mode |= MODE_MODERATED;
+                       break;
+               case 't':
+                       mode.mode |= MODE_TOPICLIMIT;
+                       break;
+               case 'r':
+                       mode.mode |= MODE_REGONLY;
+                       break;
+               case 'L':
+                       mode.mode |= MODE_EXLIMIT;
+                       break;
+               case 'P':
+                       mode.mode |= MODE_PERMANENT;
+                       break;
+               case 'c':
+                       mode.mode |= MODE_NOCOLOR;
+                       break;
+               case 'g':
+                       mode.mode |= MODE_FREEINVITE;
+                       break;
+               case 'z':
+                       mode.mode |= MODE_OPMODERATE;
+                       break;
+               case 'F':
+                       mode.mode |= MODE_FREETARGET;
+                       break;
+               case 'Q':
+                       mode.mode |= MODE_DISFORWARD;
+                       break;
+               case 'f':
+                       if(parc < 5 + args)
+                               return 0;
+                       strlcpy(mode.forward, parv[4 + args], sizeof(mode.forward));
+                       args++;
+                       break;
+               case 'j':
+                       /* sent a +j without an arg. */
+                       if(parc < 5 + args)
+                               return 0;
+                       sscanf(parv[4 + args], "%d:%d", &mode.join_num, &mode.join_time);
+                       args++;
+                       break;
+               case 'k':
+                       /* sent a +k without a key, eek. */
+                       if(parc < 5 + args)
+                               return 0;
+                       strlcpy(mode.key, parv[4 + args], sizeof(mode.key));
+                       args++;
+                       break;
+               case 'l':
+                       /* sent a +l without a limit. */
+                       if(parc < 5 + args)
+                               return 0;
+                       mode.limit = atoi(parv[4 + args]);
+                       args++;
+                       break;
+               }
+       }
+
+       if((chptr = get_or_create_channel(source_p, parv[2], &isnew)) == NULL)
+               return 0;
+
+       newts = atol(parv[1]);
+       oldts = chptr->channelts;
+       oldmode = &chptr->mode;
+
+#ifdef IGNORE_BOGUS_TS
+       if(newts < 800000000)
+       {
+               sendto_realops_snomask(SNO_DEBUG, L_ALL,
+                                    "*** Bogus TS %ld on %s ignored from %s",
+                                    (long) newts, chptr->chname, client_p->name);
+               newts = (oldts == 0) ? oldts : 800000000;
+       }
+#else
+       /* making a channel TS0 */
+       if(!isnew && !newts && oldts)
+       {
+               sendto_channel_local(ALL_MEMBERS, chptr,
+                                    ":%s NOTICE %s :*** Notice -- TS for %s changed from %ld to 0",
+                                    me.name, chptr->chname, chptr->chname, (long) oldts);
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Server %s changing TS on %s from %ld to 0",
+                                    source_p->name, chptr->chname, (long) oldts);
+       }
+#endif
+
+       if(isnew)
+               chptr->channelts = newts;
+       else if(newts == 0 || oldts == 0)
+               chptr->channelts = 0;
+       else if(newts == oldts)
+               ;
+       else if(newts < oldts)
+       {
+               keep_our_modes = NO;
+               chptr->channelts = newts;
+       }
+       else
+               keep_new_modes = NO;
+
+       if(!keep_new_modes)
+               mode = *oldmode;
+       else if(keep_our_modes)
+       {
+               mode.mode |= oldmode->mode;
+               if(oldmode->limit > mode.limit)
+                       mode.limit = oldmode->limit;
+               if(strcmp(mode.key, oldmode->key) < 0)
+                       strcpy(mode.key, oldmode->key);
+               if(oldmode->join_num > mode.join_num ||
+                               (oldmode->join_num == mode.join_num &&
+                                oldmode->join_time > mode.join_time))
+               {
+                       mode.join_num = oldmode->join_num;
+                       mode.join_time = oldmode->join_time;
+               }
+               if(irccmp(mode.forward, oldmode->forward) < 0)
+                       strcpy(mode.forward, oldmode->forward);
+       }
+       else
+       {
+               /* If setting -j, clear join throttle state -- jilles */
+               if (!mode.join_num)
+                       chptr->join_count = chptr->join_delta = 0;
+       }
+
+       set_final_mode(&mode, oldmode);
+       chptr->mode = mode;
+
+       /* Lost the TS, other side wins, so remove modes on this side */
+       if(!keep_our_modes)
+       {
+               remove_our_modes(chptr, source_p);
+               DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->invites.head)
+               {
+                       del_invite(chptr, ptr->data);
+               }
+               sendto_channel_local(ALL_MEMBERS, chptr,
+                                    ":%s NOTICE %s :*** Notice -- TS for %s changed from %ld to %ld",
+                                    me.name, chptr->chname, chptr->chname,
+                                    (long) oldts, (long) newts);
+       }
+
+       if(*modebuf != '\0')
+               sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s %s %s",
+                                    source_p->user->server, chptr->chname, modebuf, parabuf);
+
+       *modebuf = *parabuf = '\0';
+
+       if(!IsMember(source_p, chptr))
+       {
+               add_user_to_channel(chptr, source_p, CHFL_PEON);
+               if (chptr->mode.join_num &&
+                       CurrentTime - chptr->join_delta >= chptr->mode.join_time)
+               {
+                       chptr->join_count = 0;
+                       chptr->join_delta = CurrentTime;
+               }
+               chptr->join_count++;
+               sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s",
+                                    source_p->name, source_p->username,
+                                    source_p->host, chptr->chname);
+       }
+
+       modes = channel_modes(chptr, client_p);
+       sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
+                     ":%s JOIN %ld %s %s",
+                     source_p->id, (long) chptr->channelts, chptr->chname, modes);
+       sendto_server(client_p, chptr, NOCAPS, CAP_TS6,
+                     ":%s SJOIN %ld %s %s :%s",
+                     source_p->user->server, (long) chptr->channelts,
+                     chptr->chname, modes, source_p->name);
+       return 0;
+}
+
+/*
+ * do_join_0
+ *
+ * inputs      - pointer to client doing join 0
+ * output      - NONE
+ * side effects        - Use has decided to join 0. This is legacy
+ *               from the days when channels were numbers not names. *sigh*
+ *               There is a bunch of evilness necessary here due to
+ *               anti spambot code.
+ */
+static void
+do_join_0(struct Client *client_p, struct Client *source_p)
+{
+       struct membership *msptr;
+       struct Channel *chptr = NULL;
+       dlink_node *ptr;
+
+       /* Finish the flood grace period... */
+       if(MyClient(source_p) && !IsFloodDone(source_p))
+               flood_endgrace(source_p);
+
+
+       sendto_server(client_p, NULL, NOCAPS, NOCAPS, ":%s JOIN 0", source_p->name);
+
+       if(source_p->user->channel.head && MyConnect(source_p) &&
+          !IsOper(source_p) && !IsExemptSpambot(source_p))
+               check_spambot_warning(source_p, NULL);
+
+       while((ptr = source_p->user->channel.head))
+       {
+               msptr = ptr->data;
+               chptr = msptr->chptr;
+               sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s",
+                                    source_p->name,
+                                    source_p->username, source_p->host, chptr->chname);
+               remove_user_from_channel(msptr);
+       }
+}
+
+static int
+check_channel_name_loc(struct Client *source_p, const char *name)
+{
+       s_assert(name != NULL);
+       if(EmptyString(name))
+               return 0;
+
+       if(ConfigFileEntry.disable_fake_channels && !IsOper(source_p))
+       {
+               for(; *name; ++name)
+               {
+                       if(!IsChanChar(*name) || IsFakeChanChar(*name))
+                               return 0;
+               }
+       }
+       else
+       {
+               for(; *name; ++name)
+               {
+                       if(!IsChanChar(*name))
+                               return 0;
+               }
+       }
+
+       return 1;
+}
+
+struct mode_letter
+{
+       int mode;
+       char letter;
+};
+
+static struct mode_letter flags[] = {
+       {MODE_NOPRIVMSGS, 'n'},
+       {MODE_TOPICLIMIT, 't'},
+       {MODE_SECRET, 's'},
+       {MODE_MODERATED, 'm'},
+       {MODE_INVITEONLY, 'i'},
+       {MODE_PRIVATE, 'p'},
+       {MODE_REGONLY, 'r'},
+       {MODE_EXLIMIT, 'L'},
+       {MODE_PERMANENT, 'P'},
+       {MODE_NOCOLOR, 'c'},
+       {MODE_FREEINVITE, 'g'},
+       {MODE_OPMODERATE, 'z'},
+       {MODE_FREETARGET, 'F'},
+       {MODE_DISFORWARD, 'Q'},
+       {0, 0}
+};
+
+static void
+set_final_mode(struct Mode *mode, struct Mode *oldmode)
+{
+       int dir = MODE_QUERY;
+       char *pbuf = parabuf;
+       int len;
+       int i;
+
+       /* ok, first get a list of modes we need to add */
+       for(i = 0; flags[i].letter; i++)
+       {
+               if((mode->mode & flags[i].mode) && !(oldmode->mode & flags[i].mode))
+               {
+                       if(dir != MODE_ADD)
+                       {
+                               *mbuf++ = '+';
+                               dir = MODE_ADD;
+                       }
+                       *mbuf++ = flags[i].letter;
+               }
+       }
+
+       /* now the ones we need to remove. */
+       for(i = 0; flags[i].letter; i++)
+       {
+               if((oldmode->mode & flags[i].mode) && !(mode->mode & flags[i].mode))
+               {
+                       if(dir != MODE_DEL)
+                       {
+                               *mbuf++ = '-';
+                               dir = MODE_DEL;
+                       }
+                       *mbuf++ = flags[i].letter;
+               }
+       }
+
+       if(oldmode->limit && !mode->limit)
+       {
+               if(dir != MODE_DEL)
+               {
+                       *mbuf++ = '-';
+                       dir = MODE_DEL;
+               }
+               *mbuf++ = 'l';
+       }
+       if(oldmode->key[0] && !mode->key[0])
+       {
+               if(dir != MODE_DEL)
+               {
+                       *mbuf++ = '-';
+                       dir = MODE_DEL;
+               }
+               *mbuf++ = 'k';
+               len = ircsprintf(pbuf, "%s ", oldmode->key);
+               pbuf += len;
+       }
+       if(oldmode->join_num && !mode->join_num)
+       {
+               if(dir != MODE_DEL)
+               {
+                       *mbuf++ = '-';
+                       dir = MODE_DEL;
+               }
+               *mbuf++ = 'j';
+       }
+       if(oldmode->forward[0] && !mode->forward[0])
+       {
+               if(dir != MODE_DEL)
+               {
+                       *mbuf++ = '-';
+                       dir = MODE_DEL;
+               }
+               *mbuf++ = 'f';
+       }
+       if(mode->limit && oldmode->limit != mode->limit)
+       {
+               if(dir != MODE_ADD)
+               {
+                       *mbuf++ = '+';
+                       dir = MODE_ADD;
+               }
+               *mbuf++ = 'l';
+               len = ircsprintf(pbuf, "%d ", mode->limit);
+               pbuf += len;
+       }
+       if(mode->key[0] && strcmp(oldmode->key, mode->key))
+       {
+               if(dir != MODE_ADD)
+               {
+                       *mbuf++ = '+';
+                       dir = MODE_ADD;
+               }
+               *mbuf++ = 'k';
+               len = ircsprintf(pbuf, "%s ", mode->key);
+               pbuf += len;
+       }
+       if(mode->join_num && (oldmode->join_num != mode->join_num || oldmode->join_time != mode->join_time))
+       {
+               if(dir != MODE_ADD)
+               {
+                       *mbuf++ = '+';
+                       dir = MODE_ADD;
+               }
+               *mbuf++ = 'j';
+               len = ircsprintf(pbuf, "%d:%d ", mode->join_num, mode->join_time);
+               pbuf += len;
+       }
+       if(mode->forward[0] && strcmp(oldmode->forward, mode->forward) && ConfigChannel.use_forward)
+       {
+               if(dir != MODE_ADD)
+               {
+                       *mbuf++ = '+';
+                       dir = MODE_ADD;
+               }
+               *mbuf++ = 'f';
+               len = ircsprintf(pbuf, "%s ", mode->forward);
+               pbuf += len;
+       }
+       *mbuf = '\0';
+}
+
+/*
+ * remove_our_modes
+ *
+ * inputs      -
+ * output      - 
+ * side effects        - 
+ */
+static void
+remove_our_modes(struct Channel *chptr, struct Client *source_p)
+{
+       struct membership *msptr;
+       dlink_node *ptr;
+       char lmodebuf[MODEBUFLEN];
+       char *lpara[MAXMODEPARAMS];
+       int count = 0;
+       int i;
+
+       mbuf = lmodebuf;
+       *mbuf++ = '-';
+
+       for(i = 0; i < MAXMODEPARAMS; i++)
+               lpara[i] = NULL;
+
+       DLINK_FOREACH(ptr, chptr->members.head)
+       {
+               msptr = ptr->data;
+
+               if(is_chanop(msptr))
+               {
+                       msptr->flags &= ~CHFL_CHANOP;
+                       lpara[count++] = msptr->client_p->name;
+                       *mbuf++ = 'o';
+
+                       /* +ov, might not fit so check. */
+                       if(is_voiced(msptr))
+                       {
+                               if(count >= MAXMODEPARAMS)
+                               {
+                                       *mbuf = '\0';
+                                       sendto_channel_local(ALL_MEMBERS, chptr,
+                                                            ":%s MODE %s %s %s %s %s %s",
+                                                            me.name, chptr->chname,
+                                                            lmodebuf, lpara[0], lpara[1],
+                                                            lpara[2], lpara[3]);
+
+                                       /* preserve the initial '-' */
+                                       mbuf = lmodebuf;
+                                       *mbuf++ = '-';
+                                       count = 0;
+
+                                       for(i = 0; i < MAXMODEPARAMS; i++)
+                                               lpara[i] = NULL;
+                               }
+
+                               msptr->flags &= ~CHFL_VOICE;
+                               lpara[count++] = msptr->client_p->name;
+                               *mbuf++ = 'v';
+                       }
+               }
+               else if(is_voiced(msptr))
+               {
+                       msptr->flags &= ~CHFL_VOICE;
+                       lpara[count++] = msptr->client_p->name;
+                       *mbuf++ = 'v';
+               }
+               else
+                       continue;
+
+               if(count >= MAXMODEPARAMS)
+               {
+                       *mbuf = '\0';
+                       sendto_channel_local(ALL_MEMBERS, chptr,
+                                            ":%s MODE %s %s %s %s %s %s",
+                                            me.name, chptr->chname, lmodebuf,
+                                            lpara[0], lpara[1], lpara[2], lpara[3]);
+                       mbuf = lmodebuf;
+                       *mbuf++ = '-';
+                       count = 0;
+
+                       for(i = 0; i < MAXMODEPARAMS; i++)
+                               lpara[i] = NULL;
+               }
+       }
+
+       if(count != 0)
+       {
+               *mbuf = '\0';
+               sendto_channel_local(ALL_MEMBERS, chptr,
+                                    ":%s MODE %s %s %s %s %s %s",
+                                    me.name, chptr->chname, lmodebuf,
+                                    EmptyString(lpara[0]) ? "" : lpara[0],
+                                    EmptyString(lpara[1]) ? "" : lpara[1],
+                                    EmptyString(lpara[2]) ? "" : lpara[2],
+                                    EmptyString(lpara[3]) ? "" : lpara[3]);
+
+       }
+}
diff --git a/modules/core/m_kick.c b/modules/core/m_kick.c
new file mode 100644 (file)
index 0000000..d475aaf
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_kick.c: Kicks a user from a channel.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_kick.c 258 2005-09-21 23:57:17Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "channel.h"
+#include "client.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "msg.h"
+#include "modules.h"
+#include "parse.h"
+#include "hash.h"
+#include "packet.h"
+#include "s_serv.h"
+
+static int m_kick(struct Client *, struct Client *, int, const char **);
+#define mg_kick { m_kick, 3 }
+
+struct Message kick_msgtab = {
+       "KICK", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_kick, mg_kick, mg_kick, mg_ignore, mg_kick}
+};
+
+mapi_clist_av1 kick_clist[] = { &kick_msgtab, NULL };
+
+DECLARE_MODULE_AV1(kick, NULL, NULL, kick_clist, NULL, NULL, "$Revision: 258 $");
+
+/*
+** m_kick
+**      parv[0] = sender prefix
+**      parv[1] = channel
+**      parv[2] = client to kick
+**      parv[3] = kick comment
+*/
+static int
+m_kick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct membership *msptr;
+       struct Client *who;
+       struct Channel *chptr;
+       int chasing = 0;
+       char *comment;
+       const char *name;
+       char *p = NULL;
+       const char *user;
+       static char buf[BUFSIZE];
+
+       if(MyClient(source_p) && !IsFloodDone(source_p))
+               flood_endgrace(source_p);
+
+       comment = LOCAL_COPY((EmptyString(parv[3])) ? parv[2] : parv[3]);
+       if(strlen(comment) > (size_t) REASONLEN)
+               comment[REASONLEN] = '\0';
+
+       *buf = '\0';
+       if((p = strchr(parv[1], ',')))
+               *p = '\0';
+
+       name = parv[1];
+
+       chptr = find_channel(name);
+       if(chptr == NULL)
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name);
+               return 0;
+       }
+
+       if(!IsServer(source_p))
+       {
+               msptr = find_channel_membership(chptr, source_p);
+
+               if((msptr == NULL) && MyConnect(source_p))
+               {
+                       sendto_one_numeric(source_p, ERR_NOTONCHANNEL,
+                                          form_str(ERR_NOTONCHANNEL), name);
+                       return 0;
+               }
+
+               if(!is_chanop(msptr))
+               {
+                       if(MyConnect(source_p))
+                       {
+                               sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
+                                          me.name, source_p->name, name);
+                               return 0;
+                       }
+
+                       /* If its a TS 0 channel, do it the old way */
+                       if(chptr->channelts == 0)
+                       {
+                               sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
+                                          get_id(&me, source_p), get_id(source_p, source_p), name);
+                               return 0;
+                       }
+               }
+
+               /* Its a user doing a kick, but is not showing as chanop locally
+                * its also not a user ON -my- server, and the channel has a TS.
+                * There are two cases we can get to this point then...
+                *
+                *     1) connect burst is happening, and for some reason a legit
+                *        op has sent a KICK, but the SJOIN hasn't happened yet or 
+                *        been seen. (who knows.. due to lag...)
+                *
+                *     2) The channel is desynced. That can STILL happen with TS
+                *        
+                *     Now, the old code roger wrote, would allow the KICK to 
+                *     go through. Thats quite legit, but lets weird things like
+                *     KICKS by users who appear not to be chanopped happen,
+                *     or even neater, they appear not to be on the channel.
+                *     This fits every definition of a desync, doesn't it? ;-)
+                *     So I will allow the KICK, otherwise, things are MUCH worse.
+                *     But I will warn it as a possible desync.
+                *
+                *     -Dianora
+                */
+       }
+
+       if((p = strchr(parv[2], ',')))
+               *p = '\0';
+
+       user = parv[2];         /* strtoken(&p2, parv[2], ","); */
+
+       if(!(who = find_chasing(source_p, user, &chasing)))
+       {
+               return 0;
+       }
+
+       msptr = find_channel_membership(chptr, who);
+
+       if(msptr != NULL)
+       {
+               if(MyClient(source_p) && IsService(who))
+               {
+                       sendto_one(source_p, form_str(ERR_ISCHANSERVICE),
+                                  me.name, source_p->name, who->name, chptr->chname);
+                       return 0;
+               }
+
+               /* jdc
+                * - In the case of a server kicking a user (i.e. CLEARCHAN),
+                *   the kick should show up as coming from the server which did
+                *   the kick.
+                * - Personally, flame and I believe that server kicks shouldn't
+                *   be sent anyways.  Just waiting for some oper to abuse it...
+                */
+               if(IsServer(source_p))
+                       sendto_channel_local(ALL_MEMBERS, chptr, ":%s KICK %s %s :%s",
+                                            source_p->name, name, who->name, comment);
+               else
+                       sendto_channel_local(ALL_MEMBERS, chptr,
+                                            ":%s!%s@%s KICK %s %s :%s",
+                                            source_p->name, source_p->username,
+                                            source_p->host, name, who->name, comment);
+
+               sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
+                             ":%s KICK %s %s :%s",
+                             use_id(source_p), chptr->chname, use_id(who), comment);
+               sendto_server(client_p, chptr, NOCAPS, CAP_TS6,
+                             ":%s KICK %s %s :%s",
+                             source_p->name, chptr->chname, who->name, comment);
+               remove_user_from_channel(msptr);
+       }
+       else if (MyClient(source_p))
+               sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,
+                                  form_str(ERR_USERNOTINCHANNEL), user, name);
+
+       return 0;
+}
diff --git a/modules/core/m_kill.c b/modules/core/m_kill.c
new file mode 100644 (file)
index 0000000..5a07abf
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_kill.c: Kills a user.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_kill.c 2755 2006-11-10 19:08:03Z jilles $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "hash.h"              /* for find_client() */
+#include "ircd.h"
+#include "numeric.h"
+#include "sprintf_irc.h"
+#include "s_log.h"
+#include "s_serv.h"
+#include "s_conf.h"
+#include "send.h"
+#include "whowas.h"
+#include "irc_string.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_newconf.h"
+
+static char buf[BUFSIZE];
+
+static int ms_kill(struct Client *, struct Client *, int, const char **);
+static int mo_kill(struct Client *, struct Client *, int, const char **);
+static void relay_kill(struct Client *, struct Client *, struct Client *,
+                      const char *, const char *);
+
+struct Message kill_msgtab = {
+       "KILL", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, {ms_kill, 2}, {ms_kill, 2}, mg_ignore, {mo_kill, 2}}
+};
+
+mapi_clist_av1 kill_clist[] = { &kill_msgtab, NULL };
+
+DECLARE_MODULE_AV1(kill, NULL, NULL, kill_clist, NULL, NULL, "$Revision: 2755 $");
+
+/*
+** mo_kill
+**      parv[0] = sender prefix
+**      parv[1] = kill victim
+**      parv[2] = kill path
+*/
+static int
+mo_kill(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+       const char *inpath = client_p->name;
+       const char *user;
+       const char *reason;
+
+       user = parv[1];
+
+       if(!IsOperLocalKill(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "local_kill");
+               return 0;
+       }
+
+       if(!EmptyString(parv[2]))
+       {
+               char *s;
+               s = LOCAL_COPY(parv[2]);
+               if(strlen(s) > (size_t) KILLLEN)
+                       s[KILLLEN] = '\0';
+               reason = s;
+       }
+       else
+               reason = "<No reason given>";
+
+       if((target_p = find_named_person(user)) == NULL)
+       {
+               /*
+                ** If the user has recently changed nick, automatically
+                ** rewrite the KILL for this new nickname--this keeps
+                ** servers in synch when nick change and kill collide
+                */
+               if((target_p = get_history(user, (long) KILLCHASETIMELIMIT)) == NULL)
+               {
+                       if (strchr(user, '.'))
+                               sendto_one_numeric(source_p, ERR_CANTKILLSERVER, form_str(ERR_CANTKILLSERVER));
+                       else
+                               sendto_one_numeric(source_p, ERR_NOSUCHNICK,
+                                                  form_str(ERR_NOSUCHNICK), user);
+                       return 0;
+               }
+               sendto_one(source_p, ":%s NOTICE %s :KILL changed from %s to %s",
+                          me.name, parv[0], user, target_p->name);
+       }
+
+       if(!MyConnect(target_p) && (!IsOperGlobalKill(source_p)))
+       {
+               sendto_one(source_p, ":%s NOTICE %s :Nick %s isnt on your server",
+                          me.name, parv[0], target_p->name);
+               return 0;
+       }
+
+       if(MyConnect(target_p))
+               sendto_one(target_p, ":%s!%s@%s KILL %s :%s",
+                          source_p->name, source_p->username, source_p->host,
+                          target_p->name, reason);
+
+       /* Do not change the format of this message.  There's no point in changing messages
+        * that have been around for ever, for no reason.. */
+       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                            "Received KILL message for %s. From %s Path: %s (%s)",
+                            target_p->name, parv[0], me.name, reason);
+
+       ilog(L_KILL, "%c %s %s!%s@%s %s %s",
+            MyConnect(target_p) ? 'L' : 'G', get_oper_name(source_p),
+            target_p->name, target_p->username, target_p->host, target_p->user->server, reason);
+
+       /*
+        ** 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.
+        ** Suicide kills are NOT passed on --SRB
+        */
+       if(!MyConnect(target_p))
+       {
+               relay_kill(client_p, source_p, target_p, inpath, reason);
+               /*
+                ** Set FLAGS_KILLED. This prevents exit_one_client from sending
+                ** the unnecessary QUIT for this. (This flag should never be
+                ** set in any other place)
+                */
+               target_p->flags |= FLAGS_KILLED;
+       }
+
+       ircsprintf(buf, "Killed (%s (%s))", source_p->name, reason);
+
+       exit_client(client_p, target_p, source_p, buf);
+
+       return 0;
+}
+
+/*
+ * ms_kill
+ *      parv[0] = sender prefix
+ *      parv[1] = kill victim
+ *      parv[2] = kill path and reason
+ */
+static int
+ms_kill(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+       const char *user;
+       const char *reason;
+       char default_reason[] = "<No reason given>";
+       const char *path;
+       int chasing = 0;
+
+       *buf = '\0';
+
+       user = parv[1];
+
+       if(EmptyString(parv[2]))
+       {
+               reason = default_reason;
+
+               /* hyb6 takes the nick of the killer from the path *sigh* --fl_ */
+               path = source_p->name;
+       }
+       else
+       {
+               char *s = LOCAL_COPY(parv[2]), *t;
+               t = strchr(s, ' ');
+
+               if(t)
+               {
+                       *t = '\0';
+                       t++;
+                       reason = t;
+               }
+               else
+                       reason = default_reason;
+
+               path = s;
+       }
+
+       if((target_p = find_person(user)) == NULL)
+       {
+               /*
+                * If the user has recently changed nick, but only if its 
+                * not an uid, automatically rewrite the KILL for this new nickname.
+                * --this keeps servers in synch when nick change and kill collide
+                */
+               if(IsDigit(*user) || (!(target_p = get_history(user, (long) KILLCHASETIMELIMIT))))
+               {
+                       sendto_one_numeric(source_p, ERR_NOSUCHNICK,
+                                          form_str(ERR_NOSUCHNICK), IsDigit(*user) ? "*" : user);
+                       return 0;
+               }
+               sendto_one_notice(source_p, ":KILL changed from %s to %s", user, target_p->name);
+               chasing = 1;
+       }
+
+       if(IsServer(target_p) || IsMe(target_p))
+       {
+               sendto_one_numeric(source_p, ERR_CANTKILLSERVER, form_str(ERR_CANTKILLSERVER));
+               return 0;
+       }
+
+       if(MyConnect(target_p))
+       {
+               if(IsServer(source_p))
+               {
+                       sendto_one(target_p, ":%s KILL %s :%s",
+                                  source_p->name, target_p->name, reason);
+               }
+               else
+                       sendto_one(target_p, ":%s!%s@%s KILL %s :%s",
+                                  source_p->name, source_p->username, source_p->host,
+                                  target_p->name, reason);
+       }
+
+       /* Be warned, this message must be From %s, or it confuses clients
+        * so dont change it to From: or the case or anything! -- fl -- db */
+       /* path must contain at least 2 !'s, or bitchx falsely declares it
+        * local --fl
+        */
+       if(IsOper(source_p))    /* send it normally */
+       {
+               sendto_realops_snomask(IsService(source_p) ? SNO_SKILL : SNO_GENERAL, L_ALL,
+                                    "Received KILL message for %s. From %s Path: %s!%s!%s!%s %s",
+                                    target_p->name, parv[0], source_p->user->server,
+                                    source_p->host, source_p->username, source_p->name, reason);
+
+               ilog(L_KILL, "%c %s %s!%s@%s %s %s",
+                    MyConnect(target_p) ? 'O' : 'R', get_oper_name(source_p),
+                    target_p->name, target_p->username, target_p->host,
+                    target_p->user->server, reason);
+       }
+       else
+       {
+               sendto_realops_snomask(SNO_SKILL, L_ALL,
+                                    "Received KILL message for %s. From %s %s",
+                                    target_p->name, parv[0], reason);
+
+               ilog(L_KILL, "S %s %s!%s@%s %s %s",
+                    source_p->name, target_p->name, target_p->username,
+                    target_p->host, target_p->user->server, reason);
+       }
+
+       relay_kill(client_p, source_p, target_p, path, reason);
+
+       /* FLAGS_KILLED prevents a quit being sent out */
+       target_p->flags |= FLAGS_KILLED;
+
+       ircsprintf(buf, "Killed (%s %s)", source_p->name, reason);
+
+       exit_client(client_p, target_p, source_p, buf);
+
+       return 0;
+}
+
+static void
+relay_kill(struct Client *one, struct Client *source_p,
+          struct Client *target_p, const char *inpath, const char *reason)
+{
+       struct Client *client_p;
+       dlink_node *ptr;
+       char buffer[BUFSIZE];
+
+       if(MyClient(source_p))
+               ircsnprintf(buffer, sizeof(buffer),
+                           "%s!%s!%s!%s (%s)",
+                           me.name, source_p->host, source_p->username, source_p->name, reason);
+       else
+               ircsnprintf(buffer, sizeof(buffer), "%s %s", inpath, reason);
+
+       DLINK_FOREACH(ptr, serv_list.head)
+       {
+               client_p = ptr->data;
+
+               if(!client_p || client_p == one)
+                       continue;
+
+               sendto_one(client_p, ":%s KILL %s :%s",
+                          get_id(source_p, client_p), get_id(target_p, client_p), buffer);
+       }
+}
diff --git a/modules/core/m_message.c b/modules/core/m_message.c
new file mode 100644 (file)
index 0000000..b1e09a1
--- /dev/null
@@ -0,0 +1,1032 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_message.c: Sends a (PRIVMSG|NOTICE) message to a user or channel.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_message.c 1761 2006-07-27 19:27:49Z jilles $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "common.h"
+#include "s_conf.h"
+#include "s_serv.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "channel.h"
+#include "irc_string.h"
+#include "hash.h"
+#include "class.h"
+#include "msg.h"
+#include "packet.h"
+#include "send.h"
+#include "event.h"
+#include "patricia.h"
+#include "s_newconf.h"
+
+static int m_message(int, const char *, struct Client *, struct Client *, int, const char **);
+static int m_privmsg(struct Client *, struct Client *, int, const char **);
+static int m_notice(struct Client *, struct Client *, int, const char **);
+
+static void expire_tgchange(void *unused);
+
+static int
+modinit(void)
+{
+       eventAddIsh("expire_tgchange", expire_tgchange, NULL, 300);
+       expire_tgchange(NULL);
+       return 0;
+}
+
+static void
+moddeinit(void)
+{
+       eventDelete(expire_tgchange, NULL);
+}
+
+struct Message privmsg_msgtab = {
+       "PRIVMSG", 0, 0, 0, MFLG_SLOW | MFLG_UNREG,
+       {mg_unreg, {m_privmsg, 0}, {m_privmsg, 0}, mg_ignore, mg_ignore, {m_privmsg, 0}}
+};
+struct Message notice_msgtab = {
+       "NOTICE", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_notice, 0}, {m_notice, 0}, {m_notice, 0}, mg_ignore, {m_notice, 0}}
+};
+
+mapi_clist_av1 message_clist[] = { &privmsg_msgtab, &notice_msgtab, NULL };
+
+DECLARE_MODULE_AV1(message, modinit, moddeinit, message_clist, NULL, NULL, "$Revision: 1761 $");
+
+struct entity
+{
+       void *ptr;
+       int type;
+       int flags;
+};
+
+static int build_target_list(int p_or_n, const char *command,
+                            struct Client *client_p,
+                            struct Client *source_p, const char *nicks_channels, const char *text);
+
+static int flood_attack_client(int p_or_n, struct Client *source_p, struct Client *target_p);
+static int flood_attack_channel(int p_or_n, struct Client *source_p,
+                               struct Channel *chptr, char *chname);
+static struct Client *find_userhost(const char *, const char *, int *);
+
+#define ENTITY_NONE    0
+#define ENTITY_CHANNEL 1
+#define ENTITY_CHANOPS_ON_CHANNEL 2
+#define ENTITY_CLIENT  3
+
+static struct entity targets[512];
+static int ntargets = 0;
+
+static int duplicate_ptr(void *);
+
+static void msg_channel(int p_or_n, const char *command,
+                       struct Client *client_p,
+                       struct Client *source_p, struct Channel *chptr, const char *text);
+
+static void msg_channel_flags(int p_or_n, const char *command,
+                             struct Client *client_p,
+                             struct Client *source_p,
+                             struct Channel *chptr, int flags, const char *text);
+
+static void msg_client(int p_or_n, const char *command,
+                      struct Client *source_p, struct Client *target_p, const char *text);
+
+static void handle_special(int p_or_n, const char *command,
+                          struct Client *client_p, struct Client *source_p, const char *nick,
+                          const char *text);
+
+/*
+** m_privmsg
+**
+** massive cleanup
+** rev argv 6/91
+**
+**   Another massive cleanup Nov, 2000
+** (I don't think there is a single line left from 6/91. Maybe.)
+** m_privmsg and m_notice do basically the same thing.
+** in the original 2.8.2 code base, they were the same function
+** "m_message.c." When we did the great cleanup in conjuncton with bleep
+** of ircu fame, we split m_privmsg.c and m_notice.c.
+** I don't see the point of that now. Its harder to maintain, its
+** easier to introduce bugs into one version and not the other etc.
+** Really, the penalty of an extra function call isn't that big a deal folks.
+** -db Nov 13, 2000
+**
+*/
+
+#define PRIVMSG 0
+#define NOTICE  1
+
+static int
+m_privmsg(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       return m_message(PRIVMSG, "PRIVMSG", client_p, source_p, parc, parv);
+}
+
+static int
+m_notice(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       return m_message(NOTICE, "NOTICE", client_p, source_p, parc, parv);
+}
+
+/*
+ * inputs      - flag privmsg or notice
+ *             - pointer to command "PRIVMSG" or "NOTICE"
+ *             - pointer to client_p
+ *             - pointer to source_p
+ *             - pointer to channel
+ */
+static int
+m_message(int p_or_n,
+         const char *command,
+         struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       int i;
+
+       if(parc < 2 || EmptyString(parv[1]))
+       {
+               if(p_or_n != NOTICE)
+                       sendto_one(source_p, form_str(ERR_NORECIPIENT), me.name,
+                                  source_p->name, command);
+               return 0;
+       }
+
+       if(parc < 3 || EmptyString(parv[2]))
+       {
+               if(p_or_n != NOTICE)
+                       sendto_one(source_p, form_str(ERR_NOTEXTTOSEND), me.name, source_p->name);
+               return 0;
+       }
+
+       /* Finish the flood grace period if theyre not messaging themselves
+        * as some clients (ircN) do this as a "lag check"
+        */
+       if(MyClient(source_p) && !IsFloodDone(source_p) && irccmp(source_p->name, parv[1]))
+               flood_endgrace(source_p);
+
+       if(build_target_list(p_or_n, command, client_p, source_p, parv[1], parv[2]) < 0)
+       {
+               return 0;
+       }
+
+       for(i = 0; i < ntargets; i++)
+       {
+               switch (targets[i].type)
+               {
+               case ENTITY_CHANNEL:
+                       msg_channel(p_or_n, command, client_p, source_p,
+                                   (struct Channel *) targets[i].ptr, parv[2]);
+                       break;
+
+               case ENTITY_CHANOPS_ON_CHANNEL:
+                       msg_channel_flags(p_or_n, command, client_p, source_p,
+                                         (struct Channel *) targets[i].ptr,
+                                         targets[i].flags, parv[2]);
+                       break;
+
+               case ENTITY_CLIENT:
+                       msg_client(p_or_n, command, source_p,
+                                  (struct Client *) targets[i].ptr, parv[2]);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * build_target_list
+ *
+ * inputs      - pointer to given client_p (server)
+ *             - pointer to given source (oper/client etc.)
+ *             - pointer to list of nicks/channels
+ *             - pointer to table to place results
+ *             - pointer to text (only used if source_p is an oper)
+ * output      - number of valid entities
+ * side effects        - target_table is modified to contain a list of
+ *               pointers to channels or clients
+ *               if source client is an oper
+ *               all the classic old bizzare oper privmsg tricks
+ *               are parsed and sent as is, if prefixed with $
+ *               to disambiguate.
+ *
+ */
+
+static int
+build_target_list(int p_or_n, const char *command, struct Client *client_p,
+                 struct Client *source_p, const char *nicks_channels, const char *text)
+{
+       int type;
+       char *p, *nick, *target_list;
+       struct Channel *chptr = NULL;
+       struct Client *target_p;
+
+       target_list = LOCAL_COPY(nicks_channels);       /* skip strcpy for non-lazyleafs */
+
+       ntargets = 0;
+
+       for(nick = strtoken(&p, target_list, ","); nick; nick = strtoken(&p, NULL, ","))
+       {
+               char *with_prefix;
+               /*
+                * channels are privmsg'd a lot more than other clients, moved up
+                * here plain old channel msg?
+                */
+
+               if(IsChanPrefix(*nick))
+               {
+                       /* ignore send of local channel to a server (should not happen) */
+                       if(IsServer(client_p) && *nick == '&')
+                               continue;
+
+                       if((chptr = find_channel(nick)) != NULL)
+                       {
+                               if(!duplicate_ptr(chptr))
+                               {
+                                       if(ntargets >= ConfigFileEntry.max_targets)
+                                       {
+                                               sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
+                                                          me.name, source_p->name, nick);
+                                               return (1);
+                                       }
+                                       targets[ntargets].ptr = (void *) chptr;
+                                       targets[ntargets++].type = ENTITY_CHANNEL;
+                               }
+                       }
+
+                       /* non existant channel */
+                       else if(p_or_n != NOTICE)
+                               sendto_one_numeric(source_p, ERR_NOSUCHNICK,
+                                                  form_str(ERR_NOSUCHNICK), nick);
+
+                       continue;
+               }
+
+               if(MyClient(source_p))
+                       target_p = find_named_person(nick);
+               else
+                       target_p = find_person(nick);
+
+               /* look for a privmsg to another client */
+               if(target_p)
+               {
+                       if(!duplicate_ptr(target_p))
+                       {
+                               if(ntargets >= ConfigFileEntry.max_targets)
+                               {
+                                       sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
+                                                  me.name, source_p->name, nick);
+                                       return (1);
+                               }
+                               targets[ntargets].ptr = (void *) target_p;
+                               targets[ntargets].type = ENTITY_CLIENT;
+                               targets[ntargets++].flags = 0;
+                       }
+                       continue;
+               }
+
+               /* @#channel or +#channel message ? */
+
+               type = 0;
+               with_prefix = nick;
+               /*  allow %+@ if someone wants to do that */
+               for(;;)
+               {
+                       if(*nick == '@')
+                               type |= CHFL_CHANOP;
+                       else if(*nick == '+')
+                               type |= CHFL_CHANOP | CHFL_VOICE;
+                       else
+                               break;
+                       nick++;
+               }
+
+               if(type != 0)
+               {
+                       /* no recipient.. */
+                       if(EmptyString(nick))
+                       {
+                               sendto_one(source_p, form_str(ERR_NORECIPIENT),
+                                          me.name, source_p->name, command);
+                               continue;
+                       }
+
+                       /* At this point, nick+1 should be a channel name i.e. #foo or &foo
+                        * if the channel is found, fine, if not report an error
+                        */
+
+                       if((chptr = find_channel(nick)) != NULL)
+                       {
+                               struct membership *msptr;
+
+                               msptr = find_channel_membership(chptr, source_p);
+
+                               if(!IsServer(source_p) && !IsService(source_p) && !is_chanop_voiced(msptr))
+                               {
+                                       sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
+                                                  me.name, source_p->name, with_prefix);
+                                       return (-1);
+                               }
+
+                               if(!duplicate_ptr(chptr))
+                               {
+                                       if(ntargets >= ConfigFileEntry.max_targets)
+                                       {
+                                               sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
+                                                          me.name, source_p->name, nick);
+                                               return (1);
+                                       }
+                                       targets[ntargets].ptr = (void *) chptr;
+                                       targets[ntargets].type = ENTITY_CHANOPS_ON_CHANNEL;
+                                       targets[ntargets++].flags = type;
+                               }
+                       }
+                       else if(p_or_n != NOTICE)
+                       {
+                               sendto_one_numeric(source_p, ERR_NOSUCHNICK,
+                                                  form_str(ERR_NOSUCHNICK), nick);
+                       }
+
+                       continue;
+               }
+
+               if(strchr(nick, '@') || (IsOper(source_p) && (*nick == '$')))
+               {
+                       handle_special(p_or_n, command, client_p, source_p, nick, text);
+                       continue;
+               }
+
+               /* no matching anything found - error if not NOTICE */
+               if(p_or_n != NOTICE)
+               {
+                       /* dont give this numeric when source is local,
+                        * because its misleading --anfl
+                        */
+                       if(!MyClient(source_p) && IsDigit(*nick))
+                               sendto_one(source_p, ":%s %d %s * :Target left IRC. "
+                                          "Failed to deliver: [%.20s]",
+                                          get_id(&me, source_p), ERR_NOSUCHNICK,
+                                          get_id(source_p, source_p), text);
+                       else
+                               sendto_one_numeric(source_p, ERR_NOSUCHNICK,
+                                                  form_str(ERR_NOSUCHNICK), nick);
+               }
+
+       }
+       return (1);
+}
+
+/*
+ * duplicate_ptr
+ *
+ * inputs      - pointer to check
+ *             - pointer to table of entities
+ *             - number of valid entities so far
+ * output      - YES if duplicate pointer in table, NO if not.
+ *               note, this does the canonize using pointers
+ * side effects        - NONE
+ */
+static int
+duplicate_ptr(void *ptr)
+{
+       int i;
+       for(i = 0; i < ntargets; i++)
+               if(targets[i].ptr == ptr)
+                       return YES;
+       return NO;
+}
+
+/*
+ * msg_channel
+ *
+ * inputs      - flag privmsg or notice
+ *             - pointer to command "PRIVMSG" or "NOTICE"
+ *             - pointer to client_p
+ *             - pointer to source_p
+ *             - pointer to channel
+ * output      - NONE
+ * side effects        - message given channel
+ *
+ * XXX - We need to rework this a bit, it's a tad ugly. --nenolod
+ */
+static void
+msg_channel(int p_or_n, const char *command,
+           struct Client *client_p, struct Client *source_p, struct Channel *chptr,
+           const char *text)
+{
+       int result;
+       char text2[BUFSIZE];
+
+       if(MyClient(source_p))
+       {
+               /* idle time shouldnt be reset by notices --fl */
+               if(p_or_n != NOTICE)
+                       source_p->localClient->last = CurrentTime;
+       }
+
+       if(chptr->mode.mode & MODE_NOCOLOR)
+       {
+               strlcpy(text2, text, BUFSIZE);
+               strip_colour(text2);
+               text = text2;
+               if (EmptyString(text))
+               {
+                       /* could be empty after colour stripping and
+                        * that would cause problems later */
+                       if(p_or_n != NOTICE)
+                               sendto_one(source_p, form_str(ERR_NOTEXTTOSEND), me.name, source_p->name);
+                       return;
+               }
+       }
+
+       /* chanops and voiced can flood their own channel with impunity */
+       if((result = can_send(chptr, source_p, NULL)))
+       {
+               if(result == CAN_SEND_OPV ||
+                  !flood_attack_channel(p_or_n, source_p, chptr, chptr->chname))
+               {
+                       sendto_channel_flags(client_p, ALL_MEMBERS, source_p, chptr,
+                                            "%s %s :%s", command, chptr->chname, text);
+               }
+       }
+       else if(chptr->mode.mode & MODE_OPMODERATE &&
+                       chptr->mode.mode & MODE_MODERATED &&
+                       IsMember(source_p, chptr))
+       {
+               /* only do +z for +m channels for now, as bans/quiets
+                * aren't tested for remote clients -- jilles */
+               if(!flood_attack_channel(p_or_n, source_p, chptr, chptr->chname))
+               {
+                       sendto_channel_flags(client_p, ONLY_CHANOPS, source_p, chptr,
+                                            "%s %s :%s", command, chptr->chname, text);
+               }
+       }
+       else
+       {
+               if(p_or_n != NOTICE)
+                       sendto_one_numeric(source_p, ERR_CANNOTSENDTOCHAN,
+                                          form_str(ERR_CANNOTSENDTOCHAN), chptr->chname);
+       }
+}
+
+/*
+ * msg_channel_flags
+ *
+ * inputs      - flag 0 if PRIVMSG 1 if NOTICE. RFC 
+ *               say NOTICE must not auto reply
+ *             - pointer to command, "PRIVMSG" or "NOTICE"
+ *             - pointer to client_p
+ *             - pointer to source_p
+ *             - pointer to channel
+ *             - flags
+ *             - pointer to text to send
+ * output      - NONE
+ * side effects        - message given channel either chanop or voice
+ */
+static void
+msg_channel_flags(int p_or_n, const char *command, struct Client *client_p,
+                 struct Client *source_p, struct Channel *chptr, int flags, const char *text)
+{
+       int type;
+       char c;
+
+       if(flags & CHFL_VOICE)
+       {
+               type = ONLY_CHANOPSVOICED;
+               c = '+';
+       }
+       else
+       {
+               type = ONLY_CHANOPS;
+               c = '@';
+       }
+
+       if(MyClient(source_p))
+       {
+               /* idletime shouldnt be reset by notice --fl */
+               if(p_or_n != NOTICE)
+                       source_p->localClient->last = CurrentTime;
+       }
+
+       sendto_channel_flags(client_p, type, source_p, chptr, "%s %c%s :%s",
+                            command, c, chptr->chname, text);
+}
+
+#define PREV_FREE_TARGET(x) ((FREE_TARGET(x) == 0) ? 9 : FREE_TARGET(x) - 1)
+#define PREV_TARGET(i) ((i == 0) ? i = 9 : --i)
+#define NEXT_TARGET(i) ((i == 9) ? i = 0 : ++i)
+
+static void
+expire_tgchange(void *unused)
+{
+       tgchange *target;
+       dlink_node *ptr, *next_ptr;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, tgchange_list.head)
+       {
+               target = ptr->data;
+
+               if(target->expiry < CurrentTime)
+               {
+                       dlinkDelete(ptr, &tgchange_list);
+                       patricia_remove(tgchange_tree, target->pnode);
+                       MyFree(target->ip);
+                       MyFree(target);
+               }
+       }
+}
+
+static int
+add_target(struct Client *source_p, struct Client *target_p)
+{
+       int i, j;
+
+       /* can msg themselves or services without using any target slots */
+       if(source_p == target_p || IsService(target_p))
+               return 1;
+
+       /* special condition for those who have had PRIVMSG crippled to allow them
+        * to talk to IRCops still.
+        *
+        * XXX: is this controversial?
+        */
+       if(source_p->localClient->target_last > CurrentTime && IsOper(target_p))
+               return 1;
+
+       if(USED_TARGETS(source_p))
+       {
+               /* hunt for an existing target */
+               for(i = PREV_FREE_TARGET(source_p), j = USED_TARGETS(source_p);
+                   j; --j, PREV_TARGET(i))
+               {
+                       if(source_p->localClient->targets[i] == target_p)
+                               return 1;
+               }
+
+               /* first message after connect, we may only start clearing
+                * slots after this message --anfl
+                */
+               if(!IsTGChange(source_p))
+               {
+                       SetTGChange(source_p);
+                       source_p->localClient->target_last = CurrentTime;
+               }
+               /* clear as many targets as we can */
+               else if((i = (CurrentTime - source_p->localClient->target_last) / 60))
+               {
+                       if(i > USED_TARGETS(source_p))
+                               USED_TARGETS(source_p) = 0;
+                       else
+                               USED_TARGETS(source_p) -= i;
+
+                       source_p->localClient->target_last = CurrentTime;
+               }
+               /* cant clear any, full target list */
+               else if(USED_TARGETS(source_p) == 10)
+               {
+                       add_tgchange(source_p->sockhost);
+                       return 0;
+               }
+       }
+       /* no targets in use, reset their target_last so that they cant
+        * abuse a long idle to get targets back more quickly
+        */
+       else
+       {
+               source_p->localClient->target_last = CurrentTime;
+               SetTGChange(source_p);
+       }
+
+       source_p->localClient->targets[FREE_TARGET(source_p)] = target_p;
+       NEXT_TARGET(FREE_TARGET(source_p));
+       ++USED_TARGETS(source_p);
+       return 1;
+}
+
+/*
+ * msg_client
+ *
+ * inputs      - flag 0 if PRIVMSG 1 if NOTICE. RFC 
+ *               say NOTICE must not auto reply
+ *             - pointer to command, "PRIVMSG" or "NOTICE"
+ *             - pointer to source_p source (struct Client *)
+ *             - pointer to target_p target (struct Client *)
+ *             - pointer to text
+ * output      - NONE
+ * side effects        - message given channel either chanop or voice
+ */
+static void
+msg_client(int p_or_n, const char *command,
+          struct Client *source_p, struct Client *target_p, const char *text)
+{
+       if(MyClient(source_p))
+       {
+               /* reset idle time for message only if its not to self 
+                * and its not a notice */
+               if(p_or_n != NOTICE)
+                       source_p->localClient->last = CurrentTime;
+
+               /* target change stuff, dont limit ctcp replies as that
+                * would allow people to start filling up random users
+                * targets just by ctcping them
+                */
+               if((p_or_n != NOTICE || *text != '\001') &&
+                  ConfigFileEntry.target_change && !IsOper(source_p))
+               {
+                       if(!add_target(source_p, target_p))
+                       {
+                               sendto_one(source_p, form_str(ERR_TARGCHANGE),
+                                          me.name, source_p->name, target_p->name);
+                               return;
+                       }
+               }
+       }
+       else if(source_p->from == target_p->from)
+       {
+               sendto_realops_snomask(SNO_DEBUG, L_ALL,
+                                    "Send message to %s[%s] dropped from %s(Fake Dir)",
+                                    target_p->name, target_p->from->name, source_p->name);
+               return;
+       }
+
+       if(MyConnect(source_p) && (p_or_n != NOTICE) && target_p->user && target_p->user->away)
+               sendto_one_numeric(source_p, RPL_AWAY, form_str(RPL_AWAY),
+                                  target_p->name, target_p->user->away);
+
+       if(MyClient(target_p))
+       {
+               /* XXX Controversial? allow opers always to send through a +g */
+               if(!IsServer(source_p) && (IsSetCallerId(target_p) ||
+                                       (IsSetRegOnlyMsg(target_p) && !source_p->user->suser[0])))
+               {
+                       /* Here is the anti-flood bot/spambot code -db */
+                       if(accept_message(source_p, target_p) || IsOper(source_p))
+                       {
+                               sendto_one(target_p, ":%s!%s@%s %s %s :%s",
+                                          source_p->name,
+                                          source_p->username,
+                                          source_p->host, command, target_p->name, text);
+                       }
+                       else if (IsSetRegOnlyMsg(target_p) && !source_p->user->suser[0])
+                       {
+                               if (p_or_n != NOTICE)
+                                       sendto_one_numeric(source_p, ERR_NONONREG,
+                                                       form_str(ERR_NONONREG),
+                                                       target_p->name);
+                               /* Only so opers can watch for floods */
+                               (void) flood_attack_client(p_or_n, source_p, target_p);
+                       }
+                       else
+                       {
+                               /* check for accept, flag recipient incoming message */
+                               if(p_or_n != NOTICE)
+                               {
+                                       sendto_one_numeric(source_p, ERR_TARGUMODEG,
+                                                          form_str(ERR_TARGUMODEG),
+                                                          target_p->name);
+                               }
+
+                               if((target_p->localClient->last_caller_id_time +
+                                   ConfigFileEntry.caller_id_wait) < CurrentTime)
+                               {
+                                       if(p_or_n != NOTICE)
+                                               sendto_one_numeric(source_p, RPL_TARGNOTIFY,
+                                                                  form_str(RPL_TARGNOTIFY),
+                                                                  target_p->name);
+
+                                       sendto_one(target_p, form_str(RPL_UMODEGMSG),
+                                                  me.name, target_p->name, source_p->name,
+                                                  source_p->username, source_p->host);
+
+                                       target_p->localClient->last_caller_id_time = CurrentTime;
+                               }
+                               /* Only so opers can watch for floods */
+                               (void) flood_attack_client(p_or_n, source_p, target_p);
+                       }
+               }
+               else
+               {
+                       /* If the client is remote, we dont perform a special check for
+                        * flooding.. as we wouldnt block their message anyway.. this means
+                        * we dont give warnings.. we then check if theyre opered 
+                        * (to avoid flood warnings), lastly if theyre our client
+                        * and flooding    -- fl */
+                       if(!MyClient(source_p) || IsOper(source_p) ||
+                          !flood_attack_client(p_or_n, source_p, target_p))
+                               sendto_anywhere(target_p, source_p, command, ":%s", text);
+               }
+       }
+       else if(!MyClient(source_p) || IsOper(source_p) ||
+               !flood_attack_client(p_or_n, source_p, target_p))
+               sendto_anywhere(target_p, source_p, command, ":%s", text);
+
+       return;
+}
+
+/*
+ * flood_attack_client
+ * inputs       - flag 0 if PRIVMSG 1 if NOTICE. RFC
+ *                say NOTICE must not auto reply
+ *              - pointer to source Client 
+ *             - pointer to target Client
+ * output      - 1 if target is under flood attack
+ * side effects        - check for flood attack on target target_p
+ */
+static int
+flood_attack_client(int p_or_n, struct Client *source_p, struct Client *target_p)
+{
+       int delta;
+
+       if(GlobalSetOptions.floodcount && MyConnect(target_p) && IsClient(source_p))
+       {
+               if((target_p->localClient->first_received_message_time + 1) < CurrentTime)
+               {
+                       delta = CurrentTime - target_p->localClient->first_received_message_time;
+                       target_p->localClient->received_number_of_privmsgs -= delta;
+                       target_p->localClient->first_received_message_time = CurrentTime;
+                       if(target_p->localClient->received_number_of_privmsgs <= 0)
+                       {
+                               target_p->localClient->received_number_of_privmsgs = 0;
+                               target_p->localClient->flood_noticed = 0;
+                       }
+               }
+
+               if((target_p->localClient->received_number_of_privmsgs >=
+                   GlobalSetOptions.floodcount) || target_p->localClient->flood_noticed)
+               {
+                       if(target_p->localClient->flood_noticed == 0)
+                       {
+                               sendto_realops_snomask(SNO_BOTS, L_ALL,
+                                                    "Possible Flooder %s[%s@%s] on %s target: %s",
+                                                    source_p->name, source_p->username,
+                                                    source_p->host,
+                                                    source_p->user->server, target_p->name);
+                               target_p->localClient->flood_noticed = 1;
+                               /* add a bit of penalty */
+                               target_p->localClient->received_number_of_privmsgs += 2;
+                       }
+                       if(MyClient(source_p) && (p_or_n != NOTICE))
+                               sendto_one(source_p,
+                                          ":%s NOTICE %s :*** Message to %s throttled due to flooding",
+                                          me.name, source_p->name, target_p->name);
+                       return 1;
+               }
+               else
+                       target_p->localClient->received_number_of_privmsgs++;
+       }
+
+       return 0;
+}
+
+/*
+ * flood_attack_channel
+ * inputs       - flag 0 if PRIVMSG 1 if NOTICE. RFC
+ *                says NOTICE must not auto reply
+ *              - pointer to source Client 
+ *             - pointer to target channel
+ * output      - 1 if target is under flood attack
+ * side effects        - check for flood attack on target chptr
+ */
+static int
+flood_attack_channel(int p_or_n, struct Client *source_p, struct Channel *chptr, char *chname)
+{
+       int delta;
+
+       if(GlobalSetOptions.floodcount && MyClient(source_p))
+       {
+               if((chptr->first_received_message_time + 1) < CurrentTime)
+               {
+                       delta = CurrentTime - chptr->first_received_message_time;
+                       chptr->received_number_of_privmsgs -= delta;
+                       chptr->first_received_message_time = CurrentTime;
+                       if(chptr->received_number_of_privmsgs <= 0)
+                       {
+                               chptr->received_number_of_privmsgs = 0;
+                               chptr->flood_noticed = 0;
+                       }
+               }
+
+               if((chptr->received_number_of_privmsgs >= GlobalSetOptions.floodcount)
+                  || chptr->flood_noticed)
+               {
+                       if(chptr->flood_noticed == 0)
+                       {
+                               sendto_realops_snomask(SNO_BOTS, L_ALL,
+                                                    "Possible Flooder %s[%s@%s] on %s target: %s",
+                                                    source_p->name, source_p->username,
+                                                    source_p->host,
+                                                    source_p->user->server, chptr->chname);
+                               chptr->flood_noticed = 1;
+
+                               /* Add a bit of penalty */
+                               chptr->received_number_of_privmsgs += 2;
+                       }
+                       if(MyClient(source_p) && (p_or_n != NOTICE))
+                               sendto_one(source_p,
+                                          ":%s NOTICE %s :*** Message to %s throttled due to flooding",
+                                          me.name, source_p->name, chptr->chname);
+                       return 1;
+               }
+               else
+                       chptr->received_number_of_privmsgs++;
+       }
+
+       return 0;
+}
+
+
+/*
+ * handle_special
+ *
+ * inputs      - server pointer
+ *             - client pointer
+ *             - nick stuff to grok for opers
+ *             - text to send if grok
+ * output      - none
+ * side effects        - all the traditional oper type messages are parsed here.
+ *               i.e. "/msg #some.host."
+ *               However, syntax has been changed.
+ *               previous syntax "/msg #some.host.mask"
+ *               now becomes     "/msg $#some.host.mask"
+ *               previous syntax of: "/msg $some.server.mask" remains
+ *               This disambiguates the syntax.
+ */
+static void
+handle_special(int p_or_n, const char *command, struct Client *client_p,
+              struct Client *source_p, const char *nick, const char *text)
+{
+       struct Client *target_p;
+       char *host;
+       char *server;
+       char *s;
+       int count;
+
+       /* user[%host]@server addressed?
+        * NOTE: users can send to user@server, but not user%host@server
+        * or opers@server
+        */
+       if((server = strchr(nick, '@')) != NULL)
+       {
+               if((target_p = find_server(source_p, server + 1)) == NULL)
+               {
+                       sendto_one_numeric(source_p, ERR_NOSUCHSERVER,
+                                          form_str(ERR_NOSUCHSERVER), server + 1);
+                       return;
+               }
+
+               count = 0;
+
+               if(!IsOper(source_p))
+               {
+                       if(strchr(nick, '%') || (strncmp(nick, "opers", 5) == 0))
+                       {
+                               sendto_one_numeric(source_p, ERR_NOSUCHNICK,
+                                                  form_str(ERR_NOSUCHNICK), nick);
+                               return;
+                       }
+               }
+
+               /* somewhere else.. */
+               if(!IsMe(target_p))
+               {
+                       sendto_one(target_p, ":%s %s %s :%s",
+                                  get_id(source_p, target_p), command, nick, text);
+                       return;
+               }
+
+               *server = '\0';
+
+               if((host = strchr(nick, '%')) != NULL)
+                       *host++ = '\0';
+
+               /* Check if someones msg'ing opers@our.server */
+               if(strcmp(nick, "opers") == 0)
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL, "To opers: From: %s: %s",
+                                            source_p->name, text);
+                       return;
+               }
+
+               /*
+                * Look for users which match the destination host
+                * (no host == wildcard) and if one and one only is
+                * found connected to me, deliver message!
+                */
+               target_p = find_userhost(nick, host, &count);
+
+               if(target_p != NULL)
+               {
+                       if(server != NULL)
+                               *server = '@';
+                       if(host != NULL)
+                               *--host = '%';
+
+                       if(count == 1)
+                               sendto_anywhere(target_p, source_p, command, ":%s", text);
+                       else
+                               sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
+                                          get_id(&me, source_p), get_id(source_p, source_p), nick);
+               }
+       }
+
+       /*
+        * the following two cases allow masks in NOTICEs
+        * (for OPERs only)
+        *
+        * Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
+        */
+       if(IsOper(source_p) && *nick == '$')
+       {
+               if((*(nick + 1) == '$' || *(nick + 1) == '#'))
+                       nick++;
+               else if(MyOper(source_p))
+               {
+                       sendto_one(source_p,
+                                  ":%s NOTICE %s :The command %s %s is no longer supported, please use $%s",
+                                  me.name, source_p->name, command, nick, nick);
+                       return;
+               }
+
+               if((s = strrchr(nick, '.')) == NULL)
+               {
+                       sendto_one_numeric(source_p, ERR_NOTOPLEVEL,
+                                          form_str(ERR_NOTOPLEVEL), nick);
+                       return;
+               }
+               while(*++s)
+                       if(*s == '.' || *s == '*' || *s == '?')
+                               break;
+               if(*s == '*' || *s == '?')
+               {
+                       sendto_one_numeric(source_p, ERR_WILDTOPLEVEL,
+                                          form_str(ERR_WILDTOPLEVEL), nick);
+                       return;
+               }
+
+               sendto_match_butone(IsServer(client_p) ? client_p : NULL, source_p,
+                                   nick + 1,
+                                   (*nick == '#') ? MATCH_HOST : MATCH_SERVER,
+                                   "%s $%s :%s", command, nick, text);
+               return;
+       }
+}
+
+/*
+ * find_userhost - find a user@host (server or user).
+ * inputs       - user name to look for
+ *              - host name to look for
+ *             - pointer to count of number of matches found
+ * outputs     - pointer to client if found
+ *             - count is updated
+ * side effects        - none
+ *
+ */
+static struct Client *
+find_userhost(const char *user, const char *host, int *count)
+{
+       struct Client *c2ptr;
+       struct Client *res = NULL;
+       char *u = LOCAL_COPY(user);
+       dlink_node *ptr;
+       *count = 0;
+       if(collapse(u) != NULL)
+       {
+               DLINK_FOREACH(ptr, global_client_list.head)
+               {
+                       c2ptr = ptr->data;
+                       if(!MyClient(c2ptr))    /* implies mine and an user */
+                               continue;
+                       if((!host || match(host, c2ptr->host)) && irccmp(u, c2ptr->username) == 0)
+                       {
+                               (*count)++;
+                               res = c2ptr;
+                       }
+               }
+       }
+       return (res);
+}
diff --git a/modules/core/m_mode.c b/modules/core/m_mode.c
new file mode 100644 (file)
index 0000000..25b251c
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_mode.c: Sets a user or channel mode.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_mode.c 1006 2006-03-09 15:32:14Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "balloc.h"
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_user.h"
+#include "s_conf.h"
+#include "s_serv.h"
+#include "s_log.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "packet.h"
+#include "sprintf_irc.h"
+#include "s_newconf.h"
+
+static int m_mode(struct Client *, struct Client *, int, const char **);
+static int ms_mode(struct Client *, struct Client *, int, const char **);
+static int ms_tmode(struct Client *, struct Client *, int, const char **);
+static int ms_bmask(struct Client *, struct Client *, int, const char **);
+
+struct Message mode_msgtab = {
+       "MODE", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_mode, 2}, {m_mode, 3}, {ms_mode, 3}, mg_ignore, {m_mode, 2}}
+};
+struct Message tmode_msgtab = {
+       "TMODE", 0, 0, 0, MFLG_SLOW,
+       {mg_ignore, mg_ignore, {ms_tmode, 4}, {ms_tmode, 4}, mg_ignore, mg_ignore}
+};
+struct Message bmask_msgtab = {
+       "BMASK", 0, 0, 0, MFLG_SLOW,
+       {mg_ignore, mg_ignore, mg_ignore, {ms_bmask, 5}, mg_ignore, mg_ignore}
+};
+
+mapi_clist_av1 mode_clist[] = { &mode_msgtab, &tmode_msgtab, &bmask_msgtab, NULL };
+
+DECLARE_MODULE_AV1(mode, NULL, NULL, mode_clist, NULL, NULL, "$Revision: 1006 $");
+
+/*
+ * m_mode - MODE command handler
+ * parv[0] - sender
+ * parv[1] - channel
+ */
+static int
+m_mode(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Channel *chptr = NULL;
+       struct membership *msptr;
+       int n = 2;
+       const char *dest;
+       int operspy = 0;
+
+       dest = parv[1];
+
+       if(IsOperSpy(source_p) && *dest == '!')
+       {
+               dest++;
+               operspy = 1;
+
+               if(EmptyString(dest))
+               {
+                       sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+                                  me.name, source_p->name, "MODE");
+                       return 0;
+               }
+       }
+
+       /* Now, try to find the channel in question */
+       if(!IsChanPrefix(*dest))
+       {
+               /* if here, it has to be a non-channel name */
+               user_mode(client_p, source_p, parc, parv);
+               return 0;
+       }
+
+       if(!check_channel_name(dest))
+       {
+               sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), parv[1]);
+               return 0;
+       }
+
+       chptr = find_channel(dest);
+
+       if(chptr == NULL)
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
+                                  form_str(ERR_NOSUCHCHANNEL), parv[1]);
+               return 0;
+       }
+
+       /* Now know the channel exists */
+       if(parc < n + 1)
+       {
+               if(operspy)
+                       report_operspy(source_p, "MODE", chptr->chname);
+
+               sendto_one(source_p, form_str(RPL_CHANNELMODEIS),
+                          me.name, source_p->name, parv[1],
+                          operspy ? channel_modes(chptr, &me) : channel_modes(chptr, source_p));
+
+               sendto_one(source_p, form_str(RPL_CREATIONTIME),
+                          me.name, source_p->name, parv[1], chptr->channelts);
+       }
+       else
+       {
+               msptr = find_channel_membership(chptr, source_p);
+
+               if(is_deop(msptr))
+                       return 0;
+
+               /* Finish the flood grace period... */
+               if(MyClient(source_p) && !IsFloodDone(source_p))
+               {
+                       if(!((parc == 3) && (parv[2][0] == 'b') && (parv[2][1] == '\0')))
+                               flood_endgrace(source_p);
+               }
+
+               set_channel_mode(client_p, source_p, chptr, msptr, parc - n, parv + n);
+       }
+
+       return 0;
+}
+
+static int
+ms_mode(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Channel *chptr;
+
+       chptr = find_channel(parv[1]);
+
+       if(chptr == NULL)
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
+                                  form_str(ERR_NOSUCHCHANNEL), parv[1]);
+               return 0;
+       }
+
+       set_channel_mode(client_p, source_p, chptr, NULL, parc - 2, parv + 2);
+
+       return 0;
+}
+
+static int
+ms_tmode(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Channel *chptr = NULL;
+       struct membership *msptr;
+
+       /* Now, try to find the channel in question */
+       if(!IsChanPrefix(parv[2][0]) || !check_channel_name(parv[2]))
+       {
+               sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), parv[2]);
+               return 0;
+       }
+
+       chptr = find_channel(parv[2]);
+
+       if(chptr == NULL)
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
+                                  form_str(ERR_NOSUCHCHANNEL), parv[2]);
+               return 0;
+       }
+
+       /* TS is higher, drop it. */
+       if(atol(parv[1]) > chptr->channelts)
+               return 0;
+
+       if(IsServer(source_p))
+       {
+               set_channel_mode(client_p, source_p, chptr, NULL, parc - 3, parv + 3);
+       }
+       else
+       {
+               msptr = find_channel_membership(chptr, source_p);
+
+               /* this can still happen on a mixed ts network. */
+               if(is_deop(msptr))
+                       return 0;
+
+               set_channel_mode(client_p, source_p, chptr, msptr, parc - 3, parv + 3);
+       }
+
+       return 0;
+}
+
+static int
+ms_bmask(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       static char modebuf[BUFSIZE];
+       static char parabuf[BUFSIZE];
+       struct Channel *chptr;
+       dlink_list *banlist;
+       const char *s;
+       char *t;
+       char *mbuf;
+       char *pbuf;
+       long mode_type;
+       int mlen;
+       int plen = 0;
+       int tlen;
+       int arglen;
+       int modecount = 0;
+       int needcap = NOCAPS;
+       int mems;
+       struct Client *fakesource_p;
+
+       if(!IsChanPrefix(parv[2][0]) || !check_channel_name(parv[2]))
+               return 0;
+
+       if((chptr = find_channel(parv[2])) == NULL)
+               return 0;
+
+       /* TS is higher, drop it. */
+       if(atol(parv[1]) > chptr->channelts)
+               return 0;
+
+       switch (parv[3][0])
+       {
+       case 'b':
+               banlist = &chptr->banlist;
+               mode_type = CHFL_BAN;
+               mems = ALL_MEMBERS;
+               break;
+
+       case 'e':
+               banlist = &chptr->exceptlist;
+               mode_type = CHFL_EXCEPTION;
+               needcap = CAP_EX;
+               mems = ONLY_CHANOPS;
+               break;
+
+       case 'I':
+               banlist = &chptr->invexlist;
+               mode_type = CHFL_INVEX;
+               needcap = CAP_IE;
+               mems = ONLY_CHANOPS;
+               break;
+
+       case 'q':
+               banlist = &chptr->quietlist;
+               mode_type = CHFL_QUIET;
+               mems = ALL_MEMBERS;
+               break;
+
+               /* maybe we should just blindly propagate this? */
+       default:
+               return 0;
+       }
+
+       parabuf[0] = '\0';
+       s = LOCAL_COPY(parv[4]);
+
+       /* Hide connecting server on netburst -- jilles */
+       if (ConfigServerHide.flatten_links && !HasSentEob(source_p))
+               fakesource_p = &me;
+       else
+               fakesource_p = source_p;
+       mlen = ircsprintf(modebuf, ":%s MODE %s +", fakesource_p->name, chptr->chname);
+       mbuf = modebuf + mlen;
+       pbuf = parabuf;
+
+       while(*s == ' ')
+               s++;
+
+       /* next char isnt a space, point t to the next one */
+       if((t = strchr(s, ' ')) != NULL)
+       {
+               *t++ = '\0';
+
+               /* double spaces will break the parser */
+               while(*t == ' ')
+                       t++;
+       }
+
+       /* couldve skipped spaces and got nothing.. */
+       while(!EmptyString(s))
+       {
+               /* ban with a leading ':' -- this will break the protocol */
+               if(*s == ':')
+                       goto nextban;
+
+               tlen = strlen(s);
+
+               /* I dont even want to begin parsing this.. */
+               if(tlen > MODEBUFLEN)
+                       break;
+
+               if(add_id(fakesource_p, chptr, s, banlist, mode_type))
+               {
+                       /* this new one wont fit.. */
+                       if(mlen + MAXMODEPARAMS + plen + tlen > BUFSIZE - 5 ||
+                          modecount >= MAXMODEPARAMS)
+                       {
+                               *mbuf = '\0';
+                               *(pbuf - 1) = '\0';
+                               sendto_channel_local(mems, chptr, "%s %s", modebuf, parabuf);
+                               sendto_server(client_p, chptr, needcap, CAP_TS6,
+                                             "%s %s", modebuf, parabuf);
+
+                               mbuf = modebuf + mlen;
+                               pbuf = parabuf;
+                               plen = modecount = 0;
+                       }
+
+                       *mbuf++ = parv[3][0];
+                       arglen = ircsprintf(pbuf, "%s ", s);
+                       pbuf += arglen;
+                       plen += arglen;
+                       modecount++;
+               }
+
+             nextban:
+               s = t;
+
+               if(s != NULL)
+               {
+                       if((t = strchr(s, ' ')) != NULL)
+                       {
+                               *t++ = '\0';
+
+                               while(*t == ' ')
+                                       t++;
+                       }
+               }
+       }
+
+       if(modecount)
+       {
+               *mbuf = '\0';
+               *(pbuf - 1) = '\0';
+               sendto_channel_local(mems, chptr, "%s %s", modebuf, parabuf);
+               sendto_server(client_p, chptr, needcap, CAP_TS6, "%s %s", modebuf, parabuf);
+       }
+
+       sendto_server(client_p, chptr, CAP_TS6 | needcap, NOCAPS, ":%s BMASK %ld %s %s :%s",
+                     source_p->id, (long) chptr->channelts, chptr->chname, parv[3], parv[4]);
+       return 0;
+}
+
diff --git a/modules/core/m_nick.c b/modules/core/m_nick.c
new file mode 100644 (file)
index 0000000..c80a0e7
--- /dev/null
@@ -0,0 +1,1360 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_nick.c: Sets a users nick.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_nick.c 1885 2006-08-28 10:09:50Z jilles $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_conf.h"
+#include "s_stats.h"
+#include "s_user.h"
+#include "hash.h"
+#include "whowas.h"
+#include "s_serv.h"
+#include "send.h"
+#include "channel.h"
+#include "s_log.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "common.h"
+#include "packet.h"
+#include "scache.h"
+#include "s_newconf.h"
+#include "monitor.h"
+
+static int mr_nick(struct Client *, struct Client *, int, const char **);
+static int m_nick(struct Client *, struct Client *, int, const char **);
+static int mc_nick(struct Client *, struct Client *, int, const char **);
+static int ms_nick(struct Client *, struct Client *, int, const char **);
+static int ms_uid(struct Client *, struct Client *, int, const char **);
+static int ms_euid(struct Client *, struct Client *, int, const char **);
+static int ms_save(struct Client *, struct Client *, int, const char **);
+static int can_save(struct Client *);
+static void save_user(struct Client *, struct Client *, struct Client *);
+
+struct Message nick_msgtab = {
+       "NICK", 0, 0, 0, MFLG_SLOW,
+       {{mr_nick, 0}, {m_nick, 0}, {mc_nick, 3}, {ms_nick, 8}, mg_ignore, {m_nick, 0}}
+};
+struct Message uid_msgtab = {
+       "UID", 0, 0, 0, MFLG_SLOW,
+       {mg_ignore, mg_ignore, mg_ignore, {ms_uid, 9}, mg_ignore, mg_ignore}
+};
+struct Message euid_msgtab = {
+       "EUID", 0, 0, 0, MFLG_SLOW,
+       {mg_ignore, mg_ignore, mg_ignore, {ms_euid, 12}, mg_ignore, mg_ignore}
+};
+struct Message save_msgtab = {
+       "SAVE", 0, 0, 0, MFLG_SLOW,
+       {mg_ignore, mg_ignore, mg_ignore, {ms_save, 3}, mg_ignore, mg_ignore}
+};
+
+mapi_clist_av1 nick_clist[] = { &nick_msgtab, &uid_msgtab, &euid_msgtab,
+       &save_msgtab, NULL };
+
+DECLARE_MODULE_AV1(nick, NULL, NULL, nick_clist, NULL, NULL, "$Revision: 1885 $");
+
+static int change_remote_nick(struct Client *, struct Client *, time_t,
+                             const char *, int);
+
+static int clean_nick(const char *, int loc_client);
+static int clean_username(const char *);
+static int clean_host(const char *);
+static int clean_uid(const char *uid);
+
+static void set_initial_nick(struct Client *client_p, struct Client *source_p, char *nick);
+static void change_local_nick(struct Client *client_p, struct Client *source_p, char *nick, int);
+static int register_client(struct Client *client_p, struct Client *server,
+                          const char *nick, time_t newts, int parc, const char *parv[]);
+
+static int perform_nick_collides(struct Client *, struct Client *,
+                                struct Client *, int, const char **,
+                                time_t, const char *, const char *);
+static int perform_nickchange_collides(struct Client *, struct Client *,
+                                      struct Client *, int, const char **, time_t, const char *);
+
+/* mr_nick()
+ *       parv[0] = sender prefix
+ *       parv[1] = nickname
+ */
+static int
+mr_nick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+       char nick[NICKLEN];
+       char *s;
+
+       if (strlen(client_p->id) == 3)
+       {
+               exit_client(client_p, client_p, client_p, "Mixing client and server protocol");
+               return 0;
+       }
+
+       if(parc < 2 || EmptyString(parv[1]) || (parv[1][0] == '~'))
+       {
+               sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN),
+                          me.name, EmptyString(source_p->name) ? "*" : source_p->name);
+               return 0;
+       }
+
+       /* due to the scandinavian origins, (~ being uppercase of ^) and ~
+        * being disallowed as a nick char, we need to chop the first ~
+        * instead of just erroring.
+        */
+       if((s = strchr(parv[1], '~')))
+               *s = '\0';
+
+       /* copy the nick and terminate it */
+       strlcpy(nick, parv[1], sizeof(nick));
+
+       /* check the nickname is ok */
+       if(!clean_nick(nick, 1))
+       {
+               sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME),
+                          me.name, EmptyString(parv[0]) ? "*" : parv[0], parv[1]);
+               return 0;
+       }
+
+       /* check if the nick is resv'd */
+       if(find_nick_resv(nick))
+       {
+               sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME),
+                          me.name, EmptyString(source_p->name) ? "*" : source_p->name, nick);
+               return 0;
+       }
+
+       if(hash_find_nd(nick))
+       {
+               sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
+                          me.name, EmptyString(source_p->name) ? "*" : source_p->name, nick);
+               return 0;
+       }
+
+       if((target_p = find_named_client(nick)) == NULL)
+               set_initial_nick(client_p, source_p, nick);
+       else if(source_p == target_p)
+               strcpy(source_p->name, nick);
+       else
+               sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name, "*", nick);
+
+       return 0;
+}
+
+/* m_nick()
+ *     parv[0] = sender prefix
+ *     parv[1] = nickname
+ */
+static int
+m_nick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+       char nick[NICKLEN];
+       char *s;
+
+       if(parc < 2 || EmptyString(parv[1]) || (parv[1][0] == '~'))
+       {
+               sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN), me.name, source_p->name);
+               return 0;
+       }
+
+       /* due to the scandinavian origins, (~ being uppercase of ^) and ~
+        * being disallowed as a nick char, we need to chop the first ~
+        * instead of just erroring.
+        */
+       if((s = strchr(parv[1], '~')))
+               *s = '\0';
+
+       /* mark end of grace period, to prevent nickflooding */
+       if(!IsFloodDone(source_p))
+               flood_endgrace(source_p);
+
+       /* terminate nick to NICKLEN, we dont want clean_nick() to error! */
+       strlcpy(nick, parv[1], sizeof(nick));
+
+       /* check the nickname is ok */
+       if(!clean_nick(nick, 1))
+       {
+               sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME), me.name, parv[0], nick);
+               return 0;
+       }
+
+       if(!IsExemptResv(source_p) && find_nick_resv(nick))
+       {
+               sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME), me.name, source_p->name, nick);
+               return 0;
+       }
+
+       if(hash_find_nd(nick))
+       {
+               sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
+                          me.name, EmptyString(source_p->name) ? "*" : source_p->name, nick);
+               return 0;
+       }
+
+       if((target_p = find_named_client(nick)))
+       {
+               /* If(target_p == source_p) the client is changing nicks between
+                * equivalent nicknames ie: [nick] -> {nick}
+                */
+               if(target_p == source_p)
+               {
+                       /* check the nick isnt exactly the same */
+                       if(strcmp(target_p->name, nick))
+                               change_local_nick(client_p, source_p, nick, 1);
+
+               }
+
+               /* drop unregged client */
+               else if(IsUnknown(target_p))
+               {
+                       exit_client(NULL, target_p, &me, "Overridden");
+                       change_local_nick(client_p, source_p, nick, 1);
+               }
+               else
+                       sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name, parv[0], nick);
+
+               return 0;
+       }
+       else
+               change_local_nick(client_p, source_p, nick, 1);
+
+       return 0;
+}
+
+/* ms_nick()
+ *      
+ * server -> server nick change
+ *    parv[0] = sender prefix
+ *    parv[1] = nickname
+ *    parv[2] = TS when nick change
+ *
+ * server introducing new nick
+ *    parv[0] = sender prefix
+ *    parv[1] = nickname
+ *    parv[2] = hop count
+ *    parv[3] = TS
+ *    parv[4] = umode
+ *    parv[5] = username
+ *    parv[6] = hostname
+ *    parv[7] = server
+ *    parv[8] = ircname
+ */
+static int
+mc_nick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+       time_t newts = 0;
+
+       /* if nicks erroneous, or too long, kill */
+       if(!clean_nick(parv[1], 0))
+       {
+               ServerStats->is_kill++;
+               sendto_realops_snomask(SNO_DEBUG, L_ALL,
+                                    "Bad Nick: %s From: %s(via %s)",
+                                    parv[1], source_p->user->server, client_p->name);
+               sendto_one(client_p, ":%s KILL %s :%s (Bad Nickname)", me.name, parv[1], me.name);
+
+               /* bad nick change, issue kill for the old nick to the rest
+                * of the network.
+                */
+               kill_client_serv_butone(client_p, source_p, "%s (Bad Nickname)", me.name);
+               source_p->flags |= FLAGS_KILLED;
+               exit_client(client_p, source_p, &me, "Bad Nickname");
+               return 0;
+       }
+
+       newts = atol(parv[2]);
+       target_p = find_named_client(parv[1]);
+
+       /* if the nick doesnt exist, allow it and process like normal */
+       if(target_p == NULL)
+       {
+               change_remote_nick(client_p, source_p, newts, parv[1], 1);
+       }
+       else if(IsUnknown(target_p))
+       {
+               exit_client(NULL, target_p, &me, "Overridden");
+               change_remote_nick(client_p, source_p, newts, parv[1], 1);
+       }
+       else if(target_p == source_p)
+       {
+               /* client changing case of nick */
+               if(strcmp(target_p->name, parv[1]))
+                       change_remote_nick(client_p, source_p, newts, parv[1], 1);
+       }
+       /* we've got a collision! */
+       else
+               perform_nickchange_collides(source_p, client_p, target_p,
+                                           parc, parv, newts, parv[1]);
+
+       return 0;
+}
+
+static int
+ms_nick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+       time_t newts = 0;
+
+       if(parc != 9)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Dropping server %s due to (invalid) command 'NICK' "
+                                    "with %d arguments (expecting 9)", client_p->name, parc);
+               ilog(L_SERVER, "Excess parameters (%d) for command 'NICK' from %s.",
+                    parc, client_p->name);
+               exit_client(client_p, client_p, client_p, "Excess parameters to NICK command");
+               return 0;
+       }
+
+       /* if nicks empty, erroneous, or too long, kill */
+       if(!clean_nick(parv[1], 0))
+       {
+               ServerStats->is_kill++;
+               sendto_realops_snomask(SNO_DEBUG, L_ALL,
+                                    "Bad Nick: %s From: %s(via %s)",
+                                    parv[1], parv[7], client_p->name);
+               sendto_one(client_p, ":%s KILL %s :%s (Bad Nickname)", me.name, parv[1], me.name);
+               return 0;
+       }
+
+       /* invalid username or host? */
+       if(!clean_username(parv[5]) || !clean_host(parv[6]))
+       {
+               ServerStats->is_kill++;
+               sendto_realops_snomask(SNO_DEBUG, L_ALL,
+                                    "Bad user@host: %s@%s From: %s(via %s)",
+                                    parv[5], parv[6], parv[7], client_p->name);
+               sendto_one(client_p, ":%s KILL %s :%s (Bad user@host)", me.name, parv[1], me.name);
+               return 0;
+       }
+
+       /* check the length of the clients gecos */
+       if(strlen(parv[8]) > REALLEN)
+       {
+               char *s = LOCAL_COPY(parv[8]);
+               /* why exactly do we care? --fl */
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Long realname from server %s for %s", parv[7], parv[1]);
+
+               s[REALLEN] = '\0';
+               parv[8] = s;
+       }
+
+       newts = atol(parv[3]);
+
+       target_p = find_named_client(parv[1]);
+
+       /* if the nick doesnt exist, allow it and process like normal */
+       if(target_p == NULL)
+       {
+               register_client(client_p, NULL, parv[1], newts, parc, parv);
+       }
+       else if(IsUnknown(target_p))
+       {
+               exit_client(NULL, target_p, &me, "Overridden");
+               register_client(client_p, NULL, parv[1], newts, parc, parv);
+       }
+       else if(target_p == source_p)
+       {
+               /* client changing case of nick */
+               if(strcmp(target_p->name, parv[1]))
+                       register_client(client_p, NULL, parv[1], newts, parc, parv);
+       }
+       /* we've got a collision! */
+       else
+               perform_nick_collides(source_p, client_p, target_p, parc, parv,
+                                     newts, parv[1], NULL);
+
+       return 0;
+}
+
+/* ms_uid()
+ *     parv[1] - nickname
+ *     parv[2] - hops
+ *     parv[3] - TS
+ *     parv[4] - umodes
+ *     parv[5] - username
+ *     parv[6] - hostname
+ *     parv[7] - IP
+ *     parv[8] - UID
+ *     parv[9] - gecos
+ */
+static int
+ms_uid(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+       time_t newts = 0;
+
+       newts = atol(parv[3]);
+
+       if(parc != 10)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Dropping server %s due to (invalid) command 'UID' "
+                                    "with %d arguments (expecting 10)", client_p->name, parc);
+               ilog(L_SERVER, "Excess parameters (%d) for command 'UID' from %s.",
+                    parc, client_p->name);
+               exit_client(client_p, client_p, client_p, "Excess parameters to UID command");
+               return 0;
+       }
+
+       /* if nicks erroneous, or too long, kill */
+       if(!clean_nick(parv[1], 0))
+       {
+               ServerStats->is_kill++;
+               sendto_realops_snomask(SNO_DEBUG, L_ALL,
+                                    "Bad Nick: %s From: %s(via %s)",
+                                    parv[1], source_p->name, client_p->name);
+               sendto_one(client_p, ":%s KILL %s :%s (Bad Nickname)", me.id, parv[8], me.name);
+               return 0;
+       }
+
+       if(!clean_username(parv[5]) || !clean_host(parv[6]))
+       {
+               ServerStats->is_kill++;
+               sendto_realops_snomask(SNO_DEBUG, L_ALL,
+                                    "Bad user@host: %s@%s From: %s(via %s)",
+                                    parv[5], parv[6], source_p->name, client_p->name);
+               sendto_one(client_p, ":%s KILL %s :%s (Bad user@host)", me.id, parv[8], me.name);
+               return 0;
+       }
+
+       if(!clean_uid(parv[8]))
+       {
+               ServerStats->is_kill++;
+               sendto_realops_snomask(SNO_DEBUG, L_ALL,
+                                    "Bad UID: %s From: %s(via %s)",
+                                    parv[8], source_p->name, client_p->name);
+               sendto_one(client_p, ":%s KILL %s :%s (Bad UID)", me.id, parv[8], me.name);
+               return 0;
+       }
+
+       /* check length of clients gecos */
+       if(strlen(parv[9]) > REALLEN)
+       {
+               char *s = LOCAL_COPY(parv[9]);
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "Long realname from server %s for %s",
+                                    parv[0], parv[1]);
+               s[REALLEN] = '\0';
+               parv[9] = s;
+       }
+
+       target_p = find_named_client(parv[1]);
+
+       if(target_p == NULL)
+       {
+               register_client(client_p, source_p, parv[1], newts, parc, parv);
+       }
+       else if(IsUnknown(target_p))
+       {
+               exit_client(NULL, target_p, &me, "Overridden");
+               register_client(client_p, source_p, parv[1], newts, parc, parv);
+       }
+       /* we've got a collision! */
+       else
+               perform_nick_collides(source_p, client_p, target_p, parc, parv,
+                                     newts, parv[1], parv[8]);
+
+       return 0;
+}
+
+/* ms_euid()
+ *     parv[1] - nickname
+ *     parv[2] - hops
+ *     parv[3] - TS
+ *     parv[4] - umodes
+ *     parv[5] - username
+ *     parv[6] - hostname
+ *     parv[7] - IP
+ *     parv[8] - UID
+ *     parv[9] - realhost
+ *     parv[10] - account
+ *     parv[11] - gecos
+ */
+static int
+ms_euid(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+       time_t newts = 0;
+
+       newts = atol(parv[3]);
+
+       if(parc != 12)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Dropping server %s due to (invalid) command 'EUID' "
+                                    "with %d arguments (expecting 12)", client_p->name, parc);
+               ilog(L_SERVER, "Excess parameters (%d) for command 'EUID' from %s.",
+                    parc, client_p->name);
+               exit_client(client_p, client_p, client_p, "Excess parameters to EUID command");
+               return 0;
+       }
+
+       /* if nicks erroneous, or too long, kill */
+       if(!clean_nick(parv[1], 0))
+       {
+               ServerStats->is_kill++;
+               sendto_realops_snomask(SNO_DEBUG, L_ALL,
+                                    "Bad Nick: %s From: %s(via %s)",
+                                    parv[1], source_p->name, client_p->name);
+               sendto_one(client_p, ":%s KILL %s :%s (Bad Nickname)", me.id, parv[8], me.name);
+               return 0;
+       }
+
+       if(!clean_username(parv[5]) || !clean_host(parv[6]))
+       {
+               ServerStats->is_kill++;
+               sendto_realops_snomask(SNO_DEBUG, L_ALL,
+                                    "Bad user@host: %s@%s From: %s(via %s)",
+                                    parv[5], parv[6], source_p->name, client_p->name);
+               sendto_one(client_p, ":%s KILL %s :%s (Bad user@host)", me.id, parv[8], me.name);
+               return 0;
+       }
+
+       if(!clean_uid(parv[8]))
+       {
+               ServerStats->is_kill++;
+               sendto_realops_snomask(SNO_DEBUG, L_ALL,
+                                    "Bad UID: %s From: %s(via %s)",
+                                    parv[8], source_p->name, client_p->name);
+               sendto_one(client_p, ":%s KILL %s :%s (Bad UID)", me.id, parv[8], me.name);
+               return 0;
+       }
+
+       if(strcmp(parv[9], "*") && !clean_host(parv[9]))
+       {
+               ServerStats->is_kill++;
+               sendto_realops_snomask(SNO_DEBUG, L_ALL,
+                                    "Bad realhost: %s From: %s(via %s)",
+                                    parv[9], source_p->name, client_p->name);
+               sendto_one(client_p, ":%s KILL %s :%s (Bad user@host)", me.id, parv[8], me.name);
+               return 0;
+       }
+
+       /* check length of clients gecos */
+       if(strlen(parv[11]) > REALLEN)
+       {
+               char *s = LOCAL_COPY(parv[11]);
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "Long realname from server %s for %s",
+                                    parv[0], parv[1]);
+               s[REALLEN] = '\0';
+               parv[11] = s;
+       }
+
+       target_p = find_named_client(parv[1]);
+
+       if(target_p == NULL)
+       {
+               register_client(client_p, source_p, parv[1], newts, parc, parv);
+       }
+       else if(IsUnknown(target_p))
+       {
+               exit_client(NULL, target_p, &me, "Overridden");
+               register_client(client_p, source_p, parv[1], newts, parc, parv);
+       }
+       /* we've got a collision! */
+       else
+               perform_nick_collides(source_p, client_p, target_p, parc, parv,
+                                     newts, parv[1], parv[8]);
+
+       return 0;
+}
+
+/* ms_save()
+ *   parv[1] - UID
+ *   parv[2] - TS
+ */
+static int
+ms_save(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+
+       target_p = find_id(parv[1]);
+       if (target_p == NULL)
+               return 0;
+       if (!IsPerson(target_p))
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                               "Ignored SAVE message for non-person %s from %s",
+                               target_p->name, source_p->name);
+       else if (IsDigit(target_p->name[0]))
+               sendto_realops_snomask(SNO_DEBUG, L_ALL,
+                               "Ignored noop SAVE message for %s from %s",
+                               target_p->name, source_p->name);
+       else if (target_p->tsinfo == atol(parv[2]))
+               save_user(client_p, source_p, target_p);
+       else
+               sendto_realops_snomask(SNO_SKILL, L_ALL,
+                               "Ignored SAVE message for %s from %s",
+                               target_p->name, source_p->name);
+       return 0;
+}
+
+/* clean_nick()
+ *
+ * input       - nickname to check
+ * output      - 0 if erroneous, else 1
+ * side effects - 
+ */
+static int
+clean_nick(const char *nick, int loc_client)
+{
+       int len = 0;
+
+       /* nicks cant start with a digit or -, and must have a length */
+       if(*nick == '-' || *nick == '\0')
+               return 0;
+
+       if(loc_client && IsDigit(*nick))
+               return 0;
+
+       for(; *nick; nick++)
+       {
+               len++;
+               if(!IsNickChar(*nick))
+                       return 0;
+       }
+
+       /* nicklen is +1 */
+       if(len >= NICKLEN)
+               return 0;
+
+       return 1;
+}
+
+/* clean_username()
+ *
+ * input       - username to check
+ * output      - 0 if erroneous, else 0
+ * side effects -
+ */
+static int
+clean_username(const char *username)
+{
+       int len = 0;
+
+       for(; *username; username++)
+       {
+               len++;
+
+               if(!IsUserChar(*username))
+                       return 0;
+       }
+
+       if(len > USERLEN)
+               return 0;
+
+       return 1;
+}
+
+/* clean_host()
+ *
+ * input       - host to check
+ * output      - 0 if erroneous, else 0
+ * side effects -
+ */
+static int
+clean_host(const char *host)
+{
+       int len = 0;
+
+       for(; *host; host++)
+       {
+               len++;
+
+               if(!IsHostChar(*host))
+                       return 0;
+       }
+
+       if(len > HOSTLEN)
+               return 0;
+
+       return 1;
+}
+
+static int
+clean_uid(const char *uid)
+{
+       int len = 1;
+
+       if(!IsDigit(*uid++))
+               return 0;
+
+       for(; *uid; uid++)
+       {
+               len++;
+
+               if(!IsIdChar(*uid))
+                       return 0;
+       }
+
+       if(len != IDLEN - 1)
+               return 0;
+
+       return 1;
+}
+
+static void
+set_initial_nick(struct Client *client_p, struct Client *source_p, char *nick)
+{
+       char buf[USERLEN + 1];
+
+       /* This had to be copied here to avoid problems.. */
+       source_p->tsinfo = CurrentTime;
+       if(source_p->name[0])
+               del_from_client_hash(source_p->name, source_p);
+
+       strcpy(source_p->name, nick);
+       add_to_client_hash(nick, source_p);
+
+       /* fd_desc is long enough */
+       comm_note(client_p->localClient->fd, "Nick: %s", nick);
+
+       if(source_p->flags & FLAGS_SENTUSER)
+       {
+               strlcpy(buf, source_p->username, sizeof(buf));
+
+               /* got user, heres nick. */
+               register_local_user(client_p, source_p, buf);
+
+       }
+}
+
+static void
+change_local_nick(struct Client *client_p, struct Client *source_p,
+               char *nick, int dosend)
+{
+       struct Client *target_p;
+       dlink_node *ptr, *next_ptr;
+       struct Channel *chptr;
+       int samenick;
+
+       if (dosend)
+       {
+               chptr = find_bannickchange_channel(source_p);
+               if (chptr != NULL)
+               {
+                       sendto_one_numeric(source_p, ERR_BANNICKCHANGE,
+                                       form_str(ERR_BANNICKCHANGE),
+                                       nick, chptr->chname);
+                       return;
+               }
+               if((source_p->localClient->last_nick_change + ConfigFileEntry.max_nick_time) < CurrentTime)
+                       source_p->localClient->number_of_nick_changes = 0;
+
+               source_p->localClient->last_nick_change = CurrentTime;
+               source_p->localClient->number_of_nick_changes++;
+
+               if(ConfigFileEntry.anti_nick_flood && !IsOper(source_p) &&
+                               source_p->localClient->number_of_nick_changes > ConfigFileEntry.max_nick_changes)
+               {
+                       sendto_one(source_p, form_str(ERR_NICKTOOFAST),
+                                       me.name, source_p->name, source_p->name,
+                                       nick, ConfigFileEntry.max_nick_time);
+                       return;
+               }
+       }
+
+       samenick = irccmp(source_p->name, nick) ? 0 : 1;
+
+       /* dont reset TS if theyre just changing case of nick */
+       if(!samenick)
+       {
+               source_p->tsinfo = CurrentTime;
+               monitor_signoff(source_p);
+               /* we only do bancache for local users -- jilles */
+               if(source_p->user)
+                       invalidate_bancache_user(source_p);
+       }
+
+       sendto_realops_snomask(SNO_NCHANGE, L_ALL,
+                            "Nick change: From %s to %s [%s@%s]",
+                            source_p->name, nick, source_p->username, source_p->host);
+
+       /* send the nick change to the users channels */
+       sendto_common_channels_local(source_p, ":%s!%s@%s NICK :%s",
+                                    source_p->name, source_p->username, source_p->host, nick);
+
+       /* send the nick change to servers.. */
+       if(source_p->user)
+       {
+               add_history(source_p, 1);
+
+               if (dosend)
+               {
+                       sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s NICK %s :%ld",
+                                       use_id(source_p), nick, (long) source_p->tsinfo);
+                       sendto_server(client_p, NULL, NOCAPS, CAP_TS6, ":%s NICK %s :%ld",
+                                       source_p->name, nick, (long) source_p->tsinfo);
+               }
+       }
+
+       /* Finally, add to hash */
+       del_from_client_hash(source_p->name, source_p);
+       strcpy(source_p->name, nick);
+       add_to_client_hash(nick, source_p);
+
+       if(!samenick)
+               monitor_signon(source_p);
+
+       /* Make sure everyone that has this client on its accept list
+        * loses that reference. 
+        */
+       /* we used to call del_all_accepts() here, but theres no real reason
+        * to clear a clients own list of accepted clients.  So just remove
+        * them from everyone elses list --anfl
+        */
+       DLINK_FOREACH_SAFE(ptr, next_ptr, source_p->on_allow_list.head)
+       {
+               target_p = ptr->data;
+
+               dlinkFindDestroy(source_p, &target_p->localClient->allow_list);
+               dlinkDestroy(ptr, &source_p->on_allow_list);
+       }
+
+       /* fd_desc is long enough */
+       comm_note(client_p->localClient->fd, "Nick: %s", nick);
+
+       return;
+}
+
+/*
+ * change_remote_nick()
+ */
+static int
+change_remote_nick(struct Client *client_p, struct Client *source_p,
+                  time_t newts, const char *nick, int dosend)
+{
+       struct nd_entry *nd;
+       int samenick = irccmp(source_p->name, nick) ? 0 : 1;
+
+       /* client changing their nick - dont reset ts if its same */
+       if(!samenick)
+       {
+               source_p->tsinfo = newts ? newts : CurrentTime;
+               monitor_signoff(source_p);
+       }
+
+       sendto_common_channels_local(source_p, ":%s!%s@%s NICK :%s",
+                                    source_p->name, source_p->username, source_p->host, nick);
+
+       if(source_p->user)
+       {
+               add_history(source_p, 1);
+               if (dosend)
+               {
+                       sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s NICK %s :%ld",
+                                       use_id(source_p), nick, (long) source_p->tsinfo);
+                       sendto_server(client_p, NULL, NOCAPS, CAP_TS6, ":%s NICK %s :%ld",
+                                       source_p->name, nick, (long) source_p->tsinfo);
+               }
+       }
+
+       del_from_client_hash(source_p->name, source_p);
+
+       /* invalidate nick delay when a remote client uses the nick.. */
+       if((nd = hash_find_nd(nick)))
+               free_nd_entry(nd);
+
+       strcpy(source_p->name, nick);
+       add_to_client_hash(nick, source_p);
+
+       if(!samenick)
+               monitor_signon(source_p);
+
+       /* remove all accepts pointing to the client */
+       del_all_accepts(source_p);
+
+       return 0;
+}
+
+static int
+perform_nick_collides(struct Client *source_p, struct Client *client_p,
+                     struct Client *target_p, int parc, const char *parv[],
+                     time_t newts, const char *nick, const char *uid)
+{
+       int sameuser;
+       int use_save;
+       const char *action;
+
+       use_save = ConfigFileEntry.collision_fnc && can_save(target_p) &&
+               uid != NULL && can_save(source_p);
+       action = use_save ? "saved" : "killed";
+
+       /* if we dont have a ts, or their TS's are the same, kill both */
+       if(!newts || !target_p->tsinfo || (newts == target_p->tsinfo))
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Nick collision on %s(%s <- %s)(both %s)",
+                                    target_p->name, target_p->from->name, client_p->name, action);
+
+               if (use_save)
+               {
+                       save_user(&me, &me, target_p);
+                       ServerStats->is_save++;
+                       sendto_one(client_p, ":%s SAVE %s %ld", me.id,
+                                       uid, (long)newts);
+                       register_client(client_p, source_p,
+                                       uid, newts, parc, parv);
+               }
+               else
+               {
+                       sendto_one_numeric(target_p, ERR_NICKCOLLISION,
+                                       form_str(ERR_NICKCOLLISION), target_p->name);
+
+                       /* if the new client being introduced has a UID, we need to
+                        * issue a KILL for it..
+                        */
+                       if(uid)
+                               sendto_one(client_p, ":%s KILL %s :%s (Nick collision (new))",
+                                               me.id, uid, me.name);
+
+                       /* we then need to KILL the old client everywhere */
+                       kill_client_serv_butone(NULL, target_p, "%s (Nick collision (new))", me.name);
+                       ServerStats->is_kill++;
+
+                       target_p->flags |= FLAGS_KILLED;
+                       exit_client(client_p, target_p, &me, "Nick collision (new)");
+               }
+               return 0;
+       }
+       /* the timestamps are different */
+       else
+       {
+               sameuser = (target_p->user) && !irccmp(target_p->username, parv[5])
+                       && !irccmp(target_p->host, parv[6]);
+
+               if((sameuser && newts < target_p->tsinfo) ||
+                  (!sameuser && newts > target_p->tsinfo))
+               {
+                       /* if we have a UID, then we need to issue a KILL,
+                        * otherwise we do nothing and hope that the other
+                        * client will collide it..
+                        */
+                       if (use_save)
+                       {
+                               sendto_one(client_p, ":%s SAVE %s %ld", me.id,
+                                               uid, (long)newts);
+                               register_client(client_p, source_p,
+                                               uid, newts, parc, parv);
+                       }
+                       else if(uid)
+                               sendto_one(client_p,
+                                          ":%s KILL %s :%s (Nick collision (new))",
+                                          me.id, uid, me.name);
+                       return 0;
+               }
+               else
+               {
+                       if(sameuser)
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                                    "Nick collision on %s(%s <- %s)(older %s)",
+                                                    target_p->name, target_p->from->name,
+                                                    client_p->name, action);
+                       else
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                                    "Nick collision on %s(%s <- %s)(newer %s)",
+                                                    target_p->name, target_p->from->name,
+                                                    client_p->name, action);
+
+                       if (use_save)
+                       {
+                               ServerStats->is_save++;
+                               save_user(&me, &me, target_p);
+                       }
+                       else
+                       {
+                               ServerStats->is_kill++;
+                               sendto_one_numeric(target_p, ERR_NICKCOLLISION,
+                                               form_str(ERR_NICKCOLLISION), target_p->name);
+
+                               /* now we just need to kill the existing client */
+                               kill_client_serv_butone(client_p, target_p,
+                                               "%s (Nick collision (new))", me.name);
+
+                               target_p->flags |= FLAGS_KILLED;
+                               (void) exit_client(client_p, target_p, &me, "Nick collision");
+                       }
+
+                       register_client(client_p, parc >= 10 ? source_p : NULL,
+                                       nick, newts, parc, parv);
+
+                       return 0;
+               }
+       }
+}
+
+
+static int
+perform_nickchange_collides(struct Client *source_p, struct Client *client_p,
+                           struct Client *target_p, int parc,
+                           const char *parv[], time_t newts, const char *nick)
+{
+       int sameuser;
+       int use_save;
+       const char *action;
+
+       use_save = ConfigFileEntry.collision_fnc && can_save(target_p) &&
+               can_save(source_p);
+       action = use_save ? "saved" : "killed";
+
+       /* its a client changing nick and causing a collide */
+       if(!newts || !target_p->tsinfo || (newts == target_p->tsinfo) || !source_p->user)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Nick change collision from %s to %s(%s <- %s)(both %s)",
+                                    source_p->name, target_p->name, target_p->from->name,
+                                    client_p->name, action);
+
+               if (use_save)
+               {
+                       ServerStats->is_save += 2;
+                       save_user(&me, &me, target_p);
+                       sendto_one(client_p, ":%s SAVE %s %ld", me.id,
+                                       source_p->id, (long)newts);
+                       /* don't send a redundant nick change */
+                       if (!IsDigit(source_p->name[0]))
+                               change_remote_nick(client_p, source_p, CurrentTime, source_p->id, 1);
+               }
+               else
+               {
+                       ServerStats->is_kill++;
+                       sendto_one_numeric(target_p, ERR_NICKCOLLISION,
+                                       form_str(ERR_NICKCOLLISION), target_p->name);
+
+                       kill_client_serv_butone(NULL, source_p, "%s (Nick change collision)", me.name);
+
+                       ServerStats->is_kill++;
+
+                       kill_client_serv_butone(NULL, target_p, "%s (Nick change collision)", me.name);
+
+                       target_p->flags |= FLAGS_KILLED;
+                       exit_client(NULL, target_p, &me, "Nick collision(new)");
+                       source_p->flags |= FLAGS_KILLED;
+                       exit_client(client_p, source_p, &me, "Nick collision(old)");
+               }
+               return 0;
+       }
+       else
+       {
+               sameuser = !irccmp(target_p->username, source_p->username) &&
+                       !irccmp(target_p->host, source_p->host);
+
+               if((sameuser && newts < target_p->tsinfo) ||
+                  (!sameuser && newts > target_p->tsinfo))
+               {
+                       if(sameuser)
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                                    "Nick change collision from %s to %s(%s <- %s)(older %s)",
+                                                    source_p->name, target_p->name,
+                                                    target_p->from->name, client_p->name, action);
+                       else
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                                    "Nick change collision from %s to %s(%s <- %s)(newer %s)",
+                                                    source_p->name, target_p->name,
+                                                    target_p->from->name, client_p->name, action);
+
+                       if (use_save)
+                       {
+                               ServerStats->is_save++;
+                               /* can't broadcast a SAVE because the
+                                * nickchange has happened at client_p
+                                * but not in other directions -- jilles */
+                               sendto_one(client_p, ":%s SAVE %s %ld", me.id,
+                                               source_p->id, (long)newts);
+                               /* same CurrentTime as in save_user() */
+                               /* send a :<id> NICK <id> <ts> (!) */
+                               if (!IsDigit(source_p->name[0]))
+                                       change_remote_nick(client_p, source_p, CurrentTime, source_p->id, 1);
+                       }
+                       else
+                       {
+                               ServerStats->is_kill++;
+
+                               sendto_one_numeric(target_p, ERR_NICKCOLLISION,
+                                               form_str(ERR_NICKCOLLISION), target_p->name);
+
+                               /* kill the client issuing the nickchange */
+                               kill_client_serv_butone(client_p, source_p,
+                                               "%s (Nick change collision)", me.name);
+
+                               source_p->flags |= FLAGS_KILLED;
+
+                               if(sameuser)
+                                       exit_client(client_p, source_p, &me, "Nick collision(old)");
+                               else
+                                       exit_client(client_p, source_p, &me, "Nick collision(new)");
+                       }
+                       return 0;
+               }
+               else
+               {
+                       if(sameuser)
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                                    "Nick collision on %s(%s <- %s)(older %s)",
+                                                    target_p->name, target_p->from->name,
+                                                    client_p->name, action);
+                       else
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                                    "Nick collision on %s(%s <- %s)(newer %s)",
+                                                    target_p->name, target_p->from->name,
+                                                    client_p->name, action);
+
+                       if (use_save)
+                       {
+                               ServerStats->is_save++;
+                               save_user(&me, &me, target_p);
+                       }
+                       else
+                       {
+                               sendto_one_numeric(target_p, ERR_NICKCOLLISION,
+                                               form_str(ERR_NICKCOLLISION), target_p->name);
+
+                               /* kill the client who existed before hand */
+                               kill_client_serv_butone(client_p, target_p, "%s (Nick collision)", me.name);
+
+                               ServerStats->is_kill++;
+
+                               target_p->flags |= FLAGS_KILLED;
+                               (void) exit_client(client_p, target_p, &me, "Nick collision");
+                       }
+               }
+       }
+
+       change_remote_nick(client_p, source_p, newts, nick, 1);
+
+       return 0;
+}
+
+static int
+register_client(struct Client *client_p, struct Client *server,
+               const char *nick, time_t newts, int parc, const char *parv[])
+{
+       struct Client *source_p;
+       struct User *user;
+       struct nd_entry *nd;
+       const char *m;
+       int flag;
+
+       source_p = make_client(client_p);
+       user = make_user(source_p);
+       dlinkAddTail(source_p, &source_p->node, &global_client_list);
+
+       source_p->hopcount = atoi(parv[2]);
+       source_p->tsinfo = newts;
+
+       strcpy(source_p->name, nick);
+       strlcpy(source_p->username, parv[5], sizeof(source_p->username));
+       strlcpy(source_p->host, parv[6], sizeof(source_p->host));
+       strlcpy(source_p->orighost, source_p->host, sizeof(source_p->orighost));
+
+       if(parc == 12)
+       {
+               user->server = find_or_add(server->name);
+               strlcpy(source_p->info, parv[11], sizeof(source_p->info));
+               strlcpy(source_p->sockhost, parv[7], sizeof(source_p->sockhost));
+               strlcpy(source_p->id, parv[8], sizeof(source_p->id));
+               add_to_id_hash(source_p->id, source_p);
+               if (strcmp(parv[9], "*"))
+               {
+                       strlcpy(source_p->orighost, parv[9], sizeof(source_p->orighost));
+                       if (irccmp(source_p->host, source_p->orighost))
+                               SetDynSpoof(source_p);
+               }
+               if (strcmp(parv[10], "*"))
+                       strlcpy(source_p->user->suser, parv[10], sizeof(source_p->user->suser));
+       }
+       else if(parc == 10)
+       {
+               user->server = find_or_add(server->name);
+               strlcpy(source_p->info, parv[9], sizeof(source_p->info));
+               strlcpy(source_p->sockhost, parv[7], sizeof(source_p->sockhost));
+               strlcpy(source_p->id, parv[8], sizeof(source_p->id));
+               add_to_id_hash(source_p->id, source_p);
+       }
+       else
+       {
+               user->server = find_or_add(parv[7]);
+               strlcpy(source_p->info, parv[8], sizeof(source_p->info));
+       }
+
+       /* remove any nd entries for this nick */
+       if((nd = hash_find_nd(nick)))
+               free_nd_entry(nd);
+
+       add_to_client_hash(nick, source_p);
+       add_to_hostname_hash(source_p->host, source_p);
+       monitor_signon(source_p);
+
+       m = &parv[4][1];
+       while(*m)
+       {
+               flag = user_modes[(unsigned char) *m];
+
+               if(flag & UMODE_SERVICE)
+               {
+                       int hit = 0;
+                       dlink_node *ptr;
+
+                       DLINK_FOREACH(ptr, service_list.head)
+                       {
+                               if(!irccmp((const char *) ptr->data, user->server))
+                               {
+                                       hit++;
+                                       break;
+                               }
+                       }
+
+                       if(!hit)
+                       {
+                               m++;
+                               continue;
+                       }
+               }
+
+               /* increment +i count if theyre invis */
+               if(!(source_p->umodes & UMODE_INVISIBLE) && (flag & UMODE_INVISIBLE))
+                       Count.invisi++;
+
+               /* increment opered count if theyre opered */
+               if(!(source_p->umodes & UMODE_OPER) && (flag & UMODE_OPER))
+                       Count.oper++;
+
+               source_p->umodes |= flag;
+               m++;
+       }
+
+       if(IsOper(source_p) && !IsService(source_p))
+               dlinkAddAlloc(source_p, &oper_list);
+
+       SetRemoteClient(source_p);
+
+       if(++Count.total > Count.max_tot)
+               Count.max_tot = Count.total;
+
+       if(server == NULL)
+       {
+               if((source_p->servptr = find_server(NULL, user->server)) == NULL)
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "Ghost killed: %s on invalid server %s",
+                                            source_p->name, user->server);
+                       kill_client(client_p, source_p, "%s (Server doesn't exist)", me.name);
+                       source_p->flags |= FLAGS_KILLED;
+                       return exit_client(NULL, source_p, &me, "Ghosted Client");
+               }
+       }
+       else
+               source_p->servptr = server;
+
+       dlinkAdd(source_p, &source_p->lnode, &source_p->servptr->serv->users);
+
+       /* fake direction */
+       if(source_p->servptr->from != source_p->from)
+       {
+               struct Client *target_p = source_p->servptr->from;
+
+               sendto_realops_snomask(SNO_DEBUG, L_ALL,
+                                    "Bad User [%s] :%s USER %s@%s %s, != %s[%s]",
+                                    client_p->name, source_p->name,
+                                    source_p->username, source_p->host,
+                                    user->server, target_p->name, target_p->from->name);
+               kill_client(client_p, source_p,
+                           "%s (NICK from wrong direction (%s != %s))",
+                           me.name, user->server, target_p->from->name);
+               source_p->flags |= FLAGS_KILLED;
+               return exit_client(source_p, source_p, &me, "USER server wrong direction");
+       }
+
+       call_hook(h_new_remote_user, source_p);
+
+       return (introduce_client(client_p, source_p, user, nick, parc == 12));
+}
+
+/* Check if we can do SAVE. target_p can be a client to save or a
+ * server introducing a client -- jilles */
+static int
+can_save(struct Client *target_p)
+{
+       struct Client *serv_p;
+
+       if (MyClient(target_p))
+               return 1;
+       if (!has_id(target_p))
+               return 0;
+       serv_p = IsServer(target_p) ? target_p : target_p->servptr;
+       while (serv_p != NULL && serv_p != &me)
+       {
+               if (!(serv_p->serv->caps & CAP_SAVE))
+                       return 0;
+               serv_p = serv_p->servptr;
+       }
+       return serv_p == &me;
+}
+
+static void
+save_user(struct Client *client_p, struct Client *source_p,
+               struct Client *target_p)
+{
+       if (!MyConnect(target_p) && (!has_id(target_p) || !IsCapable(target_p->from, CAP_SAVE)))
+       {
+               /* This shouldn't happen */
+               /* Note we only need SAVE support in this direction */
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                               "Killed %s!%s@%s for nick collision detected by %s (%s does not support SAVE)",
+                               target_p->name, target_p->username, target_p->host, source_p->name, target_p->from->name);
+               kill_client_serv_butone(NULL, target_p, "%s (Nick collision (no SAVE support))", me.name);
+               ServerStats->is_kill++;
+
+               target_p->flags |= FLAGS_KILLED;
+               (void) exit_client(NULL, target_p, &me, "Nick collision (no SAVE support)");
+               return;
+       }
+       sendto_server(client_p, NULL, CAP_SAVE|CAP_TS6, NOCAPS, ":%s SAVE %s %ld",
+                       source_p->id, target_p->id, (long)target_p->tsinfo);
+       sendto_server(client_p, NULL, CAP_TS6, CAP_SAVE, ":%s NICK %s :%ld",
+                       target_p->id, target_p->id, (long)CurrentTime);
+       sendto_server(client_p, NULL, NOCAPS, CAP_TS6, ":%s NICK %s :%ld",
+                       target_p->name, target_p->id, (long)CurrentTime);
+       if (!IsMe(client_p))
+               sendto_realops_snomask(SNO_SKILL, L_ALL,
+                               "Received SAVE message for %s from %s",
+                               target_p->name, source_p->name);
+       if (MyClient(target_p))
+       {
+               sendto_one_numeric(target_p, RPL_SAVENICK,
+                               form_str(RPL_SAVENICK), target_p->id);
+               change_local_nick(target_p, target_p, target_p->id, 0);
+       }
+       else
+       {
+               /* XXX the uid nick gets garbage TS; shouldn't matter though */
+               change_remote_nick(target_p, target_p, CurrentTime, target_p->id, 0);
+       }
+}
diff --git a/modules/core/m_part.c b/modules/core/m_part.c
new file mode 100644 (file)
index 0000000..d31da2f
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_part.c: Parts a user from a channel.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_part.c 98 2005-09-11 03:37:47Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "channel.h"
+#include "client.h"
+#include "common.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "s_serv.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_conf.h"
+#include "packet.h"
+
+static int m_part(struct Client *, struct Client *, int, const char **);
+
+struct Message part_msgtab = {
+       "PART", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_part, 2}, {m_part, 2}, mg_ignore, mg_ignore, {m_part, 2}}
+};
+
+mapi_clist_av1 part_clist[] = { &part_msgtab, NULL };
+
+DECLARE_MODULE_AV1(part, NULL, NULL, part_clist, NULL, NULL, "$Revision: 98 $");
+
+static void part_one_client(struct Client *client_p,
+                           struct Client *source_p, char *name, char *reason);
+
+
+/*
+** m_part
+**      parv[0] = sender prefix
+**      parv[1] = channel
+**      parv[2] = reason
+*/
+static int
+m_part(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       char *p, *name;
+       char reason[REASONLEN + 1];
+       char *s = LOCAL_COPY(parv[1]);
+
+       reason[0] = '\0';
+
+       if(parc > 2)
+               strlcpy(reason, parv[2], sizeof(reason));
+
+       name = strtoken(&p, s, ",");
+
+       /* Finish the flood grace period... */
+       if(MyClient(source_p) && !IsFloodDone(source_p))
+               flood_endgrace(source_p);
+
+       strip_colour(reason);
+
+       while(name)
+       {
+               part_one_client(client_p, source_p, name, reason);
+               name = strtoken(&p, NULL, ",");
+       }
+       return 0;
+}
+
+/*
+ * part_one_client
+ *
+ * inputs      - pointer to server
+ *             - pointer to source client to remove
+ *             - char pointer of name of channel to remove from
+ * output      - none
+ * side effects        - remove ONE client given the channel name 
+ */
+static void
+part_one_client(struct Client *client_p, struct Client *source_p, char *name, char *reason)
+{
+       struct Channel *chptr;
+       struct membership *msptr;
+
+       if((chptr = find_channel(name)) == NULL)
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name);
+               return;
+       }
+
+       msptr = find_channel_membership(chptr, source_p);
+       if(msptr == NULL)
+       {
+               sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), name);
+               return;
+       }
+
+       if(MyConnect(source_p) && !IsOper(source_p) && !IsExemptSpambot(source_p))
+               check_spambot_warning(source_p, NULL);
+
+       /*
+        *  Remove user from the old channel (if any)
+        *  only allow /part reasons in -m chans
+        */
+       if(reason[0] && (is_chanop(msptr) || !MyConnect(source_p) ||
+                        ((can_send(chptr, source_p, msptr) > 0 &&
+                          (source_p->localClient->firsttime +
+                           ConfigFileEntry.anti_spam_exit_message_time) < CurrentTime))))
+       {
+               sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
+                             ":%s PART %s :%s", use_id(source_p), chptr->chname, reason);
+               sendto_server(client_p, chptr, NOCAPS, CAP_TS6,
+                             ":%s PART %s :%s", source_p->name, chptr->chname, reason);
+               sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s :%s",
+                                    source_p->name, source_p->username,
+                                    source_p->host, chptr->chname, reason);
+       }
+       else
+       {
+               sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
+                             ":%s PART %s", use_id(source_p), chptr->chname);
+               sendto_server(client_p, chptr, NOCAPS, CAP_TS6,
+                             ":%s PART %s", source_p->name, chptr->chname);
+               sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s",
+                                    source_p->name, source_p->username,
+                                    source_p->host, chptr->chname);
+       }
+       remove_user_from_channel(msptr);
+}
diff --git a/modules/core/m_quit.c b/modules/core/m_quit.c
new file mode 100644 (file)
index 0000000..a113b35
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_quit.c: Makes a user quit from IRC.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_quit.c 1333 2006-05-14 13:47:33Z jilles $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_serv.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_conf.h"
+#include "sprintf_irc.h"
+
+static int m_quit(struct Client *, struct Client *, int, const char **);
+static int ms_quit(struct Client *, struct Client *, int, const char **);
+
+struct Message quit_msgtab = {
+       "QUIT", 0, 0, 0, MFLG_SLOW | MFLG_UNREG,
+       {{m_quit, 0}, {m_quit, 0}, {ms_quit, 0}, mg_ignore, mg_ignore, {m_quit, 0}}
+};
+
+mapi_clist_av1 quit_clist[] = { &quit_msgtab, NULL };
+
+DECLARE_MODULE_AV1(quit, NULL, NULL, quit_clist, NULL, NULL, "$Revision: 1333 $");
+
+/*
+** m_quit
+**      parv[0] = sender prefix
+**      parv[1] = comment
+*/
+static int
+m_quit(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       char *comment = LOCAL_COPY((parc > 1 && parv[1]) ? parv[1] : client_p->name);
+       char reason[REASONLEN + 1];
+
+       source_p->flags |= FLAGS_NORMALEX;
+
+       if(strlen(comment) > (size_t) REASONLEN)
+               comment[REASONLEN] = '\0';
+
+       strip_colour(comment);
+
+       if(ConfigFileEntry.client_exit && comment[0])
+       {
+               ircsnprintf(reason, sizeof(reason), "Quit: %s", comment);
+               comment = reason;
+       }
+
+       if(!IsOper(source_p) &&
+          (source_p->localClient->firsttime + ConfigFileEntry.anti_spam_exit_message_time) >
+          CurrentTime)
+       {
+               exit_client(client_p, source_p, source_p, "Client Quit");
+               return 0;
+       }
+
+       exit_client(client_p, source_p, source_p, comment);
+
+       return 0;
+}
+
+/*
+** ms_quit
+**      parv[0] = sender prefix
+**      parv[1] = comment
+*/
+static int
+ms_quit(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       char *comment = LOCAL_COPY((parc > 1 && parv[1]) ? parv[1] : client_p->name);
+
+       source_p->flags |= FLAGS_NORMALEX;
+       if(strlen(comment) > (size_t) REASONLEN)
+               comment[REASONLEN] = '\0';
+
+       exit_client(client_p, source_p, source_p, comment);
+
+       return 0;
+}
diff --git a/modules/core/m_server.c b/modules/core/m_server.c
new file mode 100644 (file)
index 0000000..82f6c54
--- /dev/null
@@ -0,0 +1,723 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_server.c: Introduces a server.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_server.c 2733 2006-11-10 00:04:08Z jilles $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "client.h"            /* client struct */
+#include "common.h"            /* TRUE bleah */
+#include "event.h"
+#include "hash.h"              /* add_to_client_hash */
+#include "irc_string.h"
+#include "ircd.h"              /* me */
+#include "numeric.h"           /* ERR_xxx */
+#include "s_conf.h"            /* struct ConfItem */
+#include "s_newconf.h"
+#include "s_log.h"             /* log level defines */
+#include "s_serv.h"            /* server_estab, check_server */
+#include "s_stats.h"           /* ServerStats */
+#include "scache.h"            /* find_or_add */
+#include "send.h"              /* sendto_one */
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+
+static int mr_server(struct Client *, struct Client *, int, const char **);
+static int ms_server(struct Client *, struct Client *, int, const char **);
+static int ms_sid(struct Client *, struct Client *, int, const char **);
+
+struct Message server_msgtab = {
+       "SERVER", 0, 0, 0, MFLG_SLOW | MFLG_UNREG,
+       {{mr_server, 4}, mg_reg, mg_ignore, {ms_server, 4}, mg_ignore, mg_reg}
+};
+struct Message sid_msgtab = {
+       "SID", 0, 0, 0, MFLG_SLOW,
+       {mg_ignore, mg_reg, mg_ignore, {ms_sid, 5}, mg_ignore, mg_reg}
+};
+
+mapi_clist_av1 server_clist[] = { &server_msgtab, &sid_msgtab, NULL };
+
+DECLARE_MODULE_AV1(server, NULL, NULL, server_clist, NULL, NULL, "$Revision: 2733 $");
+
+int bogus_host(const char *host);
+struct Client *server_exists(const char *);
+static int set_server_gecos(struct Client *, const char *);
+
+/*
+ * mr_server - SERVER message handler
+ *      parv[0] = sender prefix
+ *      parv[1] = servername
+ *      parv[2] = serverinfo/hopcount
+ *      parv[3] = serverinfo
+ */
+static int
+mr_server(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       char info[REALLEN + 1];
+       const char *name;
+       struct Client *target_p;
+       int hop;
+
+       name = parv[1];
+       hop = atoi(parv[2]);
+       strlcpy(info, parv[3], sizeof(info));
+
+       /* 
+        * Reject a direct nonTS server connection if we're TS_ONLY -orabidoo
+        */
+       if(!DoesTS(client_p))
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "Link %s dropped, non-TS server",
+                                    get_server_name(client_p, HIDE_IP));
+               exit_client(client_p, client_p, client_p, "Non-TS server");
+               return 0;
+       }
+
+       if(bogus_host(name))
+       {
+               exit_client(client_p, client_p, client_p, "Bogus server name");
+               return 0;
+       }
+
+       /* Now we just have to call check_server and everything should be
+        * check for us... -A1kmm. */
+       switch (check_server(name, client_p))
+       {
+       case -1:
+               if(ConfigFileEntry.warn_no_nline)
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "Unauthorised server connection attempt from %s: "
+                                            "No entry for servername %s",
+                                            get_server_name(client_p, HIDE_IP), name);
+
+                       ilog(L_SERVER, "Access denied, no connect block for server %s%s",
+                            EmptyString(client_p->name) ? name : "",
+                            log_client_name(client_p, SHOW_IP));
+               }
+
+               exit_client(client_p, client_p, client_p, "Invalid servername.");
+               return 0;
+               /* NOT REACHED */
+               break;
+
+       case -2:
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Unauthorised server connection attempt from %s: "
+                                    "Bad password for server %s",
+                                    get_server_name(client_p, HIDE_IP), name);
+
+               ilog(L_SERVER, "Access denied, invalid password for server %s%s",
+                    EmptyString(client_p->name) ? name : "",
+                    log_client_name(client_p, SHOW_IP));
+
+               exit_client(client_p, client_p, client_p, "Invalid password.");
+               return 0;
+               /* NOT REACHED */
+               break;
+
+       case -3:
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Unauthorised server connection attempt from %s: "
+                                    "Invalid host for server %s",
+                                    get_server_name(client_p, HIDE_IP), name);
+
+               ilog(L_SERVER, "Access denied, invalid host for server %s%s",
+                    EmptyString(client_p->name) ? name : "",
+                    log_client_name(client_p, SHOW_IP));
+
+               exit_client(client_p, client_p, client_p, "Invalid host.");
+               return 0;
+               /* NOT REACHED */
+               break;
+
+               /* servername is > HOSTLEN */
+       case -4:
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Invalid servername %s from %s",
+                                    name, get_server_name(client_p, HIDE_IP));
+               ilog(L_SERVER, "Access denied, invalid servername from %s",
+                    log_client_name(client_p, SHOW_IP));
+
+               exit_client(client_p, client_p, client_p, "Invalid servername.");
+               return 0;
+               /* NOT REACHED */
+               break;
+       }
+
+       if((target_p = server_exists(name)))
+       {
+               /*
+                * This link is trying feed me a server that I already have
+                * access through another path -- multiple paths not accepted
+                * currently, kill this link immediately!!
+                *
+                * Rather than KILL the link which introduced it, KILL the
+                * youngest of the two links. -avalon
+                *
+                * Definitely don't do that here. This is from an unregistered
+                * connect - A1kmm.
+                */
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Attempt to re-introduce server %s from %s",
+                                    name, get_server_name(client_p, HIDE_IP));
+               ilog(L_SERVER, "Attempt to re-introduce server %s from %s",
+                               name, log_client_name(client_p, SHOW_IP));
+
+               sendto_one(client_p, "ERROR :Server already exists.");
+               exit_client(client_p, client_p, client_p, "Server Exists");
+               return 0;
+       }
+
+       if(has_id(client_p) && (target_p = find_id(client_p->id)) != NULL)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Attempt to re-introduce SID %s from %s%s",
+                                    client_p->id,
+                                    EmptyString(client_p->name) ? name : "",
+                                    get_server_name(client_p, HIDE_IP));
+               ilog(L_SERVER, "Attempt to re-introduce SID %s from %s%s",
+                               client_p->id,
+                               EmptyString(client_p->name) ? name : "",
+                               log_client_name(client_p, SHOW_IP));
+
+               sendto_one(client_p, "ERROR :SID already exists.");
+               exit_client(client_p, client_p, client_p, "SID Exists");
+               return 0;
+       }
+
+       /*
+        * if we are connecting (Handshake), we already have the name from the
+        * C:line in client_p->name
+        */
+
+       strlcpy(client_p->name, name, sizeof(client_p->name));
+       set_server_gecos(client_p, info);
+       client_p->hopcount = hop;
+       server_estab(client_p);
+
+       return 0;
+}
+
+/*
+ * ms_server - SERVER message handler
+ *      parv[0] = sender prefix
+ *      parv[1] = servername
+ *      parv[2] = serverinfo/hopcount
+ *      parv[3] = serverinfo
+ */
+static int
+ms_server(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       char info[REALLEN + 1];
+       /* same size as in s_misc.c */
+       const char *name;
+       struct Client *target_p;
+       struct remote_conf *hub_p;
+       hook_data_client hdata;
+       int hop;
+       int hlined = 0;
+       int llined = 0;
+       dlink_node *ptr;
+
+       name = parv[1];
+       hop = atoi(parv[2]);
+       strlcpy(info, parv[3], sizeof(info));
+
+       if((target_p = server_exists(name)))
+       {
+               /*
+                * This link is trying feed me a server that I already have
+                * access through another path -- multiple paths not accepted
+                * currently, kill this link immediately!!
+                *
+                * Rather than KILL the link which introduced it, KILL the
+                * youngest of the two links. -avalon
+                *
+                * I think that we should exit the link itself, not the introducer,
+                * and we should always exit the most recently received(i.e. the
+                * one we are receiving this SERVER for. -A1kmm
+                *
+                * You *cant* do this, if you link somewhere, it bursts you a server
+                * that already exists, then sends you a client burst, you squit the
+                * server, but you keep getting the burst of clients on a server that
+                * doesnt exist, although ircd can handle it, its not a realistic
+                * solution.. --fl_ 
+                */
+               /* It is behind a host-masked server. Completely ignore the
+                * server message(don't propagate or we will delink from whoever
+                * we propagate to). -A1kmm */
+               if(irccmp(target_p->name, name) && target_p->from == client_p)
+                       return 0;
+
+               sendto_one(client_p, "ERROR :Server %s already exists", name);
+
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Link %s cancelled, server %s already exists",
+                                    get_server_name(client_p, SHOW_IP), name);
+               ilog(L_SERVER, "Link %s cancelled, server %s already exists",
+                       client_p->name, name);
+
+               exit_client(client_p, client_p, &me, "Server Exists");
+               return 0;
+       }
+
+       /* 
+        * User nicks never have '.' in them and server names
+        * must always have '.' in them.
+        */
+       if(strchr(name, '.') == NULL)
+       {
+               /*
+                * Server trying to use the same name as a person. Would
+                * cause a fair bit of confusion. Enough to make it hellish
+                * for a while and servers to send stuff to the wrong place.
+                */
+               sendto_one(client_p, "ERROR :Nickname %s already exists!", name);
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Link %s cancelled: Server/nick collision on %s",
+                                    get_server_name(client_p, HIDE_IP), name);
+               ilog(L_SERVER, "Link %s cancelled: Server/nick collision on %s",
+                       client_p->name, name);
+
+               exit_client(client_p, client_p, client_p, "Nick as Server");
+               return 0;
+       }
+
+       /*
+        * 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...
+        */
+       if(parc == 1 || EmptyString(info))
+       {
+               sendto_one(client_p, "ERROR :No server info specified for %s", name);
+               return 0;
+       }
+
+       /*
+        * See if the newly found server is behind a guaranteed
+        * leaf. If so, close the link.
+        *
+        */
+       DLINK_FOREACH(ptr, hubleaf_conf_list.head)
+       {
+               hub_p = ptr->data;
+
+               if(match(hub_p->server, client_p->name) && match(hub_p->host, name))
+               {
+                       if(hub_p->flags & CONF_HUB)
+                               hlined++;
+                       else
+                               llined++;
+               }
+       }
+
+       /* Ok, this way this works is
+        *
+        * A server can have a CONF_HUB allowing it to introduce servers
+        * behind it.
+        *
+        * connect {
+        *            name = "irc.bighub.net";
+        *            hub_mask="*";
+        *            ...
+        * 
+        * That would allow "irc.bighub.net" to introduce anything it wanted..
+        *
+        * However
+        *
+        * connect {
+        *            name = "irc.somehub.fi";
+        *            hub_mask="*";
+        *            leaf_mask="*.edu";
+        *...
+        * Would allow this server in finland to hub anything but
+        * .edu's
+        */
+
+       /* Ok, check client_p can hub the new server, and make sure it's not a LL */
+       if(!hlined)
+       {
+               /* OOOPs nope can't HUB */
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "Non-Hub link %s introduced %s.",
+                                    get_server_name(client_p, HIDE_IP), name);
+               ilog(L_SERVER, "Non-Hub link %s introduced %s.",
+                       client_p->name, name);
+
+               exit_client(NULL, client_p, &me, "No matching hub_mask.");
+               return 0;
+       }
+
+       /* Check for the new server being leafed behind this HUB */
+       if(llined)
+       {
+               /* OOOPs nope can't HUB this leaf */
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Link %s introduced leafed server %s.",
+                                    get_server_name(client_p, HIDE_IP), name);
+               ilog(L_SERVER, "Link %s introduced leafed server %s.",
+                       client_p->name, name);  
+
+               exit_client(NULL, client_p, &me, "Leafed Server.");
+               return 0;
+       }
+
+
+
+       if(strlen(name) > HOSTLEN)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Link %s introduced server with invalid servername %s",
+                                    get_server_name(client_p, HIDE_IP), name);
+               ilog(L_SERVER, "Link %s introduced server with invalid servername %s",
+                       client_p->name, name);
+
+               exit_client(NULL, client_p, &me, "Invalid servername introduced.");
+               return 0;
+       }
+
+       target_p = make_client(client_p);
+       make_server(target_p);
+       target_p->hopcount = hop;
+
+       strlcpy(target_p->name, name, sizeof(target_p->name));
+
+       set_server_gecos(target_p, info);
+
+       target_p->serv->up = find_or_add(source_p->name);
+
+       if(has_id(source_p))
+               target_p->serv->upid = source_p->id;
+
+       target_p->servptr = source_p;
+
+       SetServer(target_p);
+
+       dlinkAddTail(target_p, &target_p->node, &global_client_list);
+       dlinkAddTailAlloc(target_p, &global_serv_list);
+       add_to_client_hash(target_p->name, target_p);
+       dlinkAdd(target_p, &target_p->lnode, &target_p->servptr->serv->servers);
+
+       sendto_server(client_p, NULL, NOCAPS, NOCAPS,
+                     ":%s SERVER %s %d :%s%s",
+                     source_p->name, target_p->name, target_p->hopcount + 1,
+                     IsHidden(target_p) ? "(H) " : "", target_p->info);
+
+       sendto_realops_snomask(SNO_EXTERNAL, L_ALL,
+                            "Server %s being introduced by %s", target_p->name, source_p->name);
+
+       /* quick, dirty EOB.  you know you love it. */
+       sendto_one(target_p, ":%s PING %s %s", get_id(&me, target_p), me.name, target_p->name);
+
+       hdata.client = source_p;
+       hdata.target = target_p;
+       call_hook(h_server_introduced, &hdata);
+
+       return 0;
+}
+
+static int
+ms_sid(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+       struct remote_conf *hub_p;
+       hook_data_client hdata;
+       dlink_node *ptr;
+       int hop;
+       int hlined = 0;
+       int llined = 0;
+
+       hop = atoi(parv[2]);
+
+       /* collision on the name? */
+       if((target_p = server_exists(parv[1])) != NULL)
+       {
+               sendto_one(client_p, "ERROR :Server %s already exists", parv[1]);
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Link %s cancelled, server %s already exists",
+                                    get_server_name(client_p, SHOW_IP), parv[1]);
+               ilog(L_SERVER, "Link %s cancelled, server %s already exists",
+                       client_p->name, parv[1]);
+
+               exit_client(NULL, client_p, &me, "Server Exists");
+               return 0;
+       }
+
+       /* collision on the SID? */
+       if((target_p = find_id(parv[3])) != NULL)
+       {
+               sendto_one(client_p, "ERROR :SID %s already exists", parv[3]);
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Link %s cancelled, SID %s already exists",
+                                    get_server_name(client_p, SHOW_IP), parv[3]);
+               ilog(L_SERVER, "Link %s cancelled, SID %s already exists",
+                       client_p->name, parv[3]);
+
+               exit_client(NULL, client_p, &me, "Server Exists");
+               return 0;
+       }
+
+       if(bogus_host(parv[1]) || strlen(parv[1]) > HOSTLEN)
+       {
+               sendto_one(client_p, "ERROR :Invalid servername");
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Link %s cancelled, servername %s invalid",
+                                    get_server_name(client_p, SHOW_IP), parv[1]);
+               ilog(L_SERVER, "Link %s cancelled, servername %s invalid",
+                       client_p->name, parv[1]);
+
+               exit_client(NULL, client_p, &me, "Bogus server name");
+               return 0;
+       }
+
+       if(!IsDigit(parv[3][0]) || !IsIdChar(parv[3][1]) ||
+          !IsIdChar(parv[3][2]) || parv[3][3] != '\0')
+       {
+               sendto_one(client_p, "ERROR :Invalid SID");
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Link %s cancelled, SID %s invalid",
+                                    get_server_name(client_p, SHOW_IP), parv[3]);
+               ilog(L_SERVER, "Link %s cancelled, SID %s invalid",
+                       client_p->name, parv[3]);
+
+               exit_client(NULL, client_p, &me, "Bogus SID");
+               return 0;
+       }
+
+       /* for the directly connected server:
+        * H: allows it to introduce a server matching that mask
+        * L: disallows it introducing a server matching that mask
+        */
+       DLINK_FOREACH(ptr, hubleaf_conf_list.head)
+       {
+               hub_p = ptr->data;
+
+               if(match(hub_p->server, client_p->name) && match(hub_p->host, parv[1]))
+               {
+                       if(hub_p->flags & CONF_HUB)
+                               hlined++;
+                       else
+                               llined++;
+               }
+       }
+
+       /* no matching hub_mask */
+       if(!hlined)
+       {
+               sendto_one(client_p, "ERROR :No matching hub_mask");
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Non-Hub link %s introduced %s.",
+                                    get_server_name(client_p, SHOW_IP), parv[1]);
+               ilog(L_SERVER, "Non-Hub link %s introduced %s.",
+                       client_p->name, parv[1]);
+               exit_client(NULL, client_p, &me, "No matching hub_mask.");
+               return 0;
+       }
+
+       /* matching leaf_mask */
+       if(llined)
+       {
+               sendto_one(client_p, "ERROR :Matching leaf_mask");
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Link %s introduced leafed server %s.",
+                                    get_server_name(client_p, SHOW_IP), parv[1]);
+               ilog(L_SERVER, "Link %s introduced leafed server %s.",
+                       client_p->name, parv[1]);       
+               exit_client(NULL, client_p, &me, "Leafed Server.");
+               return 0;
+       }
+
+       /* ok, alls good */
+       target_p = make_client(client_p);
+       make_server(target_p);
+
+       strlcpy(target_p->name, parv[1], sizeof(target_p->name));
+       target_p->hopcount = atoi(parv[2]);
+       strcpy(target_p->id, parv[3]);
+       set_server_gecos(target_p, parv[4]);
+
+       target_p->serv->up = find_or_add(source_p->name);
+
+       if(has_id(source_p))
+               target_p->serv->upid = source_p->id;
+
+       target_p->servptr = source_p;
+       SetServer(target_p);
+
+       dlinkAddTail(target_p, &target_p->node, &global_client_list);
+       dlinkAddTailAlloc(target_p, &global_serv_list);
+       add_to_client_hash(target_p->name, target_p);
+       add_to_id_hash(target_p->id, target_p);
+       dlinkAdd(target_p, &target_p->lnode, &target_p->servptr->serv->servers);
+
+       sendto_server(client_p, NULL, CAP_TS6, NOCAPS,
+                     ":%s SID %s %d %s :%s%s",
+                     source_p->id, target_p->name, target_p->hopcount + 1,
+                     target_p->id, IsHidden(target_p) ? "(H) " : "", target_p->info);
+       sendto_server(client_p, NULL, NOCAPS, CAP_TS6,
+                     ":%s SERVER %s %d :%s%s",
+                     source_p->name, target_p->name, target_p->hopcount + 1,
+                     IsHidden(target_p) ? "(H) " : "", target_p->info);
+
+       sendto_realops_snomask(SNO_EXTERNAL, L_ALL,
+                            "Server %s being introduced by %s", target_p->name, source_p->name);
+
+       /* quick, dirty EOB.  you know you love it. */
+       sendto_one(target_p, ":%s PING %s %s",
+                  get_id(&me, target_p), me.name, get_id(target_p, target_p));
+
+       hdata.client = source_p;
+       hdata.target = target_p;
+       call_hook(h_server_introduced, &hdata);
+
+       return 0;
+}
+
+/* set_server_gecos()
+ *
+ * input       - pointer to client
+ * output      - none
+ * side effects - servers gecos field is set
+ */
+static int
+set_server_gecos(struct Client *client_p, const char *info)
+{
+       /* check the info for [IP] */
+       if(info[0])
+       {
+               char *p;
+               char *s;
+               char *t;
+
+               s = LOCAL_COPY(info);
+
+               /* we should only check the first word for an ip */
+               if((p = strchr(s, ' ')))
+                       *p = '\0';
+
+               /* check for a ] which would symbolise an [IP] */
+               if((t = strchr(s, ']')))
+               {
+                       /* set s to after the first space */
+                       if(p)
+                               s = ++p;
+                       else
+                               s = NULL;
+               }
+               /* no ], put the space back */
+               else if(p)
+                       *p = ' ';
+
+               /* p may have been set to a trailing space, so check s exists and that
+                * it isnt \0 */
+               if(s && (*s != '\0'))
+               {
+                       /* a space? if not (H) could be the last part of info.. */
+                       if((p = strchr(s, ' ')))
+                               *p = '\0';
+
+                       /* check for (H) which is a hidden server */
+                       if(!strcmp(s, "(H)"))
+                       {
+                               SetHidden(client_p);
+
+                               /* if there was no space.. theres nothing to set info to */
+                               if(p)
+                                       s = ++p;
+                               else
+                                       s = NULL;
+                       }
+                       else if(p)
+                               *p = ' ';
+
+                       /* if there was a trailing space, s could point to \0, so check */
+                       if(s && (*s != '\0'))
+                       {
+                               strlcpy(client_p->info, s, sizeof(client_p->info));
+                               return 1;
+                       }
+               }
+       }
+
+       strlcpy(client_p->info, "(Unknown Location)", sizeof(client_p->info));
+
+       return 1;
+}
+
+/*
+ * bogus_host
+ *
+ * inputs      - hostname
+ * output      - 1 if a bogus hostname input, 0 if its valid
+ * side effects        - none
+ */
+int
+bogus_host(const char *host)
+{
+       int bogus_server = 0;
+       const char *s;
+       int dots = 0;
+
+       for(s = host; *s; s++)
+       {
+               if(!IsServChar(*s))
+               {
+                       bogus_server = 1;
+                       break;
+               }
+               if('.' == *s)
+                       ++dots;
+       }
+
+       if(!dots || bogus_server)
+               return 1;
+
+       return 0;
+}
+
+/*
+ * server_exists()
+ * 
+ * inputs      - servername
+ * output      - 1 if server exists, 0 if doesnt exist
+ */
+struct Client *
+server_exists(const char *servername)
+{
+       struct Client *target_p;
+       dlink_node *ptr;
+
+       DLINK_FOREACH(ptr, global_serv_list.head)
+       {
+               target_p = ptr->data;
+
+               if(match(target_p->name, servername) || match(servername, target_p->name))
+                       return target_p;
+       }
+
+       return NULL;
+}
diff --git a/modules/core/m_sjoin.c b/modules/core/m_sjoin.c
new file mode 100644 (file)
index 0000000..3682f22
--- /dev/null
@@ -0,0 +1,918 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_sjoin.c: Joins a user to a channel.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_sjoin.c 3131 2007-01-21 15:36:31Z jilles $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "common.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_serv.h"
+#include "s_conf.h"
+
+static int ms_sjoin(struct Client *, struct Client *, int, const char **);
+
+struct Message sjoin_msgtab = {
+       "SJOIN", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_ignore, mg_ignore, {ms_sjoin, 0}, mg_ignore, mg_ignore}
+};
+
+mapi_clist_av1 sjoin_clist[] = { &sjoin_msgtab, NULL };
+
+DECLARE_MODULE_AV1(sjoin, NULL, NULL, sjoin_clist, NULL, NULL, "$Revision: 3131 $");
+
+/*
+ * ms_sjoin
+ * parv[0] - sender
+ * parv[1] - TS
+ * parv[2] - channel
+ * parv[3] - modes + n arguments (key and/or limit)
+ * parv[4+n] - flags+nick list (all in one parameter)
+ * 
+ * process a SJOIN, taking the TS's into account to either ignore the
+ * incoming modes or undo the existing ones or merge them, and JOIN
+ * all the specified users while sending JOIN/MODEs to local clients
+ */
+
+
+static char modebuf[MODEBUFLEN];
+static char parabuf[MODEBUFLEN];
+static const char *para[MAXMODEPARAMS];
+static char *mbuf;
+static int pargs;
+
+static void set_final_mode(struct Mode *mode, struct Mode *oldmode);
+static void remove_our_modes(struct Channel *chptr, struct Client *source_p);
+static void remove_ban_list(struct Channel *chptr, struct Client *source_p,
+                           dlink_list * list, char c, int cap, int mems);
+
+static int
+ms_sjoin(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       static char buf_nick[BUFSIZE];
+       static char buf_uid[BUFSIZE];
+       static const char empty_modes[] = "0";
+       struct Channel *chptr;
+       struct Client *target_p, *fakesource_p;
+       time_t newts;
+       time_t oldts;
+       static struct Mode mode, *oldmode;
+       const char *modes;
+       int args = 0;
+       int keep_our_modes = 1;
+       int keep_new_modes = 1;
+       int fl;
+       int isnew;
+       int mlen_nick, mlen_uid;
+       int len_nick;
+       int len_uid;
+       int len;
+       int joins = 0;
+       const char *s;
+       char *ptr_nick;
+       char *ptr_uid;
+       char *p;
+       int i, joinc = 0, timeslice = 0;
+       static char empty[] = "";
+       dlink_node *ptr, *next_ptr;
+
+       if(!IsChannelName(parv[2]) || !check_channel_name(parv[2]))
+               return 0;
+
+       /* SJOIN's for local channels can't happen. */
+       if(*parv[2] == '&')
+               return 0;
+
+       modebuf[0] = parabuf[0] = mode.key[0] = mode.forward[0] = '\0';
+       pargs = mode.mode = mode.limit = mode.join_num = mode.join_time = 0;
+
+       /* Hide connecting server on netburst -- jilles */
+       if (ConfigServerHide.flatten_links && !HasSentEob(source_p))
+               fakesource_p = &me;
+       else
+               fakesource_p = source_p;
+
+       mbuf = modebuf;
+       newts = atol(parv[1]);
+
+       s = parv[3];
+       while (*s)
+       {
+               switch (*(s++))
+               {
+               case 'i':
+                       mode.mode |= MODE_INVITEONLY;
+                       break;
+               case 'n':
+                       mode.mode |= MODE_NOPRIVMSGS;
+                       break;
+               case 'p':
+                       mode.mode |= MODE_PRIVATE;
+                       break;
+               case 's':
+                       mode.mode |= MODE_SECRET;
+                       break;
+               case 'm':
+                       mode.mode |= MODE_MODERATED;
+                       break;
+               case 't':
+                       mode.mode |= MODE_TOPICLIMIT;
+                       break;
+               case 'r':
+                       mode.mode |= MODE_REGONLY;
+                       break;
+               case 'L':
+                       mode.mode |= MODE_EXLIMIT;
+                       break;
+               case 'P':
+                       mode.mode |= MODE_PERMANENT;
+                       break;
+               case 'c':
+                       mode.mode |= MODE_NOCOLOR;
+                       break;
+               case 'g':
+                       mode.mode |= MODE_FREEINVITE;
+                       break;
+               case 'z':
+                       mode.mode |= MODE_OPMODERATE;
+                       break;
+               case 'F':
+                       mode.mode |= MODE_FREETARGET;
+                       break;
+               case 'Q':
+                       mode.mode |= MODE_DISFORWARD;
+                       break;
+               case 'f':
+                       strlcpy(mode.forward, parv[4 + args], sizeof(mode.forward));
+                       args++;
+                       if(parc < 5 + args)
+                               return 0;
+                       break;
+               case 'j':
+                       sscanf(parv[4 + args], "%d:%d", &joinc, &timeslice);
+                       args++;
+                       mode.join_num = joinc;
+                       mode.join_time = timeslice;
+                       if(parc < 5 + args)
+                               return 0;
+                       break;
+               case 'k':
+                       strlcpy(mode.key, parv[4 + args], sizeof(mode.key));
+                       args++;
+                       if(parc < 5 + args)
+                               return 0;
+                       break;
+               case 'l':
+                       mode.limit = atoi(parv[4 + args]);
+                       args++;
+                       if(parc < 5 + args)
+                               return 0;
+                       break;
+               }
+       }
+
+       if(parv[args + 4])
+       {
+               s = parv[args + 4];
+
+               /* remove any leading spaces */
+               while (*s == ' ')
+                       s++;
+       }
+       else
+               s = "";
+
+       if((chptr = get_or_create_channel(source_p, parv[2], &isnew)) == NULL)
+               return 0;       /* channel name too long? */
+
+
+       oldts = chptr->channelts;
+       oldmode = &chptr->mode;
+
+#ifdef IGNORE_BOGUS_TS
+       if(newts < 800000000)
+       {
+               sendto_realops_snomask(SNO_DEBUG, L_ALL,
+                                    "*** Bogus TS %ld on %s ignored from %s",
+                                    (long) newts, chptr->chname, client_p->name);
+
+               newts = (oldts == 0) ? oldts : 800000000;
+       }
+#else
+       if(!isnew && !newts && oldts)
+       {
+               sendto_channel_local(ALL_MEMBERS, chptr,
+                                    ":%s NOTICE %s :*** Notice -- TS for %s "
+                                    "changed from %ld to 0",
+                                    me.name, chptr->chname, chptr->chname, (long) oldts);
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Server %s changing TS on %s from %ld to 0",
+                                    source_p->name, chptr->chname, (long) oldts);
+       }
+#endif
+
+       if(isnew)
+               chptr->channelts = newts;
+       
+       else if(newts == 0 || oldts == 0)
+               chptr->channelts = 0;
+       else if(newts == oldts)
+               ;
+       else if(newts < oldts)
+       {
+               /* If configured, kick people trying to join +i/+k
+                * channels by recreating them on split servers.
+                * Don't kick if the source has sent EOB (services
+                * deopping everyone by TS-1 SJOIN).
+                * -- jilles */
+               if (ConfigChannel.kick_on_split_riding &&
+                               !HasSentEob(source_p) &&
+                               ((mode.mode & MODE_INVITEONLY) ||
+                   (mode.key[0] != 0 && irccmp(mode.key, oldmode->key) != 0)))
+               {
+                       struct membership *msptr;
+                       struct Client *who;
+                       int l = dlink_list_length(&chptr->members);
+                       int b = dlink_list_length(&chptr->banlist) +
+                               dlink_list_length(&chptr->exceptlist) +
+                               dlink_list_length(&chptr->invexlist) +
+                               dlink_list_length(&chptr->quietlist);
+
+                       DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->locmembers.head)
+                       {
+                               msptr = ptr->data;
+                               who = msptr->client_p;
+                               sendto_one(who, ":%s KICK %s %s :Net Rider",
+                                                    me.name, chptr->chname, who->name);
+
+                               sendto_server(NULL, chptr, CAP_TS6, NOCAPS,
+                                             ":%s KICK %s %s :Net Rider",
+                                             me.id, chptr->chname,
+                                             who->id);
+                               sendto_server(NULL, chptr, NOCAPS, CAP_TS6,
+                                             ":%s KICK %s %s :Net Rider",
+                                             me.name, chptr->chname, who->name);
+                               remove_user_from_channel(msptr);
+                               if (--l == 0)
+                                       break;
+                       }
+                       if (l == 0)
+                       {
+                               /* Channel was emptied, create a new one */
+                               if((chptr = get_or_create_channel(source_p, parv[2], &isnew)) == NULL)
+                                       return 0;               /* oops! */
+
+                               /* If the source does not do TS6,
+                                * nontimestamped bans have been sent to it,
+                                * but we have just lost those here. Let's
+                                * warn the channel about this. Because
+                                * of the kicks, any users on the channel
+                                * will be at client_p. -- jilles */
+                               if (!has_id(source_p) && b > 0)
+                                       sendto_one(client_p, ":%s NOTICE %s :*** Notice -- possible ban desync on %s, please remove any bans just added by servers", get_id(&me, client_p), parv[2], parv[2]);
+                               oldmode = &chptr->mode;
+                       }
+               }
+               keep_our_modes = NO;
+               chptr->channelts = newts;
+       }
+       else
+               keep_new_modes = NO;
+
+       if(!keep_new_modes)
+               mode = *oldmode;
+       else if(keep_our_modes)
+       {
+               mode.mode |= oldmode->mode;
+               if(oldmode->limit > mode.limit)
+                       mode.limit = oldmode->limit;
+               if(strcmp(mode.key, oldmode->key) < 0)
+                       strcpy(mode.key, oldmode->key);
+               if(oldmode->join_num > mode.join_num ||
+                               (oldmode->join_num == mode.join_num &&
+                                oldmode->join_time > mode.join_time))
+               {
+                       mode.join_num = oldmode->join_num;
+                       mode.join_time = oldmode->join_time;
+               }
+               if(irccmp(mode.forward, oldmode->forward) < 0)
+                       strcpy(mode.forward, oldmode->forward);
+       }
+       else
+       {
+               /* If setting -j, clear join throttle state -- jilles */
+               if (!mode.join_num)
+                       chptr->join_count = chptr->join_delta = 0;
+       }
+
+       set_final_mode(&mode, oldmode);
+       chptr->mode = mode;
+
+       /* Lost the TS, other side wins, so remove modes on this side */
+       if(!keep_our_modes)
+       {
+               remove_our_modes(chptr, fakesource_p);
+               DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->invites.head)
+               {
+                       del_invite(chptr, ptr->data);
+               }
+               sendto_channel_local(ALL_MEMBERS, chptr,
+                                    ":%s NOTICE %s :*** Notice -- TS for %s changed from %ld to %ld",
+                                    me.name, chptr->chname, chptr->chname,
+                                    (long) oldts, (long) newts);
+       }
+
+       if(*modebuf != '\0')
+               sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s %s %s",
+                                    fakesource_p->name, chptr->chname, modebuf, parabuf);
+
+       *modebuf = *parabuf = '\0';
+
+       if(parv[3][0] != '0' && keep_new_modes)
+               modes = channel_modes(chptr, source_p);
+       else
+               modes = empty_modes;
+
+       mlen_nick = ircsprintf(buf_nick, ":%s SJOIN %ld %s %s :",
+                              source_p->name, (long) chptr->channelts, parv[2], modes);
+       ptr_nick = buf_nick + mlen_nick;
+
+       /* working on the presumption eventually itll be more efficient to
+        * build a TS6 buffer without checking its needed..
+        */
+       mlen_uid = ircsprintf(buf_uid, ":%s SJOIN %ld %s %s :",
+                             use_id(source_p), (long) chptr->channelts, parv[2], modes);
+       ptr_uid = buf_uid + mlen_uid;
+
+       mbuf = modebuf;
+       para[0] = para[1] = para[2] = para[3] = empty;
+       pargs = 0;
+       len_nick = len_uid = 0;
+
+       /* if theres a space, theres going to be more than one nick, change the
+        * first space to \0, so s is just the first nick, and point p to the
+        * second nick
+        */
+       if((p = strchr(s, ' ')) != NULL)
+       {
+               *p++ = '\0';
+       }
+
+       *mbuf++ = '+';
+
+       while (s)
+       {
+               fl = 0;
+
+               for (i = 0; i < 2; i++)
+               {
+                       if(*s == '@')
+                       {
+                               fl |= CHFL_CHANOP;
+                               s++;
+                       }
+                       else if(*s == '+')
+                       {
+                               fl |= CHFL_VOICE;
+                               s++;
+                       }
+               }
+
+               /* if the client doesnt exist or is fake direction, skip. */
+               if(!(target_p = find_client(s)) ||
+                  (target_p->from != client_p) || !IsPerson(target_p))
+                       goto nextnick;
+
+               /* we assume for these we can fit at least one nick/uid in.. */
+
+               /* check we can fit another status+nick+space into a buffer */
+               if((mlen_nick + len_nick + NICKLEN + 3) > (BUFSIZE - 3))
+               {
+                       *(ptr_nick - 1) = '\0';
+                       sendto_server(client_p->from, NULL, NOCAPS, CAP_TS6, "%s", buf_nick);
+                       ptr_nick = buf_nick + mlen_nick;
+                       len_nick = 0;
+               }
+
+               if((mlen_uid + len_uid + IDLEN + 3) > (BUFSIZE - 3))
+               {
+                       *(ptr_uid - 1) = '\0';
+                       sendto_server(client_p->from, NULL, CAP_TS6, NOCAPS, "%s", buf_uid);
+                       ptr_uid = buf_uid + mlen_uid;
+                       len_uid = 0;
+               }
+
+               if(keep_new_modes)
+               {
+                       if(fl & CHFL_CHANOP)
+                       {
+                               *ptr_nick++ = '@';
+                               *ptr_uid++ = '@';
+                               len_nick++;
+                               len_uid++;
+                       }
+                       if(fl & CHFL_VOICE)
+                       {
+                               *ptr_nick++ = '+';
+                               *ptr_uid++ = '+';
+                               len_nick++;
+                               len_uid++;
+                       }
+               }
+
+               /* copy the nick to the two buffers */
+               len = ircsprintf(ptr_nick, "%s ", target_p->name);
+               ptr_nick += len;
+               len_nick += len;
+               len = ircsprintf(ptr_uid, "%s ", use_id(target_p));
+               ptr_uid += len;
+               len_uid += len;
+
+               if(!keep_new_modes)
+               {
+                       if(fl & CHFL_CHANOP)
+                               fl = CHFL_DEOPPED;
+                       else
+                               fl = 0;
+               }
+
+               if(!IsMember(target_p, chptr))
+               {
+                       add_user_to_channel(chptr, target_p, fl);
+                       sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s",
+                                            target_p->name,
+                                            target_p->username, target_p->host, parv[2]);
+                       joins++;
+               }
+
+               if(fl & CHFL_CHANOP)
+               {
+                       *mbuf++ = 'o';
+                       para[pargs++] = target_p->name;
+
+                       /* a +ov user.. bleh */
+                       if(fl & CHFL_VOICE)
+                       {
+                               /* its possible the +o has filled up MAXMODEPARAMS, if so, start
+                                * a new buffer
+                                */
+                               if(pargs >= MAXMODEPARAMS)
+                               {
+                                       *mbuf = '\0';
+                                       sendto_channel_local(ALL_MEMBERS, chptr,
+                                                            ":%s MODE %s %s %s %s %s %s",
+                                                            fakesource_p->name, chptr->chname,
+                                                            modebuf,
+                                                            para[0], para[1], para[2], para[3]);
+                                       mbuf = modebuf;
+                                       *mbuf++ = '+';
+                                       para[0] = para[1] = para[2] = para[3] = NULL;
+                                       pargs = 0;
+                               }
+
+                               *mbuf++ = 'v';
+                               para[pargs++] = target_p->name;
+                       }
+               }
+               else if(fl & CHFL_VOICE)
+               {
+                       *mbuf++ = 'v';
+                       para[pargs++] = target_p->name;
+               }
+
+               if(pargs >= MAXMODEPARAMS)
+               {
+                       *mbuf = '\0';
+                       sendto_channel_local(ALL_MEMBERS, chptr,
+                                            ":%s MODE %s %s %s %s %s %s",
+                                            fakesource_p->name,
+                                            chptr->chname,
+                                            modebuf, para[0], para[1], para[2], para[3]);
+                       mbuf = modebuf;
+                       *mbuf++ = '+';
+                       para[0] = para[1] = para[2] = para[3] = NULL;
+                       pargs = 0;
+               }
+
+             nextnick:
+               /* p points to the next nick */
+               s = p;
+
+               /* if there was a trailing space and p was pointing to it, then we
+                * need to exit.. this has the side effect of breaking double spaces
+                * in an sjoin.. but that shouldnt happen anyway
+                */
+               if(s && (*s == '\0'))
+                       s = p = NULL;
+
+               /* if p was NULL due to no spaces, s wont exist due to the above, so
+                * we cant check it for spaces.. if there are no spaces, then when
+                * we next get here, s will be NULL
+                */
+               if(s && ((p = strchr(s, ' ')) != NULL))
+               {
+                       *p++ = '\0';
+               }
+       }
+
+       *mbuf = '\0';
+       if(pargs)
+       {
+               sendto_channel_local(ALL_MEMBERS, chptr,
+                                    ":%s MODE %s %s %s %s %s %s",
+                                    fakesource_p->name, chptr->chname, modebuf,
+                                    para[0], CheckEmpty(para[1]),
+                                    CheckEmpty(para[2]), CheckEmpty(para[3]));
+       }
+
+       if(!joins && !(chptr->mode.mode & MODE_PERMANENT))
+       {
+               if(isnew)
+                       destroy_channel(chptr);
+
+               return 0;
+       }
+
+       /* Keep the colon if we're sending an SJOIN without nicks -- jilles */
+       if (joins)
+       {
+               *(ptr_nick - 1) = '\0';
+               *(ptr_uid - 1) = '\0';
+       }
+
+       sendto_server(client_p->from, NULL, CAP_TS6, NOCAPS, "%s", buf_uid);
+       sendto_server(client_p->from, NULL, NOCAPS, CAP_TS6, "%s", buf_nick);
+
+       /* if the source does TS6 we have to remove our bans.  Its now safe
+        * to issue -b's to the non-ts6 servers, as the sjoin we've just
+        * sent will kill any ops they have.
+        */
+       if(!keep_our_modes && source_p->id[0] != '\0')
+       {
+               if(dlink_list_length(&chptr->banlist) > 0)
+                       remove_ban_list(chptr, fakesource_p, &chptr->banlist, 'b', NOCAPS, ALL_MEMBERS);
+
+               if(dlink_list_length(&chptr->exceptlist) > 0)
+                       remove_ban_list(chptr, fakesource_p, &chptr->exceptlist,
+                                       'e', CAP_EX, ONLY_CHANOPS);
+
+               if(dlink_list_length(&chptr->invexlist) > 0)
+                       remove_ban_list(chptr, fakesource_p, &chptr->invexlist,
+                                       'I', CAP_IE, ONLY_CHANOPS);
+
+               if(dlink_list_length(&chptr->quietlist) > 0)
+                       remove_ban_list(chptr, fakesource_p, &chptr->quietlist,
+                                       'q', NOCAPS, ALL_MEMBERS);
+
+               chptr->bants++;
+       }
+
+       return 0;
+}
+
+struct mode_letter
+{
+       int mode;
+       char letter;
+};
+
+static struct mode_letter flags[] = {
+       {MODE_NOPRIVMSGS, 'n'},
+       {MODE_TOPICLIMIT, 't'},
+       {MODE_SECRET, 's'},
+       {MODE_MODERATED, 'm'},
+       {MODE_INVITEONLY, 'i'},
+       {MODE_PRIVATE, 'p'},
+       {MODE_REGONLY, 'r'},
+       {MODE_EXLIMIT, 'L'},
+       {MODE_PERMANENT, 'P'},
+       {MODE_NOCOLOR, 'c'},
+       {MODE_FREEINVITE, 'g'},
+       {MODE_OPMODERATE, 'z'},
+       {MODE_FREETARGET, 'F'},
+       {MODE_DISFORWARD, 'Q'},
+       {0, 0}
+};
+
+static void
+set_final_mode(struct Mode *mode, struct Mode *oldmode)
+{
+       int dir = MODE_QUERY;
+       char *pbuf = parabuf;
+       int len;
+       int i;
+
+       /* ok, first get a list of modes we need to add */
+       for (i = 0; flags[i].letter; i++)
+       {
+               if((mode->mode & flags[i].mode) && !(oldmode->mode & flags[i].mode))
+               {
+                       if(dir != MODE_ADD)
+                       {
+                               *mbuf++ = '+';
+                               dir = MODE_ADD;
+                       }
+                       *mbuf++ = flags[i].letter;
+               }
+       }
+
+       /* now the ones we need to remove. */
+       for (i = 0; flags[i].letter; i++)
+       {
+               if((oldmode->mode & flags[i].mode) && !(mode->mode & flags[i].mode))
+               {
+                       if(dir != MODE_DEL)
+                       {
+                               *mbuf++ = '-';
+                               dir = MODE_DEL;
+                       }
+                       *mbuf++ = flags[i].letter;
+               }
+       }
+
+       if(oldmode->limit && !mode->limit)
+       {
+               if(dir != MODE_DEL)
+               {
+                       *mbuf++ = '-';
+                       dir = MODE_DEL;
+               }
+               *mbuf++ = 'l';
+       }
+       if(oldmode->key[0] && !mode->key[0])
+       {
+               if(dir != MODE_DEL)
+               {
+                       *mbuf++ = '-';
+                       dir = MODE_DEL;
+               }
+               *mbuf++ = 'k';
+               len = ircsprintf(pbuf, "%s ", oldmode->key);
+               pbuf += len;
+               pargs++;
+       }
+       if(oldmode->join_num && !mode->join_num)
+       {
+               if(dir != MODE_DEL)
+               {
+                       *mbuf++ = '-';
+                       dir = MODE_DEL;
+               }
+               *mbuf++ = 'j';
+       }
+       if(oldmode->forward[0] && !mode->forward[0])
+       {
+               if(dir != MODE_DEL)
+               {
+                       *mbuf++ = '-';
+                       dir = MODE_DEL;
+               }
+               *mbuf++ = 'f';
+       }
+       if(mode->limit && oldmode->limit != mode->limit)
+       {
+               if(dir != MODE_ADD)
+               {
+                       *mbuf++ = '+';
+                       dir = MODE_ADD;
+               }
+               *mbuf++ = 'l';
+               len = ircsprintf(pbuf, "%d ", mode->limit);
+               pbuf += len;
+               pargs++;
+       }
+       if(mode->key[0] && strcmp(oldmode->key, mode->key))
+       {
+               if(dir != MODE_ADD)
+               {
+                       *mbuf++ = '+';
+                       dir = MODE_ADD;
+               }
+               *mbuf++ = 'k';
+               len = ircsprintf(pbuf, "%s ", mode->key);
+               pbuf += len;
+               pargs++;
+       }
+       if(mode->join_num && (oldmode->join_num != mode->join_num || oldmode->join_time != mode->join_time))
+       {
+               if(dir != MODE_ADD)
+               {
+                       *mbuf++ = '+';
+                       dir = MODE_ADD;
+               }
+               *mbuf++ = 'j';
+               len = ircsprintf(pbuf, "%d:%d ", mode->join_num, mode->join_time);
+               pbuf += len;
+               pargs++;
+       }
+       if(mode->forward[0] && strcmp(oldmode->forward, mode->forward) && ConfigChannel.use_forward)
+       {
+               if(dir != MODE_ADD)
+               {
+                       *mbuf++ = '+';
+                       dir = MODE_ADD;
+               }
+               *mbuf++ = 'f';
+               len = ircsprintf(pbuf, "%s ", mode->forward);
+               pbuf += len;
+               pargs++;
+       }
+       *mbuf = '\0';
+}
+
+/*
+ * remove_our_modes
+ *
+ * inputs      -
+ * output      - 
+ * side effects        - 
+ */
+static void
+remove_our_modes(struct Channel *chptr, struct Client *source_p)
+{
+       struct membership *msptr;
+       dlink_node *ptr;
+       char lmodebuf[MODEBUFLEN];
+       char *lpara[MAXMODEPARAMS];
+       int count = 0;
+       int i;
+
+       mbuf = lmodebuf;
+       *mbuf++ = '-';
+
+       for (i = 0; i < MAXMODEPARAMS; i++)
+               lpara[i] = NULL;
+
+       DLINK_FOREACH(ptr, chptr->members.head)
+       {
+               msptr = ptr->data;
+
+               if(is_chanop(msptr))
+               {
+                       msptr->flags &= ~CHFL_CHANOP;
+                       lpara[count++] = msptr->client_p->name;
+                       *mbuf++ = 'o';
+
+                       /* +ov, might not fit so check. */
+                       if(is_voiced(msptr))
+                       {
+                               if(count >= MAXMODEPARAMS)
+                               {
+                                       *mbuf = '\0';
+                                       sendto_channel_local(ALL_MEMBERS, chptr,
+                                                            ":%s MODE %s %s %s %s %s %s",
+                                                            me.name, chptr->chname,
+                                                            lmodebuf, lpara[0], lpara[1],
+                                                            lpara[2], lpara[3]);
+
+                                       /* preserve the initial '-' */
+                                       mbuf = lmodebuf;
+                                       *mbuf++ = '-';
+                                       count = 0;
+
+                                       for (i = 0; i < MAXMODEPARAMS; i++)
+                                               lpara[i] = NULL;
+                               }
+
+                               msptr->flags &= ~CHFL_VOICE;
+                               lpara[count++] = msptr->client_p->name;
+                               *mbuf++ = 'v';
+                       }
+               }
+               else if(is_voiced(msptr))
+               {
+                       msptr->flags &= ~CHFL_VOICE;
+                       lpara[count++] = msptr->client_p->name;
+                       *mbuf++ = 'v';
+               }
+               else
+                       continue;
+
+               if(count >= MAXMODEPARAMS)
+               {
+                       *mbuf = '\0';
+                       sendto_channel_local(ALL_MEMBERS, chptr,
+                                            ":%s MODE %s %s %s %s %s %s",
+                                            me.name, chptr->chname, lmodebuf,
+                                            lpara[0], lpara[1], lpara[2], lpara[3]);
+                       mbuf = lmodebuf;
+                       *mbuf++ = '-';
+                       count = 0;
+
+                       for (i = 0; i < MAXMODEPARAMS; i++)
+                               lpara[i] = NULL;
+               }
+       }
+
+       if(count != 0)
+       {
+               *mbuf = '\0';
+               sendto_channel_local(ALL_MEMBERS, chptr,
+                                    ":%s MODE %s %s %s %s %s %s",
+                                    me.name, chptr->chname, lmodebuf,
+                                    EmptyString(lpara[0]) ? "" : lpara[0],
+                                    EmptyString(lpara[1]) ? "" : lpara[1],
+                                    EmptyString(lpara[2]) ? "" : lpara[2],
+                                    EmptyString(lpara[3]) ? "" : lpara[3]);
+
+       }
+}
+
+/* remove_ban_list()
+ *
+ * inputs      - channel, source, list to remove, char of mode, caps needed
+ * outputs     -
+ * side effects - given list is removed, with modes issued to local clients
+ *               and non-TS6 servers.
+ */
+static void
+remove_ban_list(struct Channel *chptr, struct Client *source_p,
+               dlink_list * list, char c, int cap, int mems)
+{
+       static char lmodebuf[BUFSIZE];
+       static char lparabuf[BUFSIZE];
+       struct Ban *banptr;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+       char *pbuf;
+       int count = 0;
+       int cur_len, mlen, plen;
+
+       pbuf = lparabuf;
+
+       cur_len = mlen = ircsprintf(lmodebuf, ":%s MODE %s -", source_p->name, chptr->chname);
+       mbuf = lmodebuf + mlen;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
+       {
+               banptr = ptr->data;
+
+               /* trailing space, and the mode letter itself */
+               plen = strlen(banptr->banstr) + 2;
+
+               if(count >= MAXMODEPARAMS || (cur_len + plen) > BUFSIZE - 4)
+               {
+                       /* remove trailing space */
+                       *mbuf = '\0';
+                       *(pbuf - 1) = '\0';
+
+                       sendto_channel_local(mems, chptr, "%s %s", lmodebuf, lparabuf);
+                       /* Tricky tricky. If we changed source_p to &me
+                        * in ms_sjoin(), this still won't send stuff
+                        * where it should not be sent, because the
+                        * real source_p does TS6 -- jilles */
+                       sendto_server(source_p, chptr, cap, CAP_TS6, "%s %s", lmodebuf, lparabuf);
+
+                       cur_len = mlen;
+                       mbuf = lmodebuf + mlen;
+                       pbuf = lparabuf;
+                       count = 0;
+               }
+
+               *mbuf++ = c;
+               cur_len += plen;
+               pbuf += ircsprintf(pbuf, "%s ", banptr->banstr);
+               count++;
+
+               free_ban(banptr);
+       }
+
+       *mbuf = '\0';
+       *(pbuf - 1) = '\0';
+       sendto_channel_local(mems, chptr, "%s %s", lmodebuf, lparabuf);
+       sendto_server(source_p, chptr, cap, CAP_TS6, "%s %s", lmodebuf, lparabuf);
+
+       list->head = list->tail = NULL;
+       list->length = 0;
+}
diff --git a/modules/core/m_squit.c b/modules/core/m_squit.c
new file mode 100644 (file)
index 0000000..cf7a761
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_squit.c: Makes a server quit.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_squit.c 698 2006-02-04 18:26:55Z jilles $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "common.h"            /* FALSE bleah */
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_conf.h"
+#include "s_log.h"
+#include "s_serv.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "hash.h"
+#include "s_newconf.h"
+
+static int ms_squit(struct Client *, struct Client *, int, const char **);
+static int mo_squit(struct Client *, struct Client *, int, const char **);
+
+struct Message squit_msgtab = {
+       "SQUIT", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, {ms_squit, 0}, {ms_squit, 0}, mg_ignore, {mo_squit, 2}}
+};
+
+mapi_clist_av1 squit_clist[] = { &squit_msgtab, NULL };
+
+DECLARE_MODULE_AV1(squit, NULL, NULL, squit_clist, NULL, NULL, "$Revision: 698 $");
+
+struct squit_parms
+{
+       const char *server_name;
+       struct Client *target_p;
+};
+
+static struct squit_parms *find_squit(struct Client *client_p,
+                                     struct Client *source_p, const char *server);
+
+
+/*
+ * mo_squit - SQUIT message handler
+ *      parv[0] = sender prefix
+ *      parv[1] = server name
+ *      parv[2] = comment
+ */
+static int
+mo_squit(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct squit_parms *found_squit;
+       const char *comment = (parc > 2 && parv[2]) ? parv[2] : client_p->name;
+
+       if((found_squit = find_squit(client_p, source_p, parv[1])))
+       {
+               if(MyConnect(found_squit->target_p))
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "Received SQUIT %s from %s (%s)",
+                                            found_squit->target_p->name,
+                                            get_client_name(source_p, HIDE_IP), comment);
+                       ilog(L_SERVER, "Received SQUIT %s from %s (%s)",
+                            found_squit->target_p->name, log_client_name(source_p, HIDE_IP),
+                            comment);
+               }
+               else if(!IsOperRemote(source_p))
+               {
+                       sendto_one(source_p, form_str(ERR_NOPRIVS),
+                                  me.name, source_p->name, "remote");
+                       return 0;
+               }
+
+               exit_client(client_p, found_squit->target_p, source_p, comment);
+               return 0;
+       }
+       else
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHSERVER, form_str(ERR_NOSUCHSERVER), parv[1]);
+       }
+
+       return 0;
+}
+
+/*
+ * ms_squit - SQUIT message handler
+ *      parv[0] = sender prefix
+ *      parv[1] = server name
+ *      parv[2] = comment
+ */
+static int
+ms_squit(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+       const char *comment = (parc > 2 && parv[2]) ? parv[2] : client_p->name;
+
+       if(parc < 2)
+               target_p = client_p;
+       else
+       {
+               if((target_p = find_server(NULL, parv[1])) == NULL)
+                       return 0;
+
+               if(IsMe(target_p))
+                       target_p = client_p;
+               if(!IsServer(target_p))
+                       return 0;
+       }
+
+       /* Server is closing its link */
+       if (target_p == client_p)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "Server %s closing link (%s)",
+                               target_p->name, comment);
+       }
+       /*
+        **  Notify all opers, if my local link is remotely squitted
+        */
+       else if(MyConnect(target_p))
+       {
+               sendto_wallops_flags(UMODE_WALLOP, &me,
+                                    "Remote SQUIT %s from %s (%s)",
+                                    target_p->name, source_p->name, comment);
+
+               sendto_server(NULL, NULL, CAP_TS6, NOCAPS,
+                             ":%s WALLOPS :Remote SQUIT %s from %s (%s)",
+                             me.id, target_p->name, source_p->name, comment);
+
+               sendto_server(NULL, NULL, NOCAPS, CAP_TS6,
+                             ":%s WALLOPS :Remote SQUIT %s from %s (%s)",
+                             me.name, target_p->name, source_p->name, comment);
+
+               ilog(L_SERVER, "SQUIT From %s : %s (%s)", parv[0], target_p->name, comment);
+
+       }
+       exit_client(client_p, target_p, source_p, comment);
+       return 0;
+}
+
+
+/*
+ * find_squit
+ * inputs      - local server connection
+ *             -
+ *             -
+ * output      - pointer to struct containing found squit or none if not found
+ * side effects        -
+ */
+static struct squit_parms *
+find_squit(struct Client *client_p, struct Client *source_p, const char *server)
+{
+       static struct squit_parms found_squit;
+       struct Client *target_p = NULL;
+       struct Client *p;
+       dlink_node *ptr;
+
+       /* must ALWAYS be reset */
+       found_squit.target_p = NULL;
+       found_squit.server_name = NULL;
+
+
+       /*
+        ** The following allows wild cards in SQUIT. Only useful
+        ** when the command is issued by an oper.
+        */
+
+       DLINK_FOREACH(ptr, global_serv_list.head)
+       {
+               p = ptr->data;
+               if(IsServer(p) || IsMe(p))
+               {
+                       if(match(server, p->name))
+                       {
+                               target_p = p;
+                               break;
+                       }
+               }
+       }
+
+       if(target_p == NULL)
+               return NULL;
+
+       found_squit.target_p = target_p;
+       found_squit.server_name = server;
+
+       if(IsMe(target_p))
+       {
+               if(IsClient(client_p))
+               {
+                       if(MyClient(client_p))
+                               sendto_one(source_p, ":%s NOTICE %s :You are trying to squit me.",
+                                          me.name, client_p->name);
+                       return NULL;
+               }
+               else
+               {
+                       found_squit.target_p = client_p;
+                       found_squit.server_name = client_p->name;
+               }
+       }
+
+       if(found_squit.target_p != NULL)
+               return &found_squit;
+       else
+               return (NULL);
+}
diff --git a/modules/m_accept.c b/modules/m_accept.c
new file mode 100644 (file)
index 0000000..2fbc716
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_accept.c: Allows a user to talk to a +g user.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_accept.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_conf.h"
+#include "s_serv.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "sprintf_irc.h"
+#include "modules.h"
+
+static int m_accept(struct Client *, struct Client *, int, const char **);
+static void build_nicklist(struct Client *, char *, char *, const char *);
+
+static void add_accept(struct Client *, struct Client *);
+static void list_accepts(struct Client *);
+
+struct Message accept_msgtab = {
+       "ACCEPT", 0, 0, 0, MFLG_SLOW | MFLG_UNREG,
+       {mg_unreg, {m_accept, 2}, mg_ignore, mg_ignore, mg_ignore, {m_accept, 2}}
+};
+
+mapi_clist_av1 accept_clist[] = {
+       &accept_msgtab, NULL
+};
+DECLARE_MODULE_AV1(accept, NULL, NULL, accept_clist, NULL, NULL, "$Revision: 254 $");
+
+/*
+ * m_accept - ACCEPT command handler
+ *      parv[0] = sender prefix
+ *      parv[1] = servername
+ */
+static int
+m_accept(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       char *nick;
+       char *p = NULL;
+       static char addbuf[BUFSIZE];
+       static char delbuf[BUFSIZE];
+       struct Client *target_p;
+       int accept_num;
+
+       if(*parv[1] == '*')
+       {
+               list_accepts(source_p);
+               return 0;
+       }
+
+       build_nicklist(source_p, addbuf, delbuf, parv[1]);
+
+       /* parse the delete list */
+       for (nick = strtoken(&p, delbuf, ","); nick != NULL; nick = strtoken(&p, NULL, ","))
+       {
+               /* shouldnt happen, but lets be paranoid */
+               if((target_p = find_named_person(nick)) == NULL)
+               {
+                       sendto_one_numeric(source_p, ERR_NOSUCHNICK,
+                                          form_str(ERR_NOSUCHNICK), nick);
+                       continue;
+               }
+
+               /* user isnt on clients accept list */
+               if(!accept_message(target_p, source_p))
+               {
+                       sendto_one(source_p, form_str(ERR_ACCEPTNOT),
+                                  me.name, source_p->name, target_p->name);
+                       continue;
+               }
+
+               dlinkFindDestroy(target_p, &source_p->localClient->allow_list);
+               dlinkFindDestroy(source_p, &target_p->on_allow_list);
+       }
+
+       /* get the number of accepts they have */
+       accept_num = dlink_list_length(&source_p->localClient->allow_list);
+
+       /* parse the add list */
+       for (nick = strtoken(&p, addbuf, ","); nick; nick = strtoken(&p, NULL, ","))
+       {
+               /* shouldnt happen, but lets be paranoid */
+               if((target_p = find_named_person(nick)) == NULL)
+               {
+                       sendto_one_numeric(source_p, ERR_NOSUCHNICK,
+                                          form_str(ERR_NOSUCHNICK), nick);
+                       continue;
+               }
+
+               /* user is already on clients accept list */
+               if(accept_message(target_p, source_p))
+               {
+                       sendto_one(source_p, form_str(ERR_ACCEPTEXIST),
+                                  me.name, source_p->name, target_p->name);
+                       continue;
+               }
+
+               if(accept_num >= ConfigFileEntry.max_accept)
+               {
+                       sendto_one(source_p, form_str(ERR_ACCEPTFULL), me.name, source_p->name);
+                       return 0;
+               }
+
+               /* why is this here? */
+               /* del_from accept(target_p, source_p); */
+               add_accept(source_p, target_p);
+               accept_num++;
+       }
+
+       return 0;
+}
+
+/*
+ * build_nicklist()
+ *
+ * input       - pointer to client
+ *             - pointer to addbuffer
+ *             - pointer to remove buffer
+ *             - pointer to list of nicks
+ * output      - 
+ * side effects - addbuf/delbuf are modified to give valid nicks
+ */
+static void
+build_nicklist(struct Client *source_p, char *addbuf, char *delbuf, const char *nicks)
+{
+       char *name;
+       char *p;
+       int lenadd;
+       int lendel;
+       int del;
+       struct Client *target_p;
+       char *n = LOCAL_COPY(nicks);
+
+       *addbuf = *delbuf = '\0';
+       del = lenadd = lendel = 0;
+
+       /* build list of clients to add into addbuf, clients to remove in delbuf */
+       for (name = strtoken(&p, n, ","); name; name = strtoken(&p, NULL, ","), del = 0)
+       {
+               if(*name == '-')
+               {
+                       del = 1;
+                       name++;
+               }
+
+               if((target_p = find_named_person(name)) == NULL)
+               {
+                       sendto_one_numeric(source_p, ERR_NOSUCHNICK, 
+                                          form_str(ERR_NOSUCHNICK), name);
+                       continue;
+               }
+
+               /* we're deleting a client */
+               if(del)
+               {
+                       if(*delbuf)
+                               (void) strcat(delbuf, ",");
+
+                       (void) strncat(delbuf, name, BUFSIZE - lendel - 1);
+                       lendel += strlen(name) + 1;
+               }
+               /* adding a client */
+               else
+               {
+                       if(*addbuf)
+                               (void) strcat(addbuf, ",");
+
+                       (void) strncat(addbuf, name, BUFSIZE - lenadd - 1);
+                       lenadd += strlen(name) + 1;
+               }
+       }
+}
+
+/*
+ * add_accept()
+ *
+ * input       - pointer to clients accept list to add to
+ *             - pointer to client to add
+ * output      - none
+ * side effects - target is added to clients list
+ */
+static void
+add_accept(struct Client *source_p, struct Client *target_p)
+{
+       dlinkAddAlloc(target_p, &source_p->localClient->allow_list);
+       dlinkAddAlloc(source_p, &target_p->on_allow_list);
+}
+
+
+/*
+ * list_accepts()
+ *
+ * input       - pointer to client
+ * output      - none
+ * side effects        - print accept list to client
+ */
+static void
+list_accepts(struct Client *source_p)
+{
+       dlink_node *ptr;
+       struct Client *target_p;
+       char nicks[BUFSIZE];
+       int len = 0;
+       int len2 = 0;
+       int count = 0;
+
+       *nicks = '\0';
+       len2 = strlen(source_p->name) + 10;
+
+       DLINK_FOREACH(ptr, source_p->localClient->allow_list.head)
+       {
+               target_p = ptr->data;
+
+               if(target_p)
+               {
+
+                       if((len + strlen(target_p->name) + len2 > BUFSIZE) || count > 14)
+                       {
+                               sendto_one(source_p, form_str(RPL_ACCEPTLIST),
+                                          me.name, source_p->name, nicks);
+
+                               len = count = 0;
+                               *nicks = '\0';
+                       }
+
+                       len += ircsnprintf(nicks + len, sizeof(nicks) - len, "%s ", target_p->name);
+                       count++;
+               }
+       }
+
+       if(*nicks)
+               sendto_one(source_p, form_str(RPL_ACCEPTLIST), 
+                          me.name, source_p->name, nicks);
+
+       sendto_one(source_p, form_str(RPL_ENDOFACCEPT), 
+                  me.name, source_p->name);
+
+}
diff --git a/modules/m_admin.c b/modules/m_admin.c
new file mode 100644 (file)
index 0000000..0a83485
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_admin.c: Sends administrative information to a user.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_admin.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_conf.h"
+#include "s_serv.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "hook.h"
+#include "modules.h"
+
+static int m_admin(struct Client *, struct Client *, int, const char **);
+static int mr_admin(struct Client *, struct Client *, int, const char **);
+static int ms_admin(struct Client *, struct Client *, int, const char **);
+static void do_admin(struct Client *source_p);
+
+static void admin_spy(struct Client *);
+
+struct Message admin_msgtab = {
+       "ADMIN", 0, 0, 0, MFLG_SLOW | MFLG_UNREG,
+       {{mr_admin, 0}, {m_admin, 0}, {ms_admin, 0}, mg_ignore, mg_ignore, {ms_admin, 0}}
+};
+
+int doing_admin_hook;
+
+mapi_clist_av1 admin_clist[] = { &admin_msgtab, NULL };
+mapi_hlist_av1 admin_hlist[] = { 
+       { "doing_admin",        &doing_admin_hook },
+       { NULL, NULL }
+};
+
+DECLARE_MODULE_AV1(admin, NULL, NULL, admin_clist, admin_hlist, NULL, "$Revision: 254 $");
+
+/*
+ * mr_admin - ADMIN command handler
+ *      parv[0] = sender prefix   
+ *      parv[1] = servername   
+ */
+static int
+mr_admin(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       static time_t last_used = 0L;
+
+       if((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
+       {
+               sendto_one(source_p, form_str(RPL_LOAD2HI), 
+                          me.name, 
+                          EmptyString(source_p->name) ? "*" : source_p->name, 
+                          "ADMIN");
+               return 0;
+       }
+       else
+               last_used = CurrentTime;
+
+       do_admin(source_p);
+
+       return 0;
+}
+
+/*
+ * m_admin - ADMIN command handler
+ *      parv[0] = sender prefix
+ *      parv[1] = servername
+ */
+static int
+m_admin(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       static time_t last_used = 0L;
+
+       if(parc > 1)
+       {
+               if((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
+               {
+                       sendto_one(source_p, form_str(RPL_LOAD2HI),
+                                  me.name, source_p->name, "ADMIN");
+                       return 0;
+               }
+               else
+                       last_used = CurrentTime;
+               
+               if(hunt_server(client_p, source_p, ":%s ADMIN :%s", 1, parc, parv) != HUNTED_ISME)
+                       return 0;
+       }
+
+       do_admin(source_p);
+
+       return 0;
+}
+
+
+/*
+ * ms_admin - ADMIN command handler, used for OPERS as well
+ *      parv[0] = sender prefix
+ *      parv[1] = servername
+ */
+static int
+ms_admin(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       if(hunt_server(client_p, source_p, ":%s ADMIN :%s", 1, parc, parv) != HUNTED_ISME)
+               return 0;
+
+       do_admin(source_p);
+
+       return 0;
+}
+
+
+/*
+ * do_admin
+ *
+ * inputs      - pointer to client to report to
+ * output      - none
+ * side effects        - admin info is sent to client given
+ */
+static void
+do_admin(struct Client *source_p)
+{
+       const char *myname;
+       const char *nick;
+
+       if(IsPerson(source_p))
+               admin_spy(source_p);
+
+       myname = get_id(&me, source_p);
+       nick = EmptyString(source_p->name) ? "*" : get_id(source_p, source_p);
+
+       sendto_one(source_p, form_str(RPL_ADMINME), myname, nick, me.name);
+       if(AdminInfo.name != NULL)
+               sendto_one(source_p, form_str(RPL_ADMINLOC1), myname, nick, AdminInfo.name);
+       if(AdminInfo.description != NULL)
+               sendto_one(source_p, form_str(RPL_ADMINLOC2), myname, nick, AdminInfo.description);
+       if(AdminInfo.email != NULL)
+               sendto_one(source_p, form_str(RPL_ADMINEMAIL), myname, nick, AdminInfo.email);
+}
+
+/* admin_spy()
+ *
+ * input       - pointer to client
+ * output      - none
+ * side effects - event doing_admin is called
+ */
+static void
+admin_spy(struct Client *source_p)
+{
+       hook_data hd;
+
+       hd.client = source_p;
+       hd.arg1 = hd.arg2 = NULL;
+
+       call_hook(doing_admin_hook, &hd);
+}
diff --git a/modules/m_away.c b/modules/m_away.c
new file mode 100644 (file)
index 0000000..39db10a
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_away.c: Sets/removes away status on a user.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_away.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_conf.h"
+#include "s_serv.h"
+#include "packet.h"
+
+
+static int m_away(struct Client *, struct Client *, int, const char **);
+
+struct Message away_msgtab = {
+       "AWAY", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_away, 0}, {m_away, 0}, mg_ignore, mg_ignore, {m_away, 0}}
+};
+
+mapi_clist_av1 away_clist[] = { &away_msgtab, NULL };
+DECLARE_MODULE_AV1(away, NULL, NULL, away_clist, NULL, NULL, "$Revision: 254 $");
+
+/***********************************************************************
+ * m_away() - Added 14 Dec 1988 by jto. 
+ *            Not currently really working, I don't like this
+ *            call at all...
+ *
+ *            ...trying to make it work. I don't like it either,
+ *            but perhaps it's worth the load it causes to net.
+ *            This requires flooding of the whole net like NICK,
+ *            USER, MODE, etc messages...  --msa
+ *             
+ *            The above comments have long since irrelvant, but
+ *            are kept for historical purposes now ;)
+ ***********************************************************************/
+
+/*
+** m_away
+**      parv[0] = sender prefix
+**      parv[1] = away message
+*/
+static int
+m_away(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       char *away;
+       char *awy2;
+
+       if(MyClient(source_p) && !IsFloodDone(source_p))
+               flood_endgrace(source_p);
+
+       if(!IsClient(source_p))
+               return 0;
+
+       away = source_p->user->away;
+
+       if(parc < 2 || EmptyString(parv[1]))
+       {
+               /* Marking as not away */
+               if(away)
+               {
+                       /* we now send this only if they were away before --is */
+                       sendto_server(client_p, NULL, CAP_TS6, NOCAPS,
+                                     ":%s AWAY", use_id(source_p));
+                       sendto_server(client_p, NULL, NOCAPS, CAP_TS6, 
+                                     ":%s AWAY", source_p->name);
+                       MyFree(away);
+                       source_p->user->away = NULL;
+               }
+               if(MyConnect(source_p))
+                       sendto_one(source_p, form_str(RPL_UNAWAY),
+                                  me.name, source_p->name);
+               return 0;
+       }
+
+       /* Marking as away */
+
+       if(MyConnect(source_p))
+       {
+               if(!IsOper(source_p) &&
+                  (CurrentTime - source_p->localClient->last_away) < ConfigFileEntry.pace_wait)
+               {
+                       sendto_one(source_p, form_str(RPL_LOAD2HI), 
+                                  me.name, source_p->name, "AWAY");
+                       return 0;
+               }
+
+               source_p->localClient->last_away = CurrentTime;
+       }
+
+       awy2 = LOCAL_COPY(parv[1]);
+       if(strlen(awy2) > AWAYLEN)
+               awy2[AWAYLEN] = '\0';
+
+       /* we now send this only if they weren't away already --is */
+       if(!away)
+       {
+               sendto_server(client_p, NULL, CAP_TS6, NOCAPS, 
+                             ":%s AWAY :%s", use_id(source_p), awy2);
+               sendto_server(client_p, NULL, NOCAPS, CAP_TS6,
+                             ":%s AWAY :%s", source_p->name, awy2);
+       }
+       else
+               MyFree(away);
+
+       DupString(away, awy2);
+
+       source_p->user->away = away;
+
+       if(MyConnect(source_p))
+               sendto_one(source_p, form_str(RPL_NOWAWAY), me.name, source_p->name);
+
+       return 0;
+}
diff --git a/modules/m_cap.c b/modules/m_cap.c
new file mode 100644 (file)
index 0000000..8704e44
--- /dev/null
@@ -0,0 +1,476 @@
+/* modules/m_cap.c
+ * 
+ *  Copyright (C) 2005 Lee Hardy <lee@leeh.co.uk>
+ *  Copyright (C) 2005 ircd-ratbox development team
+ *
+ * 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.The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: m_cap.c 676 2006-02-03 20:05:09Z gxti $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "class.h"
+#include "client.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_serv.h"
+#include "s_user.h"
+
+typedef int (*bqcmp)(const void *, const void *);
+
+static int m_cap(struct Client *, struct Client *, int, const char **);
+static int modinit(void);
+
+struct Message cap_msgtab = {
+       "CAP", 0, 0, 0, MFLG_SLOW,
+       {{m_cap, 2}, {m_cap, 2}, mg_ignore, mg_ignore, mg_ignore, {m_cap, 2}}
+};
+
+mapi_clist_av1 cap_clist[] = { &cap_msgtab, NULL };
+DECLARE_MODULE_AV1(cap, modinit, NULL, cap_clist, NULL, NULL, "$Revision: 676 $");
+
+#define _CLICAP(name, capserv, capclient, flags)       \
+       { (name), (capserv), (capclient), (flags), sizeof(name) - 1 }
+
+#define CLICAP_FLAGS_STICKY    0x001
+
+static struct clicap
+{
+       const char *name;
+       int cap_serv;           /* for altering s->c */
+       int cap_cli;            /* for altering c->s */
+       int flags;
+       int namelen;
+} clicap_list[] = {
+       _CLICAP("multi-prefix", CLICAP_MULTI_PREFIX, 0, 0),
+       _CLICAP("sasl", CLICAP_SASL, 0, 0)
+};
+
+#define CLICAP_LIST_LEN (sizeof(clicap_list) / sizeof(struct clicap))
+
+static int clicap_sort(struct clicap *, struct clicap *);
+
+static int
+modinit(void)
+{
+       qsort(clicap_list, CLICAP_LIST_LEN, sizeof(struct clicap),
+               (bqcmp) clicap_sort);
+       return 0;
+}
+
+static int
+clicap_sort(struct clicap *one, struct clicap *two)
+{
+       return irccmp(one->name, two->name);
+}
+
+static int
+clicap_compare(const char *name, struct clicap *cap)
+{
+       return irccmp(name, cap->name);
+}
+
+/* clicap_find()
+ *   Used iteratively over a buffer, extracts individual cap tokens.
+ *
+ * Inputs: buffer to start iterating over (NULL to iterate over existing buf)
+ *         int pointer to whether the cap token is negated
+ *         int pointer to whether we finish with success
+ * Ouputs: Cap entry if found, NULL otherwise.
+ */
+static struct clicap *
+clicap_find(const char *data, int *negate, int *finished)
+{
+       static char buf[BUFSIZE];
+       static char *p;
+       struct clicap *cap;
+       char *s;
+
+       *negate = 0;
+
+       if(data)
+       {
+               strlcpy(buf, data, sizeof(buf));
+               p = buf;
+       }
+
+       if(*finished)
+               return NULL;
+
+       /* skip any whitespace */
+       while(*p && IsSpace(*p))
+               p++;
+
+       if(EmptyString(p))
+       {
+               *finished = 1;
+               return NULL;
+       }
+
+       if(*p == '-')
+       {
+               *negate = 1;
+               p++;
+
+               /* someone sent a '-' without a parameter.. */
+               if(*p == '\0')
+                       return NULL;
+       }
+
+       if((s = strchr(p, ' ')))
+               *s++ = '\0';
+
+       if((cap = bsearch(p, clicap_list, CLICAP_LIST_LEN, 
+                               sizeof(struct clicap), (bqcmp) clicap_compare)))
+       {
+               if(s)
+                       p = s;
+               else
+                       *finished = 1;
+       }
+
+       return cap;
+}
+
+/* clicap_generate()
+ *   Generates a list of capabilities.
+ *
+ * Inputs: client to send to, subcmd to send,
+ *         flags to match against: 0 to do none, -1 if client has no flags,
+ *         int to whether we are doing CAP CLEAR
+ * Outputs: None
+ */
+static void
+clicap_generate(struct Client *source_p, const char *subcmd, int flags, int clear)
+{
+       char buf[BUFSIZE];
+       char capbuf[BUFSIZE];
+       char *p;
+       int buflen = 0;
+       int curlen, mlen;
+       int i;
+
+       mlen = ircsprintf(buf, ":%s CAP %s %s",
+                       me.name, 
+                       EmptyString(source_p->name) ? "*" : source_p->name, 
+                       subcmd);
+
+       p = capbuf;
+       buflen = mlen;
+
+       /* shortcut, nothing to do */
+       if(flags == -1)
+       {
+               sendto_one(source_p, "%s :", buf);
+               return;
+       }
+
+       for(i = 0; i < CLICAP_LIST_LEN; i++)
+       {
+               if(flags)
+               {
+                       if(!IsCapable(source_p, clicap_list[i].cap_serv))
+                               continue;
+                       /* they are capable of this, check sticky */
+                       else if(clear && clicap_list[i].flags & CLICAP_FLAGS_STICKY)
+                               continue;
+               }
+
+               /* \r\n\0, possible "-~=", space, " *" */
+               if(buflen + clicap_list[i].namelen >= BUFSIZE - 10)
+               {
+                       /* remove our trailing space -- if buflen == mlen
+                        * here, we didnt even succeed in adding one.
+                        */
+                       if(buflen != mlen)
+                               *(p - 1) = '\0';
+                       else
+                               *p = '\0';
+
+                       sendto_one(source_p, "%s * :%s", buf, capbuf);
+                       p = capbuf;
+                       buflen = mlen;
+               }
+
+               if(clear)
+               {
+                       *p++ = '-';
+                       buflen++;
+
+                       /* needs a client ack */
+                       if(clicap_list[i].cap_cli && 
+                          IsCapable(source_p, clicap_list[i].cap_cli))
+                       {
+                               *p++ = '~';
+                               buflen++;
+                       }
+               }
+               else
+               {
+                       if(clicap_list[i].flags & CLICAP_FLAGS_STICKY)
+                       {
+                               *p++ = '=';
+                               buflen++;
+                       }
+
+                       /* if we're doing an LS, then we only send this if
+                        * they havent ack'd
+                        */
+                       if(clicap_list[i].cap_cli &&
+                          (!flags || !IsCapable(source_p, clicap_list[i].cap_cli)))
+                       {
+                               *p++ = '~';
+                               buflen++;
+                       }
+               }
+
+               curlen = ircsprintf(p, "%s ", clicap_list[i].name);
+               p += curlen;
+               buflen += curlen;
+       }
+
+       /* remove trailing space */
+       if(buflen != mlen)
+               *(p - 1) = '\0';
+       else
+               *p = '\0';
+
+       sendto_one(source_p, "%s :%s", buf, capbuf);
+}
+
+static void
+cap_ack(struct Client *source_p, const char *arg)
+{
+       struct clicap *cap;
+       int capadd = 0, capdel = 0;
+       int finished = 0, negate;
+
+       if(EmptyString(arg))
+               return;
+
+       for(cap = clicap_find(arg, &negate, &finished); cap;
+           cap = clicap_find(NULL, &negate, &finished))
+       {
+               /* sent an ACK for something they havent REQd */
+               if(!IsCapable(source_p, cap->cap_serv))
+                       continue;
+
+               if(negate)
+               {
+                       /* dont let them ack something sticky off */
+                       if(cap->flags & CLICAP_FLAGS_STICKY)
+                               continue;
+
+                       capdel |= cap->cap_cli;
+               }
+               else
+                       capadd |= cap->cap_cli;
+       }
+
+       source_p->localClient->caps |= capadd;
+       source_p->localClient->caps &= ~capdel;
+}
+
+static void
+cap_clear(struct Client *source_p, const char *arg)
+{
+       clicap_generate(source_p, "ACK", 
+                       source_p->localClient->caps ? source_p->localClient->caps : -1, 1);
+
+       /* XXX - sticky capabs */
+#ifdef CLICAP_STICKY
+       source_p->localClient->caps = source_p->localClient->caps & CLICAP_STICKY;
+#else
+       source_p->localClient->caps = 0;
+#endif
+}
+
+static void
+cap_end(struct Client *source_p, const char *arg)
+{
+       if(IsRegistered(source_p))
+               return;
+
+       source_p->flags2 &= ~FLAGS2_CLICAP;
+
+       if(source_p->name[0] && source_p->user)
+       {
+               char buf[USERLEN+1];
+               strlcpy(buf, source_p->username, sizeof(buf));
+               register_local_user(source_p, source_p, buf);
+       }
+}
+
+static void
+cap_list(struct Client *source_p, const char *arg)
+{
+       /* list of what theyre currently using */
+       clicap_generate(source_p, "LIST",
+                       source_p->localClient->caps ? source_p->localClient->caps : -1, 0);
+}
+
+static void
+cap_ls(struct Client *source_p, const char *arg)
+{
+       if(!IsRegistered(source_p))
+               source_p->flags2 |= FLAGS2_CLICAP;
+
+       /* list of what we support */
+       clicap_generate(source_p, "LS", 0, 0);
+}
+
+static void
+cap_req(struct Client *source_p, const char *arg)
+{
+       char buf[BUFSIZE];
+       char pbuf[2][BUFSIZE];
+       struct clicap *cap;
+       int buflen, plen;
+       int i = 0;
+       int capadd = 0, capdel = 0;
+       int finished = 0, negate;
+
+       if(!IsRegistered(source_p))
+               source_p->flags2 |= FLAGS2_CLICAP;
+
+       if(EmptyString(arg))
+               return;
+
+       buflen = ircsnprintf(buf, sizeof(buf), ":%s CAP %s ACK",
+                       me.name, EmptyString(source_p->name) ? "*" : source_p->name);
+
+       pbuf[0][0] = '\0';
+       plen = 0;
+
+       for(cap = clicap_find(arg, &negate, &finished); cap;
+           cap = clicap_find(NULL, &negate, &finished))
+       {
+               /* filled the first array, but cant send it in case the
+                * request fails.  one REQ should never fill more than two
+                * buffers --fl
+                */
+               if(buflen + plen + cap->namelen + 6 >= BUFSIZE)
+               {
+                       pbuf[1][0] = '\0';
+                       plen = 0;
+                       i = 1;
+               }
+
+               if(negate)
+               {
+                       if(cap->flags & CLICAP_FLAGS_STICKY)
+                       {
+                               finished = 0;
+                               break;
+                       }
+
+                       strcat(pbuf[i], "-");
+                       plen++;
+
+                       capdel |= cap->cap_serv;
+               }
+               else
+               {
+                       if(cap->flags & CLICAP_FLAGS_STICKY)
+                       {
+                               strcat(pbuf[i], "=");
+                               plen++;
+                       }
+
+                       capadd |= cap->cap_serv;
+               }
+
+               if(cap->cap_cli)
+               {
+                       strcat(pbuf[i], "~");
+                       plen++;
+               }
+
+               strcat(pbuf[i], cap->name);
+               strcat(pbuf[i], " ");
+               plen += (cap->namelen + 1);
+       }
+
+       if(!finished)
+       {
+               sendto_one(source_p, ":%s CAP %s NAK :%s",
+                       me.name, EmptyString(source_p->name) ? "*" : source_p->name, arg);
+               return;
+       }
+
+       if(i)
+       {
+               sendto_one(source_p, "%s * :%s", buf, pbuf[0]);
+               sendto_one(source_p, "%s :%s", buf, pbuf[1]);
+       }
+       else
+               sendto_one(source_p, "%s :%s", buf, pbuf[0]);
+
+       source_p->localClient->caps |= capadd;
+       source_p->localClient->caps &= ~capdel;
+}
+
+static struct clicap_cmd
+{
+       const char *cmd;
+       void (*func)(struct Client *source_p, const char *arg);
+} clicap_cmdlist[] = {
+       /* This list *MUST* be in alphabetical order */
+       { "ACK",        cap_ack         },
+       { "CLEAR",      cap_clear       },
+       { "END",        cap_end         },
+       { "LIST",       cap_list        },
+       { "LS",         cap_ls          },
+       { "REQ",        cap_req         },
+};
+
+static int
+clicap_cmd_search(const char *command, struct clicap_cmd *entry)
+{
+       return irccmp(command, entry->cmd);
+}
+
+static int
+m_cap(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct clicap_cmd *cmd;
+
+       if(!(cmd = bsearch(parv[1], clicap_cmdlist,
+                               sizeof(clicap_cmdlist) / sizeof(struct clicap_cmd),
+                               sizeof(struct clicap_cmd), (bqcmp) clicap_cmd_search)))
+       {
+               sendto_one(source_p, form_str(ERR_INVALIDCAPCMD),
+                               me.name, source_p->name, parv[1]);
+               return 0;
+       }
+
+       (cmd->func)(source_p, parv[2]);
+       return 0;
+}
diff --git a/modules/m_capab.c b/modules/m_capab.c
new file mode 100644 (file)
index 0000000..e915f40
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_away.c: Negotiates capabilities with a remote server.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_capab.c 1295 2006-05-08 13:05:25Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "irc_string.h"
+#include "s_serv.h"
+#include "s_conf.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+
+static int mr_capab(struct Client *, struct Client *, int, const char **);
+static int me_gcap(struct Client *, struct Client *, int, const char **);
+
+struct Message capab_msgtab = {
+       "CAPAB", 0, 0, 0, MFLG_SLOW | MFLG_UNREG,
+       {{mr_capab, 0}, mg_ignore, mg_ignore, mg_ignore, mg_ignore, mg_ignore}
+};
+struct Message gcap_msgtab = {
+       "GCAP", 0, 0, 0, MFLG_SLOW,
+       {mg_ignore, mg_ignore, mg_ignore, mg_ignore, {me_gcap, 2}, mg_ignore}
+};
+
+mapi_clist_av1 capab_clist[] = { &capab_msgtab, &gcap_msgtab, NULL };
+DECLARE_MODULE_AV1(capab, NULL, NULL, capab_clist, NULL, NULL, "$Revision: 1295 $");
+
+/*
+ * mr_capab - CAPAB message handler
+ *      parv[0] = sender prefix
+ *      parv[1] = space-separated list of capabilities
+ *
+ */
+static int
+mr_capab(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Capability *cap;
+       int i;
+       char *p;
+       char *s;
+
+       /* ummm, this shouldn't happen. Could argue this should be logged etc. */
+       if(client_p->localClient == NULL)
+               return 0;
+
+       if(client_p->user)
+               return 0;
+
+       /* CAP_TS6 is set in PASS, so is valid.. */
+       if((client_p->localClient->caps & ~CAP_TS6) != 0)
+       {
+               exit_client(client_p, client_p, client_p, "CAPAB received twice");
+               return 0;
+       }
+       else
+               client_p->localClient->caps |= CAP_CAP;
+
+       MyFree(client_p->localClient->fullcaps);
+       DupString(client_p->localClient->fullcaps, parv[1]);
+
+       for (i = 1; i < parc; i++)
+       {
+               char *t = LOCAL_COPY(parv[i]);
+               for (s = strtoken(&p, t, " "); s; s = strtoken(&p, NULL, " "))
+               {
+                       for (cap = captab; cap->name; cap++)
+                       {
+                               if(!irccmp(cap->name, s))
+                               {
+                                       client_p->localClient->caps |= cap->cap;
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int
+me_gcap(struct Client *client_p, struct Client *source_p,
+               int parc, const char *parv[])
+{
+       struct Capability *cap;
+       char *t = LOCAL_COPY(parv[1]);
+       char *s;
+       char *p;
+
+       if(!IsServer(source_p))
+               return 0;
+
+       /* already had GCAPAB?! */
+       if(!EmptyString(source_p->serv->fullcaps))
+               return 0;
+
+       DupString(source_p->serv->fullcaps, parv[1]);
+
+       for (s = strtoken(&p, t, " "); s; s = strtoken(&p, NULL, " "))
+       {
+               for (cap = captab; cap->name; cap++)
+               {
+                       if(!irccmp(cap->name, s))
+                       {
+                               source_p->serv->caps |= cap->cap;
+                               break;
+                       }
+               }
+       }
+
+       return 0;
+}
diff --git a/modules/m_challenge.c b/modules/m_challenge.c
new file mode 100644 (file)
index 0000000..5fab030
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_challenge.c: Allows an IRC Operator to securely authenticate.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_challenge.c 1483 2006-05-27 18:58:12Z jilles $
+ */
+
+#include "stdinc.h"
+
+#ifdef HAVE_LIBCRYPTO
+#include <openssl/pem.h>
+#include <openssl/rand.h>
+#include <openssl/rsa.h>
+#include <openssl/md5.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#endif
+
+#include "memory.h"
+#include "client.h"
+#include "ircd.h"
+#include "modules.h"
+#include "numeric.h"
+#include "send.h"
+#include "s_conf.h"
+#include "msg.h"
+#include "parse.h"
+#include "irc_string.h"
+#include "s_log.h"
+#include "s_user.h"
+#include "cache.h"
+#include "s_newconf.h"
+
+#define CHALLENGE_WIDTH BUFSIZE - (NICKLEN + HOSTLEN + 12)
+#define CHALLENGE_EXPIRES      180     /* 180 seconds should be more than long enough */
+#define CHALLENGE_SECRET_LENGTH        128     /* how long our challenge secret should be */
+
+#ifndef HAVE_LIBCRYPTO
+/* Maybe this should be an error or something?-davidt */
+/* now it is   -larne  */
+static int     challenge_load(void)
+{
+#ifndef STATIC_MODULES
+       sendto_realops_snomask(SNO_GENERAL, L_ALL, 
+               "Challenge module not loaded because OpenSSL is not available.");
+       ilog(L_MAIN, "Challenge module not loaded because OpenSSL is not available.");
+       return -1;
+#else
+       return 0;
+#endif
+}
+
+DECLARE_MODULE_AV1(challenge, challenge_load, NULL, NULL, NULL, NULL, "$Revision: 1483 $");
+#else
+
+static int m_challenge(struct Client *, struct Client *, int, const char **);
+
+/* We have openssl support, so include /CHALLENGE */
+struct Message challenge_msgtab = {
+       "CHALLENGE", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_challenge, 2}, mg_ignore, mg_ignore, mg_ignore, {m_challenge, 2}}
+};
+
+mapi_clist_av1 challenge_clist[] = { &challenge_msgtab, NULL };
+DECLARE_MODULE_AV1(challenge, NULL, NULL, challenge_clist, NULL, NULL, "$Revision: 1483 $");
+
+static int generate_challenge(char **r_challenge, char **r_response, RSA * key);
+
+static void
+cleanup_challenge(struct Client *target_p)
+{
+       if(target_p->localClient == NULL)
+               return;
+       
+       MyFree(target_p->localClient->challenge);
+       MyFree(target_p->localClient->opername);
+       target_p->localClient->challenge = NULL;
+       target_p->localClient->opername = NULL;
+       target_p->localClient->chal_time = 0;
+}
+
+/*
+ * m_challenge - generate RSA challenge for wouldbe oper
+ * parv[0] = sender prefix
+ * parv[1] = operator to challenge for, or +response
+ *
+ */
+static int
+m_challenge(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct oper_conf *oper_p;
+       char *challenge = NULL; /* to placate gcc */
+       char chal_line[CHALLENGE_WIDTH]; 
+       unsigned char *b_response;
+       size_t cnt;
+       int len = 0;
+
+       /* if theyre an oper, reprint oper motd and ignore */
+       if(IsOper(source_p))
+       {
+               sendto_one(source_p, form_str(RPL_YOUREOPER), me.name, source_p->name);
+               send_oper_motd(source_p);
+               return 0;
+       }
+
+       if(*parv[1] == '+')
+       {
+               /* Ignore it if we aren't expecting this... -A1kmm */
+               if(!source_p->localClient->challenge)
+                       return 0;
+
+               if((CurrentTime - source_p->localClient->chal_time) > CHALLENGE_EXPIRES)
+               {
+                       sendto_one(source_p, form_str(ERR_PASSWDMISMATCH), me.name, source_p->name);
+                       ilog(L_FOPER, "EXPIRED CHALLENGE (%s) by (%s!%s@%s) (%s)",
+                            source_p->localClient->opername, source_p->name,
+                            source_p->username, source_p->host, source_p->sockhost);
+
+                       if(ConfigFileEntry.failed_oper_notice)
+                               sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
+                                                    "Expired CHALLENGE attempt by %s (%s@%s)",
+                                                    source_p->name, source_p->username,
+                                                    source_p->host);
+                       cleanup_challenge(source_p);
+                       return 0;                       
+               }
+
+               b_response = ircd_base64_decode((const unsigned char *)++parv[1], strlen(parv[1]), &len);
+
+               if(len != SHA_DIGEST_LENGTH ||
+                  memcmp(source_p->localClient->challenge, b_response, SHA_DIGEST_LENGTH))
+               {
+                       sendto_one(source_p, form_str(ERR_PASSWDMISMATCH), me.name, source_p->name);
+                       ilog(L_FOPER, "FAILED CHALLENGE (%s) by (%s!%s@%s) (%s)",
+                            source_p->localClient->opername, source_p->name,
+                            source_p->username, source_p->host, source_p->sockhost);
+
+                       if(ConfigFileEntry.failed_oper_notice)
+                               sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
+                                                    "Failed CHALLENGE attempt by %s (%s@%s)",
+                                                    source_p->name, source_p->username,
+                                                    source_p->host);
+
+                       MyFree(b_response);
+                       cleanup_challenge(source_p);
+                       return 0;
+               }
+
+               MyFree(b_response);
+
+               oper_p = find_oper_conf(source_p->username, source_p->orighost, 
+                                       source_p->sockhost, 
+                                       source_p->localClient->opername);
+
+               if(oper_p == NULL)
+               {
+                       sendto_one(source_p, form_str(ERR_NOOPERHOST), 
+                                  me.name, source_p->name);
+                       ilog(L_FOPER, "FAILED OPER (%s) by (%s!%s@%s) (%s)",
+                            source_p->localClient->opername, source_p->name,
+                            source_p->username, source_p->host,
+                            source_p->sockhost);
+
+                       if(ConfigFileEntry.failed_oper_notice)
+                               sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
+                                                    "Failed CHALLENGE attempt - host mismatch by %s (%s@%s)",
+                                                    source_p->name, source_p->username,
+                                                    source_p->host);
+                       return 0;
+               }
+
+               cleanup_challenge(source_p);
+
+               oper_up(source_p, oper_p);
+
+               ilog(L_OPERED, "OPER %s by %s!%s@%s (%s)",
+                    source_p->localClient->opername, source_p->name, 
+                    source_p->username, source_p->host, source_p->sockhost);
+               return 0;
+       }
+
+       cleanup_challenge(source_p);
+
+       oper_p = find_oper_conf(source_p->username, source_p->orighost, 
+                               source_p->sockhost, parv[1]);
+
+       if(oper_p == NULL)
+       {
+               sendto_one(source_p, form_str(ERR_NOOPERHOST), me.name, source_p->name);
+               ilog(L_FOPER, "FAILED OPER (%s) by (%s!%s@%s) (%s)",
+                    parv[1], source_p->name,
+                    source_p->username, source_p->host, source_p->sockhost);
+
+               if(ConfigFileEntry.failed_oper_notice)
+                       sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
+                                            "Failed CHALLENGE attempt - host mismatch by %s (%s@%s)",
+                                            source_p->name, source_p->username, source_p->host);
+               return 0;
+       }
+
+       if(!oper_p->rsa_pubkey)
+       {
+               sendto_one(source_p, ":%s NOTICE %s :I'm sorry, PK authentication "
+                          "is not enabled for your oper{} block.", me.name, parv[0]);
+               return 0;
+       }
+
+       if(!generate_challenge(&challenge, &(source_p->localClient->challenge), oper_p->rsa_pubkey))
+       {
+               char *chal = challenge;
+               source_p->localClient->chal_time = CurrentTime;
+               for(;;)
+               {
+                       cnt = strlcpy(chal_line, chal, CHALLENGE_WIDTH);
+                       sendto_one(source_p, form_str(RPL_RSACHALLENGE2), me.name, source_p->name, chal_line);
+                       if(cnt > CHALLENGE_WIDTH)
+                               chal += CHALLENGE_WIDTH - 1;
+                       else
+                               break;
+                       
+               }
+               sendto_one(source_p, form_str(RPL_ENDOFRSACHALLENGE2), 
+                          me.name, source_p->name);
+               MyFree(challenge);
+               DupString(source_p->localClient->opername, oper_p->name);
+       }
+       else
+               sendto_one_notice(source_p, ":Failed to generate challenge.");
+
+       return 0;
+}
+
+static int
+get_randomness(unsigned char *buf, int length)
+{
+       /* Seed OpenSSL PRNG with EGD enthropy pool -kre */
+       if(ConfigFileEntry.use_egd && (ConfigFileEntry.egdpool_path != NULL))
+       {
+               if(RAND_egd(ConfigFileEntry.egdpool_path) == -1)
+                       return -1;
+       }
+
+       if(RAND_status())
+       {
+               if(RAND_bytes(buf, length) > 0)
+                       return 1;
+       }
+       else {
+               if(RAND_pseudo_bytes(buf, length) >= 0)
+                       return 1;
+       }
+       return 0;
+}
+
+static int
+generate_challenge(char **r_challenge, char **r_response, RSA * rsa)
+{
+       SHA_CTX ctx;
+       unsigned char secret[CHALLENGE_SECRET_LENGTH], *tmp;
+       unsigned long length;
+       unsigned long e = 0;
+       unsigned long cnt = 0;
+       int ret;
+
+       if(!rsa)
+               return -1;
+       if(get_randomness(secret, CHALLENGE_SECRET_LENGTH))
+       {
+               SHA1_Init(&ctx);
+               SHA1_Update(&ctx, (u_int8_t *)secret, CHALLENGE_SECRET_LENGTH);
+               *r_response = MyMalloc(SHA_DIGEST_LENGTH);
+               SHA1_Final((u_int8_t *)*r_response, &ctx);
+
+               length = RSA_size(rsa);
+               tmp = MyMalloc(length);
+               ret = RSA_public_encrypt(CHALLENGE_SECRET_LENGTH, secret, tmp, rsa, RSA_PKCS1_OAEP_PADDING);
+
+               if (ret >= 0)
+               {
+                       *r_challenge = (char *)ircd_base64_encode(tmp, ret);
+                       MyFree(tmp);
+                       return 0;
+               }
+               MyFree(tmp);
+               MyFree(*r_response);
+               *r_response = NULL;
+       }
+
+       ERR_load_crypto_strings();
+       while ((cnt < 100) && (e = ERR_get_error()))
+       {
+               ilog(L_MAIN, "SSL error: %s", ERR_error_string(e, 0));
+               cnt++;
+       }
+
+       return (-1);
+}
+
+#endif /* HAVE_LIBCRYPTO */
diff --git a/modules/m_chghost.c b/modules/m_chghost.c
new file mode 100644 (file)
index 0000000..fcf87a8
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2005 William Pitcock <nenolod -at- nenolod.net>
+ * and Jilles Tjoelker <jilles -at- stack.nl>
+ * All rights reserved.
+ *
+ * Redistribution in both source and binary forms are permitted
+ * provided that the above copyright notice remains unchanged.
+ *
+ * m_chghost.c: A module for handling spoofing dynamically.
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "send.h"
+#include "channel.h"
+#include "client.h"
+#include "common.h"
+#include "config.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "memory.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "s_serv.h"
+#include "s_user.h"
+#include "hash.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "sprintf_irc.h"
+#include "whowas.h"
+#include "monitor.h"
+
+static int me_realhost(struct Client *, struct Client *, int, const char **);
+static int ms_chghost(struct Client *, struct Client *, int, const char **);
+static int me_chghost(struct Client *, struct Client *, int, const char **);
+static int mo_chghost(struct Client *, struct Client *, int, const char **);
+
+struct Message realhost_msgtab = {
+       "REALHOST", 0, 0, 0, MFLG_SLOW,
+       {mg_ignore, mg_ignore, mg_ignore, mg_ignore, {me_realhost, 2}, mg_ignore}
+};
+
+struct Message chghost_msgtab = {
+       "CHGHOST", 0, 0, 0, MFLG_SLOW,
+       {mg_ignore, mg_not_oper, {ms_chghost, 3}, {ms_chghost, 3}, {me_chghost, 3}, {mo_chghost, 3}}
+};
+
+mapi_clist_av1 chghost_clist[] = { &chghost_msgtab, &realhost_msgtab, NULL };
+
+DECLARE_MODULE_AV1(chghost, NULL, NULL, chghost_clist, NULL, NULL, "$Revision: 1865 $");
+
+/* clean_host()
+ *
+ * input       - host to check
+ * output      - 0 if erroneous, else 0
+ * side effects -
+ */
+static int
+clean_host(const char *host)
+{
+       int len = 0;
+
+       for(; *host; host++)
+       {
+               len++;
+
+               if(!IsHostChar(*host))
+                       return 0;
+       }
+
+       if(len > HOSTLEN)
+               return 0;
+
+       return 1;
+}
+
+/*
+ * me_realhost
+ * parv[0] = origin
+ * parv[1] = real host
+ *
+ * Yes this contains a little race condition if someone does a whois
+ * in between the UID and REALHOST and use_whois_actually is enabled.
+ * I don't think that's a big problem as the whole thing is a
+ * race condition.
+ */
+static int
+me_realhost(struct Client *client_p, struct Client *source_p,
+       int parc, const char *parv[])
+{
+       if (!IsPerson(source_p))
+               return 0;
+
+       del_from_hostname_hash(source_p->orighost, source_p);
+       strlcpy(source_p->orighost, parv[1], HOSTLEN);
+       if (irccmp(source_p->host, source_p->orighost))
+               SetDynSpoof(source_p);
+       else
+               ClearDynSpoof(source_p);
+       add_to_hostname_hash(source_p->orighost, source_p);
+       return 0;
+}
+
+static int
+do_chghost(struct Client *source_p, struct Client *target_p,
+               const char *newhost, int is_encap)
+{
+       if (!clean_host(newhost))
+       {
+               sendto_realops_snomask(SNO_GENERAL, is_encap ? L_ALL : L_NETWIDE, "%s attempted to change hostname for %s to %s (invalid)",
+                               IsServer(source_p) ? source_p->name : get_oper_name(source_p),
+                               target_p->name, newhost);
+               /* sending this remotely may disclose important
+                * routing information -- jilles */
+               if (is_encap ? MyClient(target_p) : !ConfigServerHide.flatten_links)
+                       sendto_one_notice(target_p, ":*** Notice -- %s attempted to change your hostname to %s (invalid)",
+                                       source_p->name, newhost);
+               return 0;
+       }
+       change_nick_user_host(target_p, target_p->name, target_p->username, newhost, 0, "Changing host");
+       if (irccmp(target_p->host, target_p->orighost))
+       {
+               SetDynSpoof(target_p);
+               if (MyClient(target_p))
+                       sendto_one_numeric(target_p, RPL_HOSTHIDDEN, "%s :is now your hidden host (set by %s)", target_p->host, source_p->name);
+       }
+       else
+       {
+               ClearDynSpoof(target_p);
+               if (MyClient(target_p))
+                       sendto_one_numeric(target_p, RPL_HOSTHIDDEN, "%s :hostname reset by %s", target_p->host, source_p->name);
+       }
+       if (MyClient(source_p))
+               sendto_one_notice(source_p, ":Changed hostname for %s to %s", target_p->name, target_p->host);
+       if (!IsServer(source_p) && !IsService(source_p))
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s changed hostname for %s to %s", get_oper_name(source_p), target_p->name, target_p->host);
+       return 1;
+}
+
+/*
+ * ms_chghost
+ * parv[0] = origin
+ * parv[1] = target
+ * parv[2] = host
+ */
+static int
+ms_chghost(struct Client *client_p, struct Client *source_p,
+       int parc, const char *parv[])
+{
+       struct Client *target_p;
+
+       if (!(target_p = find_person(parv[1])))
+               return -1;
+
+       if (do_chghost(source_p, target_p, parv[2], 0))
+       {
+               sendto_server(client_p, NULL,
+                       CAP_EUID | CAP_TS6, NOCAPS, ":%s CHGHOST %s %s",
+                       use_id(source_p), use_id(target_p), parv[2]);
+               sendto_server(client_p, NULL,
+                       CAP_TS6, CAP_EUID, ":%s ENCAP * CHGHOST %s :%s",
+                       use_id(source_p), use_id(target_p), parv[2]);
+               sendto_server(client_p, NULL,
+                       NOCAPS, CAP_TS6, ":%s ENCAP * CHGHOST %s :%s",
+                       source_p->name, target_p->name, parv[2]);
+       }
+
+       return 0;
+}
+
+/*
+ * me_chghost
+ * parv[0] = origin
+ * parv[1] = target
+ * parv[2] = host
+ */
+static int
+me_chghost(struct Client *client_p, struct Client *source_p,
+       int parc, const char *parv[])
+{
+       struct Client *target_p;
+
+       if (!(target_p = find_person(parv[1])))
+               return -1;
+
+       do_chghost(source_p, target_p, parv[2], 1);
+
+       return 0;
+}
+
+/*
+ * mo_chghost
+ * parv[0] = origin
+ * parv[1] = target
+ * parv[2] = host
+ */
+/* Disable this because of the abuse potential -- jilles
+ * No, make it toggleable via ./configure. --nenolod
+ */
+static int
+mo_chghost(struct Client *client_p, struct Client *source_p,
+       int parc, const char *parv[])
+{
+#ifdef ENABLE_OPER_CHGHOST
+       struct Client *target_p;
+
+       if(!IsOperAdmin(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS),
+                          me.name, source_p->name, "admin");
+               return 0;
+       }
+
+       if (!(target_p = find_named_person(parv[1])))
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHNICK,
+                               form_str(ERR_NOSUCHNICK), parv[1]);
+               return 0;
+       }
+
+       if (!clean_host(parv[2]))
+       {
+               sendto_one_notice(source_p, ":Hostname %s is invalid", parv[2]);
+               return 0;
+       }
+
+       do_chghost(source_p, target_p, parv[2], 0);
+
+       sendto_server(NULL, NULL,
+               CAP_EUID | CAP_TS6, NOCAPS, ":%s CHGHOST %s %s",
+               use_id(source_p), use_id(target_p), parv[2]);
+       sendto_server(NULL, NULL,
+               CAP_TS6, CAP_EUID, ":%s ENCAP * CHGHOST %s :%s",
+               use_id(source_p), use_id(target_p), parv[2]);
+       sendto_server(NULL, NULL,
+               NOCAPS, CAP_TS6, ":%s ENCAP * CHGHOST %s :%s",
+               source_p->name, target_p->name, parv[2]);
+#else
+       sendto_one_notice(source_p, ":CHGHOST is disabled");
+#endif
+
+       return 0;
+}
+
diff --git a/modules/m_close.c b/modules/m_close.c
new file mode 100644 (file)
index 0000000..e352bc5
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_close.c: Closes all unregistered connections.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_close.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "client.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "commio.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+
+static int mo_close(struct Client *, struct Client *, int, const char **);
+
+struct Message close_msgtab = {
+       "CLOSE", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_close, 0}}
+};
+
+mapi_clist_av1 close_clist[] = { &close_msgtab, NULL };
+DECLARE_MODULE_AV1(close, NULL, NULL, close_clist, NULL, NULL, "$Revision: 254 $");
+
+/*
+ * mo_close - CLOSE message handler
+ *  - added by Darren Reed Jul 13 1992.
+ */
+static int
+mo_close(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+       dlink_node *ptr;
+       dlink_node *ptr_next;
+       int closed = 0;
+
+       DLINK_FOREACH_SAFE(ptr, ptr_next, unknown_list.head)
+       {
+               target_p = ptr->data;
+
+               sendto_one(source_p, form_str(RPL_CLOSING), me.name, source_p->name,
+                          get_client_name(target_p, SHOW_IP), target_p->status);
+
+               (void) exit_client(target_p, target_p, target_p, "Oper Closing");
+               closed++;
+       }
+
+       sendto_one(source_p, form_str(RPL_CLOSEEND), me.name, source_p->name, closed);
+       return 0;
+}
diff --git a/modules/m_cmessage.c b/modules/m_cmessage.c
new file mode 100644 (file)
index 0000000..d1a069e
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ *  ircd-ratbox: an advanced Internet Relay Chat Daemon(ircd).
+ *  m_cmessage.c: Handles CPRIVMSG/CNOTICE, target change limitation free
+ *                PRIVMSG/NOTICE implementations.
+ *
+ *  Copyright (C) 2005 Lee Hardy <lee -at- leeh.co.uk>
+ *  Copyright (C) 2005 ircd-ratbox development team
+ *
+ *  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.The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ *  $Id: m_cmessage.c 1543 2006-06-01 18:18:28Z jilles $
+ */
+#include "stdinc.h"
+#include "client.h"
+#include "channel.h"
+#include "numeric.h"
+#include "msg.h"
+#include "modules.h"
+#include "hash.h"
+#include "send.h"
+#include "s_conf.h"
+#include "packet.h"
+
+static int m_cmessage(int, const char *, struct Client *, struct Client *, int, const char **);
+static int m_cprivmsg(struct Client *, struct Client *, int, const char **);
+static int m_cnotice(struct Client *, struct Client *, int, const char **);
+
+struct Message cprivmsg_msgtab = {
+       "CPRIVMSG", 0, 0, 0, MFLG_SLOW,
+       {mg_ignore, {m_cprivmsg, 4}, mg_ignore, mg_ignore, mg_ignore, {m_cprivmsg, 4}}
+};
+struct Message cnotice_msgtab = {
+       "CNOTICE", 0, 0, 0, MFLG_SLOW,
+       {mg_ignore, {m_cnotice, 4}, mg_ignore, mg_ignore, mg_ignore, {m_cnotice, 4}}
+};
+
+mapi_clist_av1 cmessage_clist[] = { &cprivmsg_msgtab, &cnotice_msgtab, NULL };
+DECLARE_MODULE_AV1(cmessage, NULL, NULL, cmessage_clist, NULL, NULL, "$Revision: 1543 $");
+
+#define PRIVMSG 0
+#define NOTICE 1
+
+static int
+m_cprivmsg(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       return m_cmessage(PRIVMSG, "PRIVMSG", client_p, source_p, parc, parv);
+}
+
+static int
+m_cnotice(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       return m_cmessage(NOTICE, "NOTICE", client_p, source_p, parc, parv);
+}
+
+static int
+m_cmessage(int p_or_n, const char *command,
+               struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+       struct Channel *chptr;
+       struct membership *msptr;
+
+       if(!IsFloodDone(source_p))
+               flood_endgrace(source_p);
+
+       if((target_p = find_named_person(parv[1])) == NULL)
+       {
+               if(p_or_n != NOTICE)
+                       sendto_one_numeric(source_p, ERR_NOSUCHNICK,
+                                       form_str(ERR_NOSUCHNICK), parv[1]);
+               return 0;
+       }
+
+       if((chptr = find_channel(parv[2])) == NULL)
+       {
+               if(p_or_n != NOTICE)
+                       sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
+                                       form_str(ERR_NOSUCHCHANNEL), parv[2]);
+               return 0;
+       }
+
+       if((msptr = find_channel_membership(chptr, source_p)) == NULL)
+       {
+               if(p_or_n != NOTICE)
+                       sendto_one_numeric(source_p, ERR_NOTONCHANNEL,
+                                       form_str(ERR_NOTONCHANNEL), 
+                                       chptr->chname);
+               return 0;
+       }
+
+       if(!is_chanop_voiced(msptr))
+       {
+               if(p_or_n != NOTICE)
+                       sendto_one(source_p, form_str(ERR_VOICENEEDED),
+                               me.name, source_p->name, chptr->chname);
+               return 0;
+       }
+
+       if(!IsMember(target_p, chptr))
+       {
+               if(p_or_n != NOTICE)
+                       sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,
+                                       form_str(ERR_USERNOTINCHANNEL),
+                                       target_p->name, chptr->chname);
+               return 0;
+       }
+
+       if(MyClient(target_p) && (IsSetCallerId(target_p) || (IsSetRegOnlyMsg(target_p) && !source_p->user->suser[0])) &&
+          !accept_message(source_p, target_p) && !IsOper(source_p))
+       {
+               if (IsSetRegOnlyMsg(target_p) && !source_p->user->suser[0])
+               {
+                       if (p_or_n != NOTICE)
+                               sendto_one_numeric(source_p, ERR_NONONREG,
+                                               form_str(ERR_NONONREG),
+                                               target_p->name);
+                       return 0;
+               }
+               if(p_or_n != NOTICE)
+                       sendto_one_numeric(source_p, ERR_TARGUMODEG,
+                                       form_str(ERR_TARGUMODEG), target_p->name);
+
+               if((target_p->localClient->last_caller_id_time +
+                   ConfigFileEntry.caller_id_wait) < CurrentTime)
+               {
+                       if(p_or_n != NOTICE)
+                               sendto_one_numeric(source_p, RPL_TARGNOTIFY,
+                                               form_str(RPL_TARGNOTIFY),
+                                               target_p->name);
+
+                       sendto_one(target_p, form_str(RPL_UMODEGMSG),
+                               me.name, target_p->name, source_p->name,
+                               source_p->username, source_p->host);
+
+                       target_p->localClient->last_caller_id_time = CurrentTime;
+               }
+
+               return 0;
+       }
+
+       if(p_or_n != NOTICE)
+               source_p->localClient->last = CurrentTime;
+
+       sendto_anywhere(target_p, source_p, command, ":%s", parv[3]);
+       return 0;
+}
diff --git a/modules/m_connect.c b/modules/m_connect.c
new file mode 100644 (file)
index 0000000..6615c5d
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_connect.c: Connects to a remote IRC server.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_connect.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "ircd.h"
+#include "irc_string.h"
+#include "numeric.h"
+#include "commio.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "s_log.h"
+#include "s_serv.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "hash.h"
+#include "modules.h"
+
+static int mo_connect(struct Client *, struct Client *, int, const char **);
+static int ms_connect(struct Client *, struct Client *, int, const char **);
+
+struct Message connect_msgtab = {
+       "CONNECT", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, {ms_connect, 4}, {ms_connect, 4}, mg_ignore, {mo_connect, 2}}
+};
+
+mapi_clist_av1 connect_clist[] = { &connect_msgtab, NULL };
+DECLARE_MODULE_AV1(connect, NULL, NULL, connect_clist, NULL, NULL, "$Revision: 254 $");
+
+/*
+ * mo_connect - CONNECT command handler
+ * 
+ * Added by Jto 11 Feb 1989
+ *
+ * m_connect
+ *      parv[0] = sender prefix
+ *      parv[1] = servername
+ *      parv[2] = port number
+ *      parv[3] = remote server
+ */
+static int
+mo_connect(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       int port;
+       int tmpport;
+       struct server_conf *server_p;
+       struct Client *target_p;
+
+       /* always privileged with handlers */
+
+       if(MyConnect(source_p) && !IsOperRemote(source_p) && parc > 3)
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS),
+                          me.name, source_p->name, "remote");
+               return 0;
+       }
+
+       if(hunt_server(client_p, source_p, ":%s CONNECT %s %s :%s", 3, parc, parv) != HUNTED_ISME)
+               return 0;
+
+       if((target_p = find_server(source_p, parv[1])))
+       {
+               sendto_one(source_p, ":%s NOTICE %s :Connect: Server %s already exists from %s.",
+                          me.name, parv[0], parv[1], target_p->from->name);
+               return 0;
+       }
+
+       /*
+        * try to find the name, then host, if both fail notify ops and bail
+        */
+       if((server_p = find_server_conf(parv[1])) == NULL)
+       {
+               sendto_one(source_p,
+                          "NOTICE %s :Connect: Host %s not listed in ircd.conf",
+                          parv[0], parv[1]);
+               return 0;
+       }
+
+       /*
+        * Get port number from user, if given. If not specified,
+        * use the default form configuration structure. If missing
+        * from there, then use the precompiled default.
+        */
+       tmpport = port = server_p->port;
+       if(parc > 2 && !EmptyString(parv[2]))
+       {
+               if((port = atoi(parv[2])) <= 0)
+               {
+                       sendto_one(source_p, "NOTICE %s :Connect: Illegal port number", parv[0]);
+                       return 0;
+               }
+       }
+       else if(port <= 0 && (port = PORTNUM) <= 0)
+       {
+               sendto_one(source_p, ":%s NOTICE %s :Connect: missing port number",
+                          me.name, parv[0]);
+               return 0;
+       }
+       /*
+        * Notify all operators about remote connect requests
+        */
+
+       ilog(L_SERVER, "CONNECT From %s : %s %s", parv[0], parv[1], parc > 2 ? parv[2] : "");
+
+       server_p->port = port;
+       /*
+        * at this point we should be calling connect_server with a valid
+        * C:line and a valid port in the C:line
+        */
+       if(serv_connect(server_p, source_p))
+       {
+#ifndef HIDE_SERVERS_IPS
+                       sendto_one(source_p, ":%s NOTICE %s :*** Connecting to %s[%s].%d",
+                                  me.name, parv[0], server_p->host, server_p->name, server_p->port);
+#else
+                       sendto_one(source_p, ":%s NOTICE %s :*** Connecting to %s.%d",
+                                  me.name, parv[0], server_p->name, server_p->port);
+#endif
+
+       }
+       else
+       {
+               sendto_one(source_p, ":%s NOTICE %s :*** Couldn't connect to %s.%d",
+                          me.name, parv[0], server_p->name, server_p->port);
+
+       }
+
+       /*
+        * client is either connecting with all the data it needs or has been
+        * destroyed
+        */
+       server_p->port = tmpport;
+       return 0;
+}
+
+/*
+ * ms_connect - CONNECT command handler
+ * 
+ * Added by Jto 11 Feb 1989
+ *
+ * m_connect
+ *      parv[0] = sender prefix
+ *      parv[1] = servername
+ *      parv[2] = port number
+ *      parv[3] = remote server
+ */
+static int
+ms_connect(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       int port;
+       int tmpport;
+       struct server_conf *server_p;
+       struct Client *target_p;
+
+       if(hunt_server(client_p, source_p, ":%s CONNECT %s %s :%s", 3, parc, parv) != HUNTED_ISME)
+               return 0;
+
+       if((target_p = find_server(NULL, parv[1])))
+       {
+               sendto_one_notice(source_p, ":Connect: Server %s already exists from %s.",
+                                 parv[1], target_p->from->name);
+               return 0;
+       }
+
+       /*
+        * try to find the name, then host, if both fail notify ops and bail
+        */
+       if((server_p = find_server_conf(parv[1])) == NULL)
+       {
+               sendto_one_notice(source_p, ":Connect: Host %s not listed in ircd.conf",
+                                 parv[1]);
+               return 0;
+       }
+
+       /*
+        * Get port number from user, if given. If not specified,
+        * use the default form configuration structure. If missing
+        * from there, then use the precompiled default.
+        */
+       tmpport = server_p->port;
+
+       port = atoi(parv[2]);
+
+       /* if someone sends port 0, and we have a config port.. use it */
+       if(port == 0 && server_p->port)
+               port = server_p->port;
+       else if(port <= 0)
+       {
+               sendto_one_notice(source_p, ":Connect: Illegal port number");
+               return 0;
+       }
+
+       /*
+        * Notify all operators about remote connect requests
+        */
+       sendto_wallops_flags(UMODE_WALLOP, &me,
+                            "Remote CONNECT %s %d from %s", 
+                            parv[1], port, source_p->name);
+       sendto_server(NULL, NULL, CAP_TS6, NOCAPS,
+                     ":%s WALLOPS :Remote CONNECT %s %d from %s",
+                     me.id, parv[1], port, source_p->name);
+       sendto_server(NULL, NULL, NOCAPS, CAP_TS6,
+                     ":%s WALLOPS :Remote CONNECT %s %d from %s",
+                     me.name, parv[1], port, source_p->name);
+
+       ilog(L_SERVER, "CONNECT From %s : %s %d", source_p->name, parv[1], port);
+
+       server_p->port = port;
+       /*
+        * at this point we should be calling connect_server with a valid
+        * C:line and a valid port in the C:line
+        */
+       if(serv_connect(server_p, source_p))
+               sendto_one_notice(source_p, ":*** Connecting to %s.%d",
+                                 server_p->name, server_p->port);
+       else
+               sendto_one_notice(source_p, ":*** Couldn't connect to %s.%d",
+                                 server_p->name, server_p->port);
+       /*
+        * client is either connecting with all the data it needs or has been
+        * destroyed
+        */
+       server_p->port = tmpport;
+       return 0;
+}
diff --git a/modules/m_dline.c b/modules/m_dline.c
new file mode 100644 (file)
index 0000000..e5bd03d
--- /dev/null
@@ -0,0 +1,473 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_dline.c: Bans/unbans a user.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_dline.c 3051 2006-12-27 00:02:32Z jilles $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "channel.h"
+#include "class.h"
+#include "client.h"
+#include "common.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "hostmask.h"
+#include "numeric.h"
+#include "commio.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "s_log.h"
+#include "send.h"
+#include "hash.h"
+#include "s_serv.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+
+static int mo_dline(struct Client *, struct Client *, int, const char **);
+static int mo_undline(struct Client *, struct Client *, int, const char **);
+
+struct Message dline_msgtab = {
+       "DLINE", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_dline, 2}}
+};
+struct Message undline_msgtab = {
+       "UNDLINE", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_undline, 2}}
+};
+
+mapi_clist_av1 dline_clist[] = { &dline_msgtab, &undline_msgtab, NULL };
+DECLARE_MODULE_AV1(dline, NULL, NULL, dline_clist, NULL, NULL, "$Revision: 3051 $");
+
+static int valid_comment(char *comment);
+static int flush_write(struct Client *, FILE *, char *, char *);
+static int remove_temp_dline(const char *);
+
+/* mo_dline()
+ * 
+ *   parv[1] - dline to add
+ *   parv[2] - reason
+ */
+static int
+mo_dline(struct Client *client_p, struct Client *source_p,
+        int parc, const char *parv[])
+{
+       char def[] = "No Reason";
+       const char *dlhost;
+       char *oper_reason;
+       char *reason = def;
+       struct irc_sockaddr_storage daddr;
+       char cidr_form_host[HOSTLEN + 1];
+       struct ConfItem *aconf;
+       int bits;
+       char dlbuffer[IRCD_BUFSIZE];
+       const char *current_date;
+       int tdline_time = 0;
+       int loc = 1;
+
+       if(!IsOperK(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS),
+                          me.name, source_p->name, "kline");
+               return 0;
+       }
+
+       if((tdline_time = valid_temp_time(parv[loc])) >= 0)
+               loc++;
+
+       if(parc < loc + 1)
+       {
+               sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+                          me.name, source_p->name, "DLINE");
+               return 0;
+       }
+
+       dlhost = parv[loc];
+       strlcpy(cidr_form_host, dlhost, sizeof(cidr_form_host));
+
+       if(!parse_netmask(dlhost, NULL, &bits))
+       {
+               sendto_one(source_p, ":%s NOTICE %s :Invalid D-Line",
+                          me.name, source_p->name);
+               return 0;
+       }
+
+       loc++;
+
+       if(parc >= loc + 1)     /* host :reason */
+       {
+               if(!EmptyString(parv[loc]))
+                       reason = LOCAL_COPY(parv[loc]);
+
+               if(!valid_comment(reason))
+               {
+                       sendto_one(source_p,
+                                  ":%s NOTICE %s :Invalid character '\"' in comment",
+                                  me.name, source_p->name);
+                       return 0;
+               }
+       }
+
+       if(IsOperAdmin(source_p))
+       {
+               if(bits < 8)
+               {
+                       sendto_one(source_p,
+                                  ":%s NOTICE %s :For safety, bitmasks less than 8 require conf access.",
+                                  me.name, parv[0]);
+                       return 0;
+               }
+       }
+       else
+       {
+               if(bits < 16)
+               {
+                       sendto_one(source_p,
+                                  ":%s NOTICE %s :Dline bitmasks less than 16 are for admins only.",
+                                  me.name, parv[0]);
+                       return 0;
+               }
+       }
+
+       if(ConfigFileEntry.non_redundant_klines)
+       {
+               const char *creason;
+               int t = AF_INET, ty, b;
+               ty = parse_netmask(dlhost, (struct sockaddr *)&daddr, &b);
+#ifdef IPV6
+               if(ty == HM_IPV6)
+                       t = AF_INET6;
+                else
+#endif
+                       t = AF_INET;
+                                               
+               if((aconf = find_dline((struct sockaddr *)&daddr, t)) != NULL)
+               {
+                       int bx;
+                       parse_netmask(aconf->host, NULL, &bx);
+                       if(b >= bx)
+                       {
+                               creason = aconf->passwd ? aconf->passwd : "<No Reason>";
+                               if(IsConfExemptKline(aconf))
+                                       sendto_one(source_p,
+                                                  ":%s NOTICE %s :[%s] is (E)d-lined by [%s] - %s",
+                                                  me.name, parv[0], dlhost, aconf->host, creason);
+                               else
+                                       sendto_one(source_p,
+                                                  ":%s NOTICE %s :[%s] already D-lined by [%s] - %s",
+                                                  me.name, parv[0], dlhost, aconf->host, creason);
+                               return 0;
+                       }
+               }
+       }
+
+       set_time();
+       current_date = smalldate();
+
+       aconf = make_conf();
+       aconf->status = CONF_DLINE;
+       DupString(aconf->host, dlhost);
+
+       /* Look for an oper reason */
+       if((oper_reason = strchr(reason, '|')) != NULL)
+       {
+               *oper_reason = '\0';
+               oper_reason++;
+
+               if(!EmptyString(oper_reason))
+                       DupString(aconf->spasswd, oper_reason);
+       }
+
+       if(tdline_time > 0)
+       {
+               ircsnprintf(dlbuffer, sizeof(dlbuffer), 
+                        "Temporary D-line %d min. - %s (%s)",
+                        (int) (tdline_time / 60), reason, current_date);
+               DupString(aconf->passwd, dlbuffer);
+               aconf->hold = CurrentTime + tdline_time;
+               add_temp_dline(aconf);
+
+               if(EmptyString(oper_reason))
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "%s added temporary %d min. D-Line for [%s] [%s]",
+                                            get_oper_name(source_p), tdline_time / 60,
+                                            aconf->host, reason);
+                       ilog(L_KLINE, "D %s %d %s %s",
+                               get_oper_name(source_p), tdline_time / 60,
+                               aconf->host, reason);
+               }
+               else
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "%s added temporary %d min. D-Line for [%s] [%s|%s]",
+                                            get_oper_name(source_p), tdline_time / 60,
+                                            aconf->host, reason, oper_reason);
+                       ilog(L_KLINE, "D %s %d %s %s|%s",
+                               get_oper_name(source_p), tdline_time / 60,
+                               aconf->host, reason, oper_reason);
+               }
+
+               sendto_one(source_p, ":%s NOTICE %s :Added temporary %d min. D-Line for [%s]",
+                          me.name, source_p->name, tdline_time / 60, aconf->host);
+       }
+       else
+       {
+               ircsnprintf(dlbuffer, sizeof(dlbuffer), "%s (%s)", reason, current_date);
+               DupString(aconf->passwd, dlbuffer);
+               add_conf_by_address(aconf->host, CONF_DLINE, NULL, aconf);
+               write_confitem(DLINE_TYPE, source_p, NULL, aconf->host, reason,
+                              oper_reason, current_date, 0);
+       }
+
+       check_dlines();
+       return 0;
+}
+
+/* mo_undline()
+ *
+ *      parv[1] = dline to remove
+ */
+static int
+mo_undline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       FILE *in;
+       FILE *out;
+       char buf[BUFSIZE], buff[BUFSIZE], temppath[BUFSIZE], *p;
+       const char *filename, *found_cidr;
+       const char *cidr;
+       int pairme = NO, error_on_write = NO;
+       mode_t oldumask;
+
+       ircsnprintf(temppath, sizeof(temppath), "%s.tmp", ConfigFileEntry.dlinefile);
+
+       if(!IsOperUnkline(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS),
+                          me.name, source_p->name, "unkline");
+               return 0;
+       }
+
+       cidr = parv[1];
+
+       if(parse_netmask(cidr, NULL, NULL) == HM_HOST)
+       {
+               sendto_one(source_p, ":%s NOTICE %s :Invalid D-Line",
+                          me.name, source_p->name);
+               return 0;
+       }
+
+       if(remove_temp_dline(cidr))
+       {
+               sendto_one(source_p,
+                          ":%s NOTICE %s :Un-dlined [%s] from temporary D-lines",
+                          me.name, parv[0], cidr);
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "%s has removed the temporary D-Line for: [%s]",
+                                    get_oper_name(source_p), cidr);
+               ilog(L_KLINE, "UD %s %s", get_oper_name(source_p), cidr);
+               return 0;
+       }
+
+       filename = get_conf_name(DLINE_TYPE);
+
+       if((in = fopen(filename, "r")) == 0)
+       {
+               sendto_one(source_p, ":%s NOTICE %s :Cannot open %s", me.name, parv[0], filename);
+               return 0;
+       }
+
+       oldumask = umask(0);
+       if((out = fopen(temppath, "w")) == 0)
+       {
+               sendto_one(source_p, ":%s NOTICE %s :Cannot open %s", me.name, parv[0], temppath);
+               fclose(in);
+               umask(oldumask);
+               return 0;
+       }
+
+       umask(oldumask);
+
+       while (fgets(buf, sizeof(buf), in))
+       {
+               strlcpy(buff, buf, sizeof(buff));
+
+               if((p = strchr(buff, '\n')) != NULL)
+                       *p = '\0';
+
+               if((*buff == '\0') || (*buff == '#'))
+               {
+                       if(!error_on_write)
+                               flush_write(source_p, out, buf, temppath);
+                       continue;
+               }
+
+               if((found_cidr = getfield(buff)) == NULL)
+               {
+                       if(!error_on_write)
+                               flush_write(source_p, out, buf, temppath);
+                       continue;
+               }
+
+               if(irccmp(found_cidr, cidr) == 0)
+               {
+                       pairme++;
+               }
+               else
+               {
+                       if(!error_on_write)
+                               flush_write(source_p, out, buf, temppath);
+                       continue;
+               }
+       }
+
+       fclose(in);
+       if (fclose(out))
+               error_on_write = YES;
+
+       if(error_on_write)
+       {
+               sendto_one(source_p,
+                          ":%s NOTICE %s :Couldn't write D-line file, aborted", 
+                          me.name, parv[0]);
+               return 0;
+       }
+       else if(!pairme)
+       {
+               sendto_one(source_p, ":%s NOTICE %s :No D-Line for %s",
+                          me.name, parv[0], cidr);
+
+               if(temppath != NULL)
+                       (void) unlink(temppath);
+
+               return 0;
+       }
+
+       if (rename(temppath, filename))
+       {
+               sendto_one_notice(source_p, ":Couldn't rename temp file, aborted");
+               return 0;
+       }
+       rehash_bans(0);
+
+
+       sendto_one(source_p, ":%s NOTICE %s :D-Line for [%s] is removed", me.name, parv[0], cidr);
+       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                            "%s has removed the D-Line for: [%s]", get_oper_name(source_p), cidr);
+       ilog(L_KLINE, "UD %s %s", get_oper_name(source_p), cidr);
+
+       return 0;
+}
+
+/*
+ * valid_comment
+ * inputs      - pointer to client
+ *              - pointer to comment
+ * output       - 0 if no valid comment, 1 if valid
+ * side effects - NONE
+ */
+static int
+valid_comment(char *comment)
+{
+       if(strchr(comment, '"'))
+               return 0;
+
+       if(strlen(comment) > REASONLEN)
+               comment[REASONLEN] = '\0';
+
+       return 1;
+}
+
+/*
+ * flush_write()
+ *
+ * inputs       - pointer to client structure of oper requesting unkline
+ *              - out is the file descriptor
+ *              - buf is the buffer to write
+ *              - ntowrite is the expected number of character to be written
+ *              - temppath is the temporary file name to be written
+ * output       - YES for error on write
+ *              - NO for success
+ * side effects - if successful, the buf is written to output file
+ *                if a write failure happesn, and the file pointed to
+ *                by temppath, if its non NULL, is removed.
+ *
+ * The idea here is, to be as robust as possible when writing to the 
+ * kline file.
+ *
+ * -Dianora
+ */
+static int
+flush_write(struct Client *source_p, FILE * out, char *buf, char *temppath)
+{
+       int error_on_write = (fputs(buf, out) < 0) ? YES : NO;
+
+       if(error_on_write)
+       {
+               sendto_one(source_p, ":%s NOTICE %s :Unable to write to %s",
+                          me.name, source_p->name, temppath);
+               fclose(out);
+               if(temppath != NULL)
+                       (void) unlink(temppath);
+       }
+       return (error_on_write);
+}
+
+/* remove_temp_dline()
+ *
+ * inputs       - hostname to undline
+ * outputs      -
+ * side effects - tries to undline anything that matches
+ */
+static int
+remove_temp_dline(const char *host)
+{
+       struct ConfItem *aconf;
+       dlink_node *ptr;
+       struct irc_sockaddr_storage addr, caddr;
+       int bits, cbits;
+       int i;
+
+       parse_netmask(host, (struct sockaddr *)&addr, &bits);
+
+       for (i = 0; i < LAST_TEMP_TYPE; i++)
+       {
+               DLINK_FOREACH(ptr, temp_dlines[i].head)
+               {
+                       aconf = ptr->data;
+
+                       parse_netmask(aconf->host, (struct sockaddr *)&caddr, &cbits);
+
+                       if(comp_with_mask_sock((struct sockaddr *)&addr, (struct sockaddr *)&caddr, bits) && bits == cbits)
+                       {
+                               dlinkDestroy(ptr, &temp_dlines[i]);
+                               delete_one_address_conf(aconf->host, aconf);
+                               return YES;
+                       }
+               }
+       }
+
+       return NO;
+}
diff --git a/modules/m_encap.c b/modules/m_encap.c
new file mode 100644 (file)
index 0000000..a467add
--- /dev/null
@@ -0,0 +1,112 @@
+/*  modules/m_encap.c
+ *  Copyright (C) 2003-2005 ircd-ratbox development team
+ *  Copyright (C) 2003 Lee Hardy <lee@leeh.co.uk>
+ *
+ * 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.The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: m_encap.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "send.h"
+#include "channel.h"
+#include "client.h"
+#include "common.h"
+#include "config.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "memory.h"
+#include "s_serv.h"
+#include "hash.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "sprintf_irc.h"
+
+static int ms_encap(struct Client *client_p, struct Client *source_p,
+                    int parc, const char *parv[]);
+
+struct Message encap_msgtab = {
+       "ENCAP", 0, 0, 0, MFLG_SLOW,
+       {mg_ignore, mg_ignore, {ms_encap, 3}, {ms_encap, 3}, mg_ignore, mg_ignore}
+};
+
+mapi_clist_av1 encap_clist[] = { &encap_msgtab, NULL };
+DECLARE_MODULE_AV1(encap, NULL, NULL, encap_clist, NULL, NULL, "$Revision: 254 $");
+
+/* ms_encap()
+ *
+ * parv[1] - destination server
+ * parv[2] - subcommand
+ * parv[3] - parameters
+ */
+static int
+ms_encap(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       char buffer[BUFSIZE];
+       char *ptr;
+       int cur_len = 0;
+       int len;
+       int i;
+
+       ptr = buffer;
+       
+       for(i = 1; i < parc - 1; i++)
+       {
+               len = strlen(parv[i]) + 1;
+
+               /* ugh, not even at the last parameter, just bail --fl */
+               if((size_t)(cur_len + len) >= sizeof(buffer))
+                       return 0;
+
+               ircsnprintf(ptr, sizeof(buffer) - cur_len, "%s ", parv[i]);
+               cur_len += len;
+               ptr += len;
+       }
+
+       len = strlen(parv[i]);
+
+       /* if its a command without parameters, dont prepend a ':' */
+       if(parc == 3)
+               ircsnprintf(ptr, sizeof(buffer) - cur_len, "%s", parv[2]);
+       else
+               ircsnprintf(ptr, sizeof(buffer) - cur_len, ":%s", parv[parc-1]);
+
+       /* add a trailing \0 if it was too long */
+       if((cur_len + len) >= BUFSIZE)
+               buffer[BUFSIZE-1] = '\0';
+
+       sendto_match_servs(source_p, parv[1], CAP_ENCAP, NOCAPS,
+                          "ENCAP %s", buffer);
+
+       /* if it matches us, find a matching handler and call it */
+       if(match(parv[1], me.name))
+               handle_encap(client_p, source_p, parv[2], parc - 2, parv + 2);
+
+       return 0;
+}
+
+
diff --git a/modules/m_etrace.c b/modules/m_etrace.c
new file mode 100644 (file)
index 0000000..30b5b98
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+ *  ircd-ratbox: an advanced Internet Relay Chat Daemon(ircd).
+ *  m_etrace.c: Gives local opers a trace output with added info.
+ *
+ *  Copyright (C) 2002-2003 Lee Hardy <lee@leeh.co.uk>
+ *  Copyright (C) 2002-2005 ircd-ratbox development team
+ *
+ *  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.The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ *  $Id: m_etrace.c 2775 2006-11-27 11:45:31Z jilles $
+ */
+
+#include "stdinc.h"
+#include "class.h"
+#include "hook.h"
+#include "client.h"
+#include "hash.h"
+#include "common.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "commio.h"
+#include "s_serv.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+
+static int mo_etrace(struct Client *, struct Client *, int, const char **);
+static int me_etrace(struct Client *, struct Client *, int, const char **);
+static int mo_chantrace(struct Client *, struct Client *, int, const char **);
+static int mo_masktrace(struct Client *, struct Client *, int, const char **);
+
+struct Message etrace_msgtab = {
+       "ETRACE", 0, 0, 0, MFLG_SLOW,
+       {mg_ignore, mg_not_oper, mg_ignore, mg_ignore, {me_etrace, 0}, {mo_etrace, 0}}
+};
+struct Message chantrace_msgtab = {
+       "CHANTRACE", 0, 0, 0, MFLG_SLOW,
+       {mg_ignore, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_chantrace, 2}}
+};
+struct Message masktrace_msgtab = {
+       "MASKTRACE", 0, 0, 0, MFLG_SLOW,
+       {mg_ignore, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_masktrace, 2}}
+};
+
+mapi_clist_av1 etrace_clist[] = { &etrace_msgtab, &chantrace_msgtab, &masktrace_msgtab, NULL };
+DECLARE_MODULE_AV1(etrace, NULL, NULL, etrace_clist, NULL, NULL, "$Revision: 2775 $");
+
+static void do_etrace(struct Client *source_p, int ipv4, int ipv6);
+static void do_etrace_full(struct Client *source_p);
+static void do_single_etrace(struct Client *source_p, struct Client *target_p);
+
+static const char *empty_sockhost = "255.255.255.255";
+static const char *spoofed_sockhost = "0";
+
+/*
+ * m_etrace
+ *      parv[0] = sender prefix
+ *      parv[1] = options [or target]
+ *     parv[2] = [target]
+ */
+static int
+mo_etrace(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       if(parc > 1 && !EmptyString(parv[1]))
+       {
+               if(!irccmp(parv[1], "-full"))
+                       do_etrace_full(source_p);
+#ifdef IPV6
+               else if(!irccmp(parv[1], "-v6"))
+                       do_etrace(source_p, 0, 1);
+               else if(!irccmp(parv[1], "-v4"))
+                       do_etrace(source_p, 1, 0);
+#endif
+               else
+               {
+                       struct Client *target_p = find_named_person(parv[1]);
+
+                       if(target_p)
+                       {
+                               if(!MyClient(target_p))
+                                       sendto_one(target_p, ":%s ENCAP %s ETRACE %s",
+                                               get_id(source_p, target_p),
+                                               target_p->user->server,
+                                               get_id(target_p, target_p));
+                               else
+                                       do_single_etrace(source_p, target_p);
+                       }
+                       else
+                               sendto_one_numeric(source_p, ERR_NOSUCHNICK,
+                                               form_str(ERR_NOSUCHNICK), parv[1]);
+               }
+       }
+       else
+               do_etrace(source_p, 1, 1);
+
+       return 0;
+}
+
+static int
+me_etrace(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+
+       if(!IsOper(source_p) || parc < 2 || EmptyString(parv[1]))
+               return 0;
+
+       /* we cant etrace remote clients.. we shouldnt even get sent them */
+       if((target_p = find_person(parv[1])) && MyClient(target_p))
+               do_single_etrace(source_p, target_p);
+
+        sendto_one_numeric(source_p, RPL_ENDOFTRACE, form_str(RPL_ENDOFTRACE), 
+                               target_p ? target_p->name : parv[1]);
+
+       return 0;
+}
+
+static void
+do_etrace(struct Client *source_p, int ipv4, int ipv6)
+{
+       struct Client *target_p;
+       dlink_node *ptr;
+
+       /* report all direct connections */
+       DLINK_FOREACH(ptr, lclient_list.head)
+       {
+               target_p = ptr->data;
+
+#ifdef IPV6
+               if((!ipv4 && target_p->localClient->ip.ss_family == AF_INET) ||
+                  (!ipv6 && target_p->localClient->ip.ss_family == AF_INET6))
+                       continue;
+#endif
+
+               sendto_one(source_p, form_str(RPL_ETRACE),
+                          me.name, source_p->name, 
+                          IsOper(target_p) ? "Oper" : "User", 
+                          get_client_class(target_p),
+                          target_p->name, target_p->username, target_p->host,
+                          show_ip(source_p, target_p) ? target_p->sockhost : "255.255.255.255",
+                          target_p->info);
+       }
+
+       sendto_one_numeric(source_p, RPL_ENDOFTRACE, form_str(RPL_ENDOFTRACE), me.name);
+}
+
+static void
+do_etrace_full(struct Client *source_p)
+{
+       dlink_node *ptr;
+
+       DLINK_FOREACH(ptr, lclient_list.head)
+       {
+               do_single_etrace(source_p, ptr->data);
+       }
+
+       sendto_one_numeric(source_p, RPL_ENDOFTRACE, form_str(RPL_ENDOFTRACE), me.name);
+}
+
+/*
+ * do_single_etrace  - searches local clients and displays those matching
+ *                     a pattern
+ * input             - source client, target client
+ * output           - etrace results
+ * side effects             - etrace results are displayed
+ */
+static void
+do_single_etrace(struct Client *source_p, struct Client *target_p)
+{
+       /* note, we hide fullcaps for spoofed users, as mirc can often
+        * advertise its internal ip address in the field --fl
+        */
+       if(!show_ip(source_p, target_p))
+               sendto_one(source_p, form_str(RPL_ETRACEFULL),
+                               me.name, source_p->name, 
+                               IsOper(target_p) ? "Oper" : "User",
+                               get_client_class(target_p),
+                               target_p->name, target_p->username, target_p->host, 
+                               "255.255.255.255", "<hidden> <hidden>", target_p->info);
+       else
+               sendto_one(source_p, form_str(RPL_ETRACEFULL),
+                               me.name, source_p->name, 
+                               IsOper(target_p) ? "Oper" : "User",
+                               get_client_class(target_p),
+                               target_p->name, target_p->username, 
+                               target_p->host, target_p->sockhost,
+                               target_p->localClient->fullcaps, target_p->info);
+}
+
+static int
+mo_chantrace(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+       struct Channel *chptr;
+       struct membership *msptr;
+       const char *sockhost;
+       const char *name;
+       dlink_node *ptr;
+       int operspy = 0;
+
+       name = parv[1];
+
+       if(IsOperSpy(source_p) && parv[1][0] == '!')
+       {
+               name++;
+               operspy = 1;
+
+               if(EmptyString(name))
+               {
+                       sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+                                       me.name, source_p->name, "CHANTRACE");
+                       return 0;
+               }
+       }
+
+       if((chptr = find_channel(name)) == NULL)
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL),
+                               name);
+               return 0;
+       }
+
+       /* dont report operspys for nonexistant channels. */
+       if(operspy)
+               report_operspy(source_p, "CHANTRACE", chptr->chname);
+
+       if(!operspy && !IsMember(client_p, chptr))
+       {
+               sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL),
+                               chptr->chname);
+               return 0;
+       }
+
+       DLINK_FOREACH(ptr, chptr->members.head)
+       {
+               msptr = ptr->data;
+               target_p = msptr->client_p;
+
+               if(EmptyString(target_p->sockhost))
+                       sockhost = empty_sockhost;
+               else if(!show_ip(source_p, target_p))
+                       sockhost = spoofed_sockhost;
+               else
+                       sockhost = target_p->sockhost;
+
+               sendto_one(source_p, form_str(RPL_ETRACE),
+                               me.name, source_p->name, 
+                               IsOper(target_p) ? "Oper" : "User",
+                               /* class field -- pretend its server.. */
+                               target_p->servptr->name,
+                               target_p->name, target_p->username, target_p->host,
+                               sockhost, target_p->info);
+       }
+
+       sendto_one_numeric(source_p, RPL_ENDOFTRACE, form_str(RPL_ENDOFTRACE), me.name);
+       return 0;
+}
+
+static void
+match_masktrace(struct Client *source_p, dlink_list *list,
+       const char *username, const char *hostname, const char *name,
+       const char *gecos)
+{
+       struct Client *target_p;
+       dlink_node *ptr;
+       const char *sockhost;   
+       char *mangle_gecos = NULL;
+       
+       if(gecos != NULL)
+       {
+               if(strstr(gecos, "\\s"))
+               {
+                       char *tmp = LOCAL_COPY(gecos);
+                       char *orig = tmp;
+                       char *new = tmp;
+                       while(*orig)
+                       {
+                               if(*orig == '\\' && *(orig + 1) != '\0')
+                                       {
+                                       if(*(orig + 1) == 's')
+                                       {
+                                               *new++ = ' ';
+                                               orig += 2;   
+                                       }
+                                       /* otherwise skip that and the escaped
+                                        * character after it, so we dont mistake
+                                        * \\s as \s --fl
+                                        */
+                                       else
+                                       {   
+                                               *new++ = *orig++;
+                                               *new++ = *orig++;
+                                       }
+                               }
+                               else
+                                       *new++ = *orig++;
+                       }
+       
+                       *new = '\0';
+                       mangle_gecos = LOCAL_COPY(tmp);
+               }
+               else
+                       mangle_gecos = LOCAL_COPY(gecos);
+       }
+
+       DLINK_FOREACH(ptr, list->head)
+       {
+               target_p = ptr->data;
+               if(!IsPerson(target_p))
+                       continue;
+               
+               if(EmptyString(target_p->sockhost))
+                       sockhost = empty_sockhost;
+               else if(!show_ip(source_p, target_p))
+                       sockhost = spoofed_sockhost;
+               else
+                       sockhost = target_p->sockhost;
+
+               if(match(username, target_p->username) &&
+                  (match(hostname, target_p->host) ||
+                   match(hostname, target_p->orighost) ||
+                   match(hostname, sockhost) || match_ips(hostname, sockhost)))
+               {
+                       if(name != NULL && !match(name, target_p->name))
+                               continue;
+
+                       if(mangle_gecos != NULL && !match_esc(mangle_gecos, target_p->info))
+                               continue;
+                       
+                       sendto_one(source_p, form_str(RPL_ETRACE),
+                               me.name, source_p->name, 
+                               IsOper(target_p) ? "Oper" : "User",
+                               /* class field -- pretend its server.. */
+                               target_p->servptr->name,
+                               target_p->name, target_p->username, target_p->host,
+                               sockhost, target_p->info);
+               }
+       }
+}
+
+static int
+mo_masktrace(struct Client *client_p, struct Client *source_p, int parc, 
+       const char *parv[])
+{
+       char *name, *username, *hostname, *gecos;
+       const char *mask;
+       int operspy = 0;
+
+       mask = parv[1]; 
+       name = LOCAL_COPY(parv[1]);     
+       collapse(name);
+
+       if(IsOperSpy(source_p) && parv[1][0] == '!')
+       {
+               name++;
+               mask++;
+               operspy = 1;
+       }               
+       
+       if(parc > 2 && !EmptyString(parv[2]))
+       {
+               gecos = LOCAL_COPY(parv[2]);
+               collapse_esc(gecos);
+       } else
+               gecos = NULL;
+       
+
+       if((hostname = strchr(name, '@')) == NULL)
+       {
+               sendto_one(source_p, ":%s NOTICE %s :Invalid parameters", me.name, source_p->name);
+               return 0;
+       }
+
+       *hostname++ = '\0';
+       
+       if((username = strchr(name, '!')) == NULL)
+       {
+               username = name;
+               name = NULL;
+       } else
+               *username++ = '\0';
+
+       if(EmptyString(username) || EmptyString(hostname))
+       {
+               sendto_one(source_p, ":%s NOTICE %s :Invalid parameters", me.name, source_p->name);
+               return 0;
+       }
+                       
+       if(operspy) {
+               if (!ConfigFileEntry.operspy_dont_care_user_info)
+               {
+                       char buf[512];
+                       strlcpy(buf, mask, sizeof(buf));
+                       if(!EmptyString(gecos)) {
+                               strlcat(buf, " ", sizeof(buf));
+                               strlcat(buf, gecos, sizeof(buf));
+                       }               
+
+                       report_operspy(source_p, "MASKTRACE", buf);     
+               }
+               match_masktrace(source_p, &global_client_list, username, hostname, name, gecos);                
+       } else
+               match_masktrace(source_p, &lclient_list, username, hostname, name, gecos);
+
+       sendto_one_numeric(source_p, RPL_ENDOFTRACE, form_str(RPL_ENDOFTRACE), me.name); 
+       return 0;
+}
diff --git a/modules/m_gline.c b/modules/m_gline.c
new file mode 100644 (file)
index 0000000..d644bca
--- /dev/null
@@ -0,0 +1,740 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_gline.c: Votes towards globally banning a mask.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_gline.c 1146 2006-04-07 22:52:35Z jilles $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "s_gline.h"
+#include "channel.h"
+#include "client.h"
+#include "common.h"
+#include "config.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "hostmask.h"
+#include "numeric.h"
+#include "commio.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "scache.h"
+#include "send.h"
+#include "msg.h"
+#include "s_serv.h"
+#include "hash.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_log.h"
+
+static int mo_gline(struct Client *, struct Client *, int, const char **);
+static int mc_gline(struct Client *, struct Client *, int, const char **);
+static int ms_gline(struct Client *, struct Client *, int, const char **);
+static int mo_ungline(struct Client *, struct Client *, int, const char **);
+
+struct Message gline_msgtab = {
+       "GLINE", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, {mc_gline, 3}, {ms_gline, 7}, mg_ignore, {mo_gline, 3}}
+};
+struct Message ungline_msgtab = {
+       "UNGLINE", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_ungline, 2}}
+};
+
+mapi_clist_av1 gline_clist[] = { &gline_msgtab, &ungline_msgtab, NULL };
+DECLARE_MODULE_AV1(gline, NULL, NULL, gline_clist, NULL, NULL, "$Revision: 1146 $");
+
+static int majority_gline(struct Client *source_p, const char *user,
+                         const char *host, const char *reason);
+static void set_local_gline(struct Client *source_p, const char *user,
+                           const char *host, const char *reason);
+
+static int check_wild_gline(const char *, const char *);
+static int invalid_gline(struct Client *, const char *, const char *, char *);
+
+static int remove_temp_gline(const char *, const char *);
+
+
+/* mo_gline()
+ *
+ * inputs       - The usual for a m_ function
+ * output       -
+ * side effects - place a gline if 3 opers agree
+ */
+static int
+mo_gline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       const char *user = NULL;
+       char *host = NULL;      /* user and host of GLINE "victim" */
+       char *reason = NULL;    /* reason for "victims" demise */
+       char splat[] = "*";
+       char *ptr;
+
+       if(!ConfigFileEntry.glines)
+       {
+               sendto_one(source_p, ":%s NOTICE %s :GLINE disabled, perhaps you want a clustered or remote KLINE?",
+                          me.name, source_p->name);
+               return 0;
+       }
+
+       if(!IsOperGline(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS),
+                          me.name, source_p->name, "gline");
+               return 0;
+       }
+
+       host = strchr(parv[1], '@');
+
+       /* specific user@host */
+       if(host != NULL)
+       {
+               user = parv[1];
+               *(host++) = '\0';
+
+               /* gline for "@host", use *@host */
+               if(*user == '\0')
+                       user = splat;
+       }
+       /* just a host? */
+       else
+       {
+               /* ok, its not a host.. abort */
+               if(strchr(parv[1], '.') == NULL)
+               {
+                       sendto_one(source_p,
+                                  ":%s NOTICE %s :Invalid parameters",
+                                  me.name, source_p->name);
+                       return 0;
+               }
+
+               user = splat;
+               host = LOCAL_COPY(parv[1]);
+       }
+
+       reason = LOCAL_COPY(parv[2]);
+
+       if(invalid_gline(source_p, user, host, reason))
+               return 0;
+
+       /* Not enough non-wild characters were found, assume they are trying to gline *@*. */
+       if(check_wild_gline(user, host))
+       {
+               if(MyClient(source_p))
+                       sendto_one(source_p,
+                                  ":%s NOTICE %s :Please include at least %d non-wildcard "
+                                  "characters with the user@host",
+                                  me.name, source_p->name, 
+                                  ConfigFileEntry.min_nonwildcard);
+               return 0;
+       }
+
+       if((ptr = strchr(host, '/')) != NULL)
+       {
+               int bitlen;
+               bitlen = strtol(++ptr, NULL, 10);
+
+               /* ipv4? */
+               if(strchr(host, ':') == NULL)
+               {
+                       if(bitlen < ConfigFileEntry.gline_min_cidr)
+                       {
+                               sendto_one(source_p, ":%s NOTICE %s :Cannot set G-Lines with cidr length < %d",
+                                          me.name, source_p->name,
+                                          ConfigFileEntry.gline_min_cidr);
+                               return 0;
+                       }
+               }
+               /* ipv6 */
+               else if(bitlen < ConfigFileEntry.gline_min_cidr6)
+               {
+                       sendto_one(source_p, ":%s NOTICE %s :Cannot set G-Lines with cidr length < %d",
+                                  me.name, source_p->name, 
+                                  ConfigFileEntry.gline_min_cidr6);
+                       return 0;
+               }
+       }
+
+       /* inform users about the gline before we call majority_gline()
+        * so already voted comes below gline request --fl
+        */
+       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                       "%s!%s@%s on %s is requesting gline for [%s@%s] [%s]",
+                       source_p->name, source_p->username,
+                       source_p->host, me.name, user, host, reason);
+       ilog(L_GLINE, "R %s %s %s %s %s %s %s",
+            source_p->name, source_p->username, source_p->host, 
+            source_p->user->server, user, host, reason);
+
+       /* If at least 3 opers agree this user should be G lined then do it */
+       majority_gline(source_p, user, host, reason);
+
+       /* 4 param version for hyb-7 servers */
+       sendto_server(NULL, NULL, CAP_GLN|CAP_TS6, NOCAPS,
+                       ":%s GLINE %s %s :%s", 
+                       use_id(source_p), user, host, reason);
+       sendto_server(NULL, NULL, CAP_GLN, CAP_TS6,
+                       ":%s GLINE %s %s :%s", 
+                       source_p->name, user, host, reason);
+
+       /* 8 param for hyb-6 */
+       sendto_server(NULL, NULL, NOCAPS, CAP_GLN,
+                       ":%s GLINE %s %s %s %s %s %s :%s",
+                       me.name, source_p->name, source_p->username,
+                       source_p->host, source_p->user->server, 
+                       user, host, reason);
+       return 0;
+}
+
+/* mc_gline()
+ */
+static int
+mc_gline(struct Client *client_p, struct Client *source_p,
+        int parc, const char *parv[])
+{
+       struct Client *acptr;
+       const char *user;
+       const char *host;
+       char *reason;
+       char *ptr;
+
+       /* hyb6 allows empty gline reasons */
+       if(parc < 4 || EmptyString(parv[3]))
+               return 0;
+
+       acptr = source_p;
+
+       user = parv[1];
+       host = parv[2];
+       reason = LOCAL_COPY(parv[3]);
+
+       if(invalid_gline(acptr, user, host, reason))
+               return 0;
+
+       sendto_server(client_p, NULL, CAP_GLN|CAP_TS6, NOCAPS,
+                     ":%s GLINE %s %s :%s",
+                     use_id(acptr), user, host, reason);
+       sendto_server(client_p, NULL, CAP_GLN, CAP_TS6,
+                     ":%s GLINE %s %s :%s",
+                     acptr->name, user, host, reason);
+       sendto_server(client_p, NULL, NOCAPS, CAP_GLN,
+                     ":%s GLINE %s %s %s %s %s %s :%s",
+                     acptr->user->server, acptr->name, 
+                     acptr->username, acptr->host,
+                     acptr->user->server, user, host, reason);
+
+       if(!ConfigFileEntry.glines)
+               return 0;
+
+       /* check theres enough non-wildcard chars */
+       if(check_wild_gline(user, host))
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                               "%s!%s@%s on %s is requesting a gline without "
+                               "%d non-wildcard characters for [%s@%s] [%s]",
+                               acptr->name, acptr->username, 
+                               acptr->host, acptr->user->server,
+                               ConfigFileEntry.min_nonwildcard,
+                               user, host, reason);
+               return 0;
+       }
+
+       if((ptr = strchr(host, '/')) != NULL)
+       {
+               int bitlen;
+               bitlen = strtol(++ptr, NULL, 10);
+
+               /* ipv4? */
+               if(strchr(host, ':') == NULL)
+               {
+                       if(bitlen < ConfigFileEntry.gline_min_cidr)
+                       {
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s!%s@%s on %s is requesting a "
+                                                    "gline with a cidr mask < %d for [%s@%s] [%s]",
+                                                    acptr->name, acptr->username, acptr->host,
+                                                    acptr->user->server,
+                                                    ConfigFileEntry.gline_min_cidr, 
+                                                    user, host, reason);
+                               return 0;
+                       }
+               }
+               /* ipv6 */
+               else if(bitlen < ConfigFileEntry.gline_min_cidr6)
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s!%s@%s on %s is requesting a "
+                                            "gline with a cidr mask < %d for [%s@%s] [%s]",
+                                            acptr->name, acptr->username, acptr->host,
+                                            acptr->user->server,
+                                            ConfigFileEntry.gline_min_cidr6,
+                                            user, host, reason);
+                       return 0;
+               }
+       }
+
+
+       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                       "%s!%s@%s on %s is requesting gline for [%s@%s] [%s]",
+                       acptr->name, acptr->username, acptr->host,
+                       acptr->user->server, user, host, reason);
+
+       ilog(L_GLINE, "R %s %s %s %s %s %s %s",
+            source_p->name, source_p->username, source_p->host, 
+            source_p->user->server, user, host, reason);
+
+       /* If at least 3 opers agree this user should be G lined then do it */
+       majority_gline(acptr, user, host, reason);
+
+       return 0;
+}
+
+
+/* ms_gline()
+ *
+ * inputs       - The usual for a m_ function
+ * output       -
+ * side effects - attempts to place a gline, if 3 opers agree
+ */
+static int
+ms_gline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *acptr;
+       const char *user;
+       const char *host;
+       char *reason;
+
+       /* hyb6 allows empty gline reasons */
+       if(parc < 8 || EmptyString(parv[7]))
+               return 0;
+
+       /* client doesnt exist.. someones messing */
+       if((acptr = find_client(parv[1])) == NULL)
+               return 0;
+
+       /* client that sent the gline, isnt on the server that sent
+        * the gline out.  somethings fucked.
+        */
+       if(acptr->servptr != source_p)
+               return 0;
+
+       user = parv[5];
+       host = parv[6];
+       reason = LOCAL_COPY(parv[7]);
+
+       if(invalid_gline(acptr, user, host, reason))
+               return 0;
+
+       sendto_server(client_p, NULL, CAP_GLN|CAP_TS6, NOCAPS,
+                     ":%s GLINE %s %s :%s",
+                     use_id(acptr), user, host, reason);
+       sendto_server(client_p, NULL, CAP_GLN, CAP_TS6,
+                     ":%s GLINE %s %s :%s",
+                     acptr->name, user, host, reason);
+       sendto_server(client_p, NULL, NOCAPS, CAP_GLN,
+                     ":%s GLINE %s %s %s %s %s %s :%s",
+                     acptr->user->server, acptr->name, 
+                     acptr->username, acptr->host,
+                     acptr->user->server, user, host, reason);
+
+       if(!ConfigFileEntry.glines)
+               return 0;
+
+       /* check theres enough non-wildcard chars */
+       if(check_wild_gline(user, host))
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                               "%s!%s@%s on %s is requesting a gline without "
+                               "%d non-wildcard characters for [%s@%s] [%s]",
+                               acptr->name, acptr->username, 
+                               acptr->host, acptr->user->server,
+                               ConfigFileEntry.min_nonwildcard,
+                               user, host, reason);
+               return 0;
+       }
+
+       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                       "%s!%s@%s on %s is requesting gline for [%s@%s] [%s]",
+                       acptr->name, acptr->username, acptr->host,
+                       acptr->user->server, user, host, reason);
+
+       ilog(L_GLINE, "R %s %s %s %s %s %s %s",
+            acptr->name, acptr->username, acptr->host, 
+            acptr->user->server, user, host, reason);
+
+       /* If at least 3 opers agree this user should be G lined then do it */
+       majority_gline(acptr, user, host, reason);
+
+       return 0;
+}
+
+/* mo_ungline()
+ *
+ *      parv[0] = sender nick
+ *      parv[1] = gline to remove
+ */
+static int
+mo_ungline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       const char *user;
+       char *h = LOCAL_COPY(parv[1]);
+       char *host;
+       char splat[] = "*";
+
+       if(!ConfigFileEntry.glines)
+       {
+               sendto_one(source_p, ":%s NOTICE %s :UNGLINE disabled, perhaps you want UNKLINE?", me.name, parv[0]);
+               return 0;
+       }
+
+       if(!IsOperUnkline(source_p) || !IsOperGline(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS),
+                          me.name, source_p->name, "unkline");
+               return 0;
+       }
+
+       if((host = strchr(h, '@')) || *h == '*')
+       {
+               /* Explicit user@host mask given */
+
+               if(host)
+               {
+                       *host++ = '\0';
+       
+                       /* check for @host */
+                       if(*h)
+                               user = h;
+                       else
+                               user = splat;
+
+                       if(!*host)
+                               host = splat;
+               }
+               else
+               {
+                       user = splat;
+                       host = h;
+               }
+       }
+       else
+       {
+               sendto_one(source_p, ":%s NOTICE %s :Invalid parameters", me.name, parv[0]);
+               return 0;
+       }
+
+       if(remove_temp_gline(user, host))
+       {
+               sendto_one(source_p, ":%s NOTICE %s :Un-glined [%s@%s]",
+                          me.name, parv[0], user, host);
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "%s has removed the G-Line for: [%s@%s]",
+                                    get_oper_name(source_p), user, host);
+               ilog(L_GLINE, "U %s %s %s %s %s %s",
+                    source_p->name, source_p->username, source_p->host, 
+                    source_p->user->server, user, host);
+       }
+       else
+       {
+               sendto_one(source_p, ":%s NOTICE %s :No G-Line for %s@%s",
+                          me.name, parv[0], user, host);
+       }
+
+       return 0;
+}
+
+/*
+ * check_wild_gline
+ *
+ * inputs       - user, host of gline
+ * output       - 1 if not enough non-wildchar char's, 0 if ok
+ * side effects - NONE
+ */
+static int
+check_wild_gline(const char *user, const char *host)
+{
+       const char *p;
+       char tmpch;
+       int nonwild;
+
+       nonwild = 0;
+       p = user;
+
+       while ((tmpch = *p++))
+       {
+               if(!IsKWildChar(tmpch))
+               {
+                       /* enough of them, break */
+                       if(++nonwild >= ConfigFileEntry.min_nonwildcard)
+                               break;
+               }
+       }
+
+       if(nonwild < ConfigFileEntry.min_nonwildcard)
+       {
+               /* user doesnt, try host */
+               p = host;
+               while ((tmpch = *p++))
+               {
+                       if(!IsKWildChar(tmpch))
+                               if(++nonwild >= ConfigFileEntry.min_nonwildcard)
+                                       break;
+               }
+       }
+
+       if(nonwild < ConfigFileEntry.min_nonwildcard)
+               return 1;
+       else
+               return 0;
+}
+
+/* invalid_gline
+ *
+ * inputs      - pointer to source client, ident, host and reason
+ * outputs     - 1 if invalid, 0 if valid
+ * side effects -
+ */
+static int
+invalid_gline(struct Client *source_p, const char *luser,
+             const char *lhost, char *lreason)
+{
+       if(strchr(luser, '!'))
+       {
+               sendto_one(source_p, ":%s NOTICE %s :Invalid character '!' in gline",
+                          me.name, source_p->name);
+               return 1;
+       }
+
+       if(strlen(lreason) > REASONLEN)
+               lreason[REASONLEN] = '\0';
+
+       return 0;
+}
+
+/*
+ * set_local_gline
+ *
+ * inputs      - pointer to oper nick/username/host/server,
+ *               victim user/host and reason
+ * output      - NONE
+ * side effects        -
+ */
+static void
+set_local_gline(struct Client *source_p, const char *user,
+               const char *host, const char *reason)
+{
+       char buffer[IRCD_BUFSIZE];
+       struct ConfItem *aconf;
+       const char *current_date;
+       char *my_reason;
+       char *oper_reason;
+
+       current_date = smalldate();
+
+       my_reason = LOCAL_COPY(reason);
+
+       aconf = make_conf();
+       aconf->status = CONF_GLINE;
+       aconf->flags |= CONF_FLAGS_TEMPORARY;
+
+       if(strlen(my_reason) > REASONLEN)
+               my_reason[REASONLEN-1] = '\0';
+
+       if((oper_reason = strchr(my_reason, '|')) != NULL)
+       {
+               *oper_reason = '\0';
+               oper_reason++;
+
+               if(!EmptyString(oper_reason))
+                       DupString(aconf->spasswd, oper_reason);
+       }
+
+       ircsnprintf(buffer, sizeof(buffer), "%s (%s)", reason, current_date);
+
+       DupString(aconf->passwd, buffer);
+       DupString(aconf->user, user);
+       DupString(aconf->host, host);
+       aconf->hold = CurrentTime + ConfigFileEntry.gline_time;
+       add_gline(aconf);
+
+       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                            "%s!%s@%s on %s has triggered gline for [%s@%s] [%s]",
+                            source_p->name, source_p->username,
+                            source_p->host, source_p->user->server,
+                            user, host, reason);
+       ilog(L_GLINE, "T %s %s %s %s %s %s %s",
+            source_p->name, source_p->username, source_p->host, 
+            source_p->user->server, user, host, reason);
+
+       check_glines();
+}
+
+/* majority_gline()
+ *
+ * input       - client doing gline, user, host and reason of gline
+ * output       - YES if there are 3 different opers/servers agree, else NO
+ * side effects -
+ */
+static int
+majority_gline(struct Client *source_p, const char *user,
+              const char *host, const char *reason)
+{
+       dlink_node *pending_node;
+       struct gline_pending *pending;
+
+       /* to avoid desync.. --fl */
+       cleanup_glines(NULL);
+
+       /* if its already glined, why bother? :) -- fl_ */
+       if(find_is_glined(host, user))
+               return NO;
+
+       DLINK_FOREACH(pending_node, pending_glines.head)
+       {
+               pending = pending_node->data;
+
+               if((irccmp(pending->user, user) == 0) &&
+                  (irccmp(pending->host, host) == 0))
+               {
+                       /* check oper or server hasnt already voted */
+                       if(((irccmp(pending->oper_user1, source_p->username) == 0) ||
+                           (irccmp(pending->oper_host1, source_p->host) == 0)))
+                       {
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL, "oper has already voted");
+                               return NO;
+                       }
+                       else if(irccmp(pending->oper_server1, source_p->user->server) == 0)
+                       {
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL, "server has already voted");
+                               return NO;
+                       }
+
+                       if(pending->oper_user2[0] != '\0')
+                       {
+                               /* if two other opers on two different servers have voted yes */
+                               if(((irccmp(pending->oper_user2, source_p->username) == 0) ||
+                                   (irccmp(pending->oper_host2, source_p->host) == 0)))
+                               {
+                                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                                            "oper has already voted");
+                                       return NO;
+                               }
+                               else if(irccmp(pending->oper_server2, source_p->user->server) == 0)
+                               {
+                                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                                            "server has already voted");
+                                       return NO;
+                               }
+
+                               /* trigger the gline using the original reason --fl */
+                               set_local_gline(source_p, user, host,
+                                               pending->reason1);
+
+                               cleanup_glines(NULL);
+                               return YES;
+                       }
+                       else
+                       {
+                               strlcpy(pending->oper_nick2, source_p->name,
+                                       sizeof(pending->oper_nick2));
+                               strlcpy(pending->oper_user2, source_p->username,
+                                       sizeof(pending->oper_user2));
+                               strlcpy(pending->oper_host2, source_p->host,
+                                       sizeof(pending->oper_host2));
+                               DupString(pending->reason2, reason);
+                               pending->oper_server2 = find_or_add(source_p->user->server);
+                               pending->last_gline_time = CurrentTime;
+                               pending->time_request2 = CurrentTime;
+                               return NO;
+                       }
+               }
+       }
+
+       /* no pending gline, create a new one */
+       pending = (struct gline_pending *) 
+                           MyMalloc(sizeof(struct gline_pending));
+
+       strlcpy(pending->oper_nick1, source_p->name,
+               sizeof(pending->oper_nick1));
+       strlcpy(pending->oper_user1, source_p->username,
+               sizeof(pending->oper_user1));
+       strlcpy(pending->oper_host1, source_p->host,
+               sizeof(pending->oper_host1));
+
+       pending->oper_server1 = find_or_add(source_p->user->server);
+
+       strlcpy(pending->user, user, sizeof(pending->user));
+       strlcpy(pending->host, host, sizeof(pending->host));
+       DupString(pending->reason1, reason);
+       pending->reason2 = NULL;
+
+       pending->last_gline_time = CurrentTime;
+       pending->time_request1 = CurrentTime;
+
+       dlinkAddAlloc(pending, &pending_glines);
+
+       return NO;
+}
+
+/* remove_temp_gline()
+ *
+ * inputs       - username, hostname to ungline
+ * outputs      -
+ * side effects - tries to ungline anything that matches
+ */
+static int
+remove_temp_gline(const char *user, const char *host)
+{
+       struct ConfItem *aconf;
+       dlink_node *ptr;
+       struct irc_sockaddr_storage addr, caddr;
+       int bits, cbits;
+       int mtype, gtype;
+
+       mtype = parse_netmask(host, (struct sockaddr *)&addr, &bits);
+
+       DLINK_FOREACH(ptr, glines.head)
+       {
+               aconf = ptr->data;
+
+               gtype = parse_netmask(aconf->host, (struct sockaddr *)&caddr, &cbits);
+
+               if(gtype != mtype || (user && irccmp(user, aconf->user)))
+                       continue;
+
+               if(gtype == HM_HOST)
+               {
+                       if(irccmp(aconf->host, host))
+                               continue;
+               }
+               else if(bits != cbits ||
+                       !comp_with_mask_sock((struct sockaddr *)&addr, 
+                                               (struct sockaddr *)&caddr, bits))
+                       continue;
+
+               dlinkDestroy(ptr, &glines);
+               delete_one_address_conf(aconf->host, aconf);
+               return YES;
+       }
+
+       return NO;
+}
diff --git a/modules/m_help.c b/modules/m_help.c
new file mode 100644 (file)
index 0000000..85f9de3
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_help.c: Provides help information to a user/operator.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_help.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "ircd.h"
+#include "msg.h"
+#include "numeric.h"
+#include "send.h"
+#include "s_conf.h"
+#include "s_log.h"
+#include "parse.h"
+#include "modules.h"
+#include "hash.h"
+#include "cache.h"
+
+static int m_help(struct Client *, struct Client *, int, const char **);
+static int mo_help(struct Client *, struct Client *, int, const char **);
+static int mo_uhelp(struct Client *, struct Client *, int, const char **);
+static void dohelp(struct Client *, int, const char *);
+
+struct Message help_msgtab = {
+       "HELP", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_help, 0}, mg_ignore, mg_ignore, mg_ignore, {mo_help, 0}}
+};
+struct Message uhelp_msgtab = {
+       "UHELP", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_help, 0}, mg_ignore, mg_ignore, mg_ignore, {mo_uhelp, 0}}
+};
+
+mapi_clist_av1 help_clist[] = { &help_msgtab, &uhelp_msgtab, NULL };
+DECLARE_MODULE_AV1(help, NULL, NULL, help_clist, NULL, NULL, "$Revision: 254 $");
+
+/*
+ * m_help - HELP message handler
+ *      parv[0] = sender prefix
+ */
+static int
+m_help(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       static time_t last_used = 0;
+
+       /* HELP is always local */
+       if((last_used + ConfigFileEntry.pace_wait_simple) > CurrentTime)
+       {
+               /* safe enough to give this on a local connect only */
+               sendto_one(source_p, form_str(RPL_LOAD2HI), 
+                          me.name, source_p->name, "HELP");
+               sendto_one(source_p, form_str(RPL_ENDOFHELP),
+                          me.name, source_p->name,
+                          (parc > 1 && !EmptyString(parv[1])) ? parv[1] : "index");
+               return 0;
+       }
+       else
+       {
+               last_used = CurrentTime;
+       }
+
+       dohelp(source_p, HELP_USER, parc > 1 ? parv[1] : NULL);
+
+       return 0;
+}
+
+/*
+ * mo_help - HELP message handler
+ *      parv[0] = sender prefix
+ */
+static int
+mo_help(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       dohelp(source_p, HELP_OPER, parc > 1 ? parv[1] : NULL);
+       return 0;
+}
+
+/*
+ * mo_uhelp - HELP message handler
+ * This is used so that opers can view the user help file without deopering
+ *      parv[0] = sender prefix
+ */
+static int
+mo_uhelp(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       dohelp(source_p, HELP_USER, parc > 1 ? parv[1] : NULL);
+       return 0;
+}
+
+static void
+dohelp(struct Client *source_p, int flags, const char *topic)
+{
+       static const char ntopic[] = "index";
+       struct cachefile *hptr;
+       struct cacheline *lineptr;
+       dlink_node *ptr;
+       dlink_node *fptr;
+
+       if(EmptyString(topic))
+               topic = ntopic;
+
+       hptr = hash_find_help(topic, flags);
+
+       if(hptr == NULL)
+       {
+               sendto_one(source_p, form_str(ERR_HELPNOTFOUND),
+                          me.name, source_p->name, topic);
+               return;
+       }
+
+       fptr = hptr->contents.head;
+       lineptr = fptr->data;
+
+       /* first line cant be empty */
+       sendto_one(source_p, form_str(RPL_HELPSTART),
+                  me.name, source_p->name, topic, lineptr->data);
+
+       DLINK_FOREACH(ptr, fptr->next)
+       {
+               lineptr = ptr->data;
+
+               sendto_one(source_p, form_str(RPL_HELPTXT),
+                          me.name, source_p->name, topic, lineptr->data);
+       }
+
+       sendto_one(source_p, form_str(RPL_ENDOFHELP),
+                  me.name, source_p->name, topic);
+       return;
+}
diff --git a/modules/m_info.c b/modules/m_info.c
new file mode 100644 (file)
index 0000000..e97fabe
--- /dev/null
@@ -0,0 +1,888 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_info.c: Sends information about the server.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_info.c 3131 2007-01-21 15:36:31Z jilles $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "m_info.h"
+#include "channel.h"
+#include "client.h"
+#include "common.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "hook.h"
+#include "numeric.h"
+#include "s_serv.h"
+#include "s_user.h"
+#include "send.h"
+#include "s_conf.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+
+static void send_conf_options(struct Client *source_p);
+static void send_birthdate_online_time(struct Client *source_p);
+static void send_info_text(struct Client *source_p);
+static void info_spy(struct Client *);
+
+static int m_info(struct Client *, struct Client *, int, const char **);
+static int mo_info(struct Client *, struct Client *, int, const char **);
+
+struct Message info_msgtab = {
+       "INFO", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_info, 0}, {mo_info, 0}, mg_ignore, mg_ignore, {mo_info, 0}}
+};
+
+int doing_info_hook;
+
+mapi_clist_av1 info_clist[] = { &info_msgtab, NULL };
+mapi_hlist_av1 info_hlist[] = {
+       { "doing_info",         &doing_info_hook },
+       { NULL, NULL }
+};
+
+DECLARE_MODULE_AV1(info, NULL, NULL, info_clist, info_hlist, NULL, "$Revision: 3131 $");
+
+/*
+ * jdc -- Structure for our configuration value table
+ */
+struct InfoStruct
+{
+       const char *name;       /* Displayed variable name */
+       unsigned int output_type;       /* See below #defines */
+       void *option;           /* Pointer reference to the value */
+       const char *desc;       /* ASCII description of the variable */
+};
+/* Types for output_type in InfoStruct */
+#define OUTPUT_STRING      0x0001      /* Output option as %s w/ dereference */
+#define OUTPUT_STRING_PTR  0x0002      /* Output option as %s w/out deference */
+#define OUTPUT_DECIMAL     0x0004      /* Output option as decimal (%d) */
+#define OUTPUT_BOOLEAN     0x0008      /* Output option as "ON" or "OFF" */
+#define OUTPUT_BOOLEAN_YN  0x0010      /* Output option as "YES" or "NO" */
+#define OUTPUT_BOOLEAN2           0x0020       /* Output option as "YES/NO/MASKED" */
+
+/* *INDENT-OFF* */
+static struct InfoStruct info_table[] = {
+       /* --[  START OF TABLE  ]-------------------------------------------- */
+       {
+               "opers_see_all_users",
+               OUTPUT_BOOLEAN_YN,
+               &opers_see_all_users,
+               "Farconnect notices available or operspy accountability limited"
+       },
+       {
+               "anti_nick_flood",
+               OUTPUT_BOOLEAN,
+               &ConfigFileEntry.anti_nick_flood,
+               "NICK flood protection"
+       },
+       {
+               "anti_spam_exit_message_time",
+               OUTPUT_DECIMAL,
+               &ConfigFileEntry.anti_spam_exit_message_time,
+               "Duration a client must be connected for to have an exit message"
+       },
+       {
+               "caller_id_wait",
+               OUTPUT_DECIMAL,
+               &ConfigFileEntry.caller_id_wait,
+               "Minimum delay between notifying UMODE +g users of messages"
+       },
+       {
+               "client_exit",
+               OUTPUT_BOOLEAN,
+               &ConfigFileEntry.client_exit,
+               "Prepend 'Client Exit:' to user QUIT messages"
+       },
+       {
+               "client_flood",
+               OUTPUT_DECIMAL,
+               &ConfigFileEntry.client_flood,
+               "Number of lines before a client Excess Flood's",
+       },
+       {
+               "connect_timeout",
+               OUTPUT_DECIMAL,
+               &ConfigFileEntry.connect_timeout,
+               "Connect timeout for connections to servers"
+       },
+       {
+               "default_floodcount",
+               OUTPUT_DECIMAL,
+               &ConfigFileEntry.default_floodcount,
+               "Startup value of FLOODCOUNT",
+       },
+       {
+               "default_adminstring",
+               OUTPUT_STRING,
+               &ConfigFileEntry.default_adminstring,
+               "Default adminstring at startup.",
+       },
+       {
+               "default_operstring",
+               OUTPUT_STRING,
+               &ConfigFileEntry.default_operstring,
+               "Default operstring at startup.",
+       },
+       {
+               "servicestring",
+               OUTPUT_STRING,
+               &ConfigFileEntry.servicestring,
+               "String shown in whois for opered services.",
+       },
+       {
+               "disable_auth",
+               OUTPUT_BOOLEAN_YN,
+               &ConfigFileEntry.disable_auth,
+               "Controls whether auth checking is disabled or not"
+       },
+       {
+               "disable_fake_channels",
+               OUTPUT_BOOLEAN_YN,
+               &ConfigFileEntry.disable_fake_channels,
+               "Controls whether bold etc are disabled for JOIN"
+       },
+       {
+               "dot_in_ip6_addr",
+               OUTPUT_BOOLEAN,
+               &ConfigFileEntry.dot_in_ip6_addr,
+               "Suffix a . to ip6 addresses",
+       },
+       {
+               "dots_in_ident",
+               OUTPUT_DECIMAL,
+               &ConfigFileEntry.dots_in_ident,
+               "Number of permissable dots in an ident"
+       },
+       {
+               "failed_oper_notice",
+               OUTPUT_BOOLEAN,
+               &ConfigFileEntry.failed_oper_notice,
+               "Inform opers if someone /oper's with the wrong password"
+       },
+       {
+               "fname_userlog",
+               OUTPUT_STRING,
+               &ConfigFileEntry.fname_userlog,
+               "User log file"
+       },
+       {
+               "fname_fuserlog",
+               OUTPUT_STRING,
+               &ConfigFileEntry.fname_fuserlog,
+               "Failed user log file"
+       },
+
+       {
+               "fname_operlog",
+               OUTPUT_STRING,
+               &ConfigFileEntry.fname_operlog,
+               "Operator log file"
+       },
+       {
+               "fname_foperlog",
+               OUTPUT_STRING,
+               &ConfigFileEntry.fname_foperlog,
+               "Failed operator log file"
+       },
+       {
+               "fname_serverlog",
+               OUTPUT_STRING,
+               &ConfigFileEntry.fname_serverlog,
+               "Server connect/disconnect log file"
+       },
+       {
+               "fname_klinelog",
+               OUTPUT_STRING,
+               &ConfigFileEntry.fname_klinelog,
+               "KLINE etc log file"
+       },
+       {
+               "fname_glinelog",
+               OUTPUT_STRING,
+               &ConfigFileEntry.fname_glinelog,
+               "GLINE log file"
+       },
+       {
+               "fname_operspylog",
+               OUTPUT_STRING,
+               &ConfigFileEntry.fname_operspylog,
+               "Oper spy log file"
+       },
+       {
+               "fname_ioerrorlog",
+               OUTPUT_STRING,
+               &ConfigFileEntry.fname_ioerrorlog,
+               "IO error log file"
+       },
+       {
+               "glines",
+               OUTPUT_BOOLEAN,
+               &ConfigFileEntry.glines,
+               "G-line (network-wide K-line) support"
+       },
+       {
+               "gline_time",
+               OUTPUT_DECIMAL,
+               &ConfigFileEntry.gline_time,
+               "Expiry time for G-lines"
+       },
+       {
+               "gline_min_cidr",
+               OUTPUT_DECIMAL,
+               &ConfigFileEntry.gline_min_cidr,
+               "Minimum CIDR bitlen for ipv4 glines"
+       },
+       {
+               "gline_min_cidr6",
+               OUTPUT_DECIMAL,
+               &ConfigFileEntry.gline_min_cidr6,
+               "Minimum CIDR bitlen for ipv6 glines"
+       },
+       {
+               "global_snotices",
+               OUTPUT_BOOLEAN_YN,
+               &ConfigFileEntry.global_snotices,
+               "Send out certain server notices globally"
+       },
+       {
+               "hide_error_messages",
+               OUTPUT_BOOLEAN2,
+               &ConfigFileEntry.hide_error_messages,
+               "Hide ERROR messages coming from servers"
+       },
+       {
+               "hide_spoof_ips",
+               OUTPUT_BOOLEAN_YN,
+               &ConfigFileEntry.hide_spoof_ips,
+               "Hide IPs of spoofed users"
+       },
+       {
+               "hub",
+               OUTPUT_BOOLEAN_YN,
+               &ServerInfo.hub,
+               "Server is a hub"
+       },
+       {
+               "idletime",
+               OUTPUT_DECIMAL,
+               &ConfigFileEntry.idletime,
+               "Number of minutes before a client is considered idle"
+       },
+       {
+               "kline_delay",
+               OUTPUT_DECIMAL,
+               &ConfigFileEntry.kline_delay,
+               "Duration of time to delay kline checking"
+       },
+       {
+               "kline_reason",
+               OUTPUT_STRING,
+               &ConfigFileEntry.kline_reason,
+               "K-lined clients sign off with this reason"
+       },
+       {
+               "dline_with_reason",
+               OUTPUT_BOOLEAN_YN,
+               &ConfigFileEntry.dline_with_reason,
+               "Display D-line reason to client on disconnect"
+       },
+       {
+               "kline_with_reason",
+               OUTPUT_BOOLEAN_YN,
+               &ConfigFileEntry.kline_with_reason,
+               "Display K-line reason to client on disconnect"
+       },
+       {
+               "max_accept",
+               OUTPUT_DECIMAL,
+               &ConfigFileEntry.max_accept,
+               "Maximum nicknames on accept list",
+       },
+       {
+               "max_nick_changes",
+               OUTPUT_DECIMAL,
+               &ConfigFileEntry.max_nick_changes,
+               "NICK change threshhold setting"
+       },
+       {
+               "max_nick_time",
+               OUTPUT_DECIMAL,
+               &ConfigFileEntry.max_nick_time,
+               "NICK flood protection time interval"
+       },
+       {
+               "max_targets",
+               OUTPUT_DECIMAL,
+               &ConfigFileEntry.max_targets,
+               "The maximum number of PRIVMSG/NOTICE targets"
+       },
+       {
+               "min_nonwildcard",
+               OUTPUT_DECIMAL,
+               &ConfigFileEntry.min_nonwildcard,
+               "Minimum non-wildcard chars in K/G lines",
+       },
+       {
+               "min_nonwildcard_simple",
+               OUTPUT_DECIMAL,
+               &ConfigFileEntry.min_nonwildcard_simple,
+               "Minimum non-wildcard chars in xlines/resvs",
+       },
+       {
+               "network_name",
+               OUTPUT_STRING,
+               &ServerInfo.network_name,
+               "Network name"
+       },
+       {
+               "network_desc",
+               OUTPUT_STRING,
+               &ServerInfo.network_desc,
+               "Network description"
+       },
+       {
+               "nick_delay",
+               OUTPUT_DECIMAL,
+               &ConfigFileEntry.nick_delay,
+               "Delay nicks are locked for on split",
+       },
+       {
+               "no_oper_flood",
+               OUTPUT_BOOLEAN,
+               &ConfigFileEntry.no_oper_flood,
+               "Disable flood control for operators",
+       },
+       {
+               "non_redundant_klines",
+               OUTPUT_BOOLEAN,
+               &ConfigFileEntry.non_redundant_klines,
+               "Check for and disallow redundant K-lines"
+       },
+       {
+               "operspy_admin_only",
+               OUTPUT_BOOLEAN,
+               &ConfigFileEntry.operspy_admin_only,
+               "Send +Z operspy notices to admins only"
+       },
+       {
+               "operspy_dont_care_user_info",
+               OUTPUT_BOOLEAN,
+               &ConfigFileEntry.operspy_dont_care_user_info,
+               "Remove accountability and some '!' requirement from non-channel operspy"
+       },
+       {
+               "pace_wait",
+               OUTPUT_DECIMAL,
+               &ConfigFileEntry.pace_wait,
+               "Minimum delay between uses of certain commands"
+       },
+       {
+               "pace_wait_simple",
+               OUTPUT_DECIMAL,
+               &ConfigFileEntry.pace_wait_simple,
+               "Minimum delay between less intensive commands"
+       },
+       {
+               "ping_cookie",
+               OUTPUT_BOOLEAN,
+               &ConfigFileEntry.ping_cookie,
+               "Require ping cookies to connect",
+       },
+       {
+               "reject_after_count",
+               OUTPUT_DECIMAL,
+               &ConfigFileEntry.reject_after_count,   
+               "Client rejection threshold setting",
+       },
+       {
+               "reject_ban_time",
+               OUTPUT_DECIMAL,
+               &ConfigFileEntry.reject_ban_time,
+               "Client rejection time interval",
+       },
+       {
+               "reject_duration",
+               OUTPUT_DECIMAL,
+               &ConfigFileEntry.reject_duration,
+               "Client rejection cache duration",
+       },
+       {
+               "short_motd",
+               OUTPUT_BOOLEAN_YN,
+               &ConfigFileEntry.short_motd,
+               "Do not show MOTD; only tell clients they should read it"
+       },
+       {
+               "stats_e_disabled",
+               OUTPUT_BOOLEAN_YN,
+               &ConfigFileEntry.stats_e_disabled,
+               "STATS e output is disabled",
+       },
+       {
+               "stats_c_oper_only",
+               OUTPUT_BOOLEAN_YN,
+               &ConfigFileEntry.stats_c_oper_only,
+               "STATS C output is only shown to operators",
+       },
+       {
+               "stats_h_oper_only",
+               OUTPUT_BOOLEAN_YN,
+               &ConfigFileEntry.stats_h_oper_only,
+               "STATS H output is only shown to operators",
+       },
+       {
+               "stats_i_oper_only",
+               OUTPUT_BOOLEAN2,
+               &ConfigFileEntry.stats_i_oper_only,
+               "STATS I output is only shown to operators",
+       },
+       {
+               "stats_k_oper_only",
+               OUTPUT_BOOLEAN2,
+               &ConfigFileEntry.stats_k_oper_only,
+               "STATS K output is only shown to operators",
+       },
+       {
+               "stats_o_oper_only",
+               OUTPUT_BOOLEAN_YN,
+               &ConfigFileEntry.stats_o_oper_only,
+               "STATS O output is only shown to operators",
+       },
+       {
+               "stats_P_oper_only",
+               OUTPUT_BOOLEAN_YN,
+               &ConfigFileEntry.stats_P_oper_only,
+               "STATS P is only shown to operators",
+       },
+       {
+               "stats_y_oper_only",
+               OUTPUT_BOOLEAN_YN,
+               &ConfigFileEntry.stats_y_oper_only,
+               "STATS Y is only shown to operators",
+       },
+       {
+               "tkline_expire_notices",
+               OUTPUT_BOOLEAN,
+               &ConfigFileEntry.tkline_expire_notices,
+               "Notices given to opers when tklines expire"
+       },
+       {
+               "ts_max_delta",
+               OUTPUT_DECIMAL,
+               &ConfigFileEntry.ts_max_delta,
+               "Maximum permitted TS delta from another server"
+       },
+       {
+               "ts_warn_delta",
+               OUTPUT_DECIMAL,
+               &ConfigFileEntry.ts_warn_delta,
+               "Maximum permitted TS delta before displaying a warning"
+       },
+       {
+               "warn_no_nline",
+               OUTPUT_BOOLEAN,
+               &ConfigFileEntry.warn_no_nline,
+               "Display warning if connecting server lacks N-line"
+       },
+       {
+               "default_split_server_count",
+               OUTPUT_DECIMAL,
+               &ConfigChannel.default_split_server_count,
+               "Startup value of SPLITNUM",
+       },
+       {
+               "default_split_user_count",
+               OUTPUT_DECIMAL,
+               &ConfigChannel.default_split_user_count,
+               "Startup value of SPLITUSERS",
+       },
+       {
+               "knock_delay",
+               OUTPUT_DECIMAL,
+               &ConfigChannel.knock_delay,
+               "Delay between a users KNOCK attempts"
+       },
+       {
+               "knock_delay_channel",
+               OUTPUT_DECIMAL,
+               &ConfigChannel.knock_delay_channel,
+               "Delay between KNOCK attempts to a channel",
+       },
+       {
+               "invite_ops_only",
+               OUTPUT_BOOLEAN_YN,
+               &ConfigChannel.invite_ops_only,
+               "INVITE is restricted to channelops only"
+       },
+       {
+               "kick_on_split_riding",
+               OUTPUT_BOOLEAN_YN,
+               &ConfigChannel.kick_on_split_riding,
+               "Kick users riding splits to join +i or +k channels"
+       },
+       {
+               "max_bans",
+               OUTPUT_DECIMAL,
+               &ConfigChannel.max_bans,
+               "Total +b/e/I/q modes allowed in a channel",
+       },
+       {
+               "max_bans_large",
+               OUTPUT_DECIMAL,
+               &ConfigChannel.max_bans_large,
+               "Total +b/e/I/q modes allowed in a +L channel",
+       },
+       {
+               "max_chans_per_user",
+               OUTPUT_DECIMAL,
+               &ConfigChannel.max_chans_per_user,
+               "Maximum number of channels a user can join",
+       },
+       {
+               "no_create_on_split",
+               OUTPUT_BOOLEAN_YN,
+               &ConfigChannel.no_create_on_split,
+               "Disallow creation of channels when split",
+       },
+       {
+               "no_join_on_split",
+               OUTPUT_BOOLEAN_YN,
+               &ConfigChannel.no_join_on_split,
+               "Disallow joining channels when split",
+       },
+       {
+               "use_except",
+               OUTPUT_BOOLEAN_YN,
+               &ConfigChannel.use_except,
+               "Enable chanmode +e (ban exceptions)",
+       },
+       {
+               "use_invex",
+               OUTPUT_BOOLEAN_YN,
+               &ConfigChannel.use_invex,
+               "Enable chanmode +I (invite exceptions)",
+       },
+       {
+               "use_forward",
+               OUTPUT_BOOLEAN_YN,
+               &ConfigChannel.use_forward,
+               "Enable chanmode +f (channel forwarding)",
+       },
+       {
+               "use_knock",
+               OUTPUT_BOOLEAN_YN,
+               &ConfigChannel.use_knock,
+               "Enable /KNOCK",
+       },
+       {
+               "disable_hidden",
+               OUTPUT_BOOLEAN_YN,
+               &ConfigServerHide.disable_hidden,
+               "Prevent servers from hiding themselves from a flattened /links",
+       },
+       {
+               "flatten_links",
+               OUTPUT_BOOLEAN_YN,
+               &ConfigServerHide.flatten_links,
+               "Flatten /links list",
+       },
+       {
+               "hidden",
+               OUTPUT_BOOLEAN_YN,
+               &ConfigServerHide.hidden,
+               "Hide this server from a flattened /links on remote servers",
+       },
+       {
+               "links_delay",
+               OUTPUT_DECIMAL,
+               &ConfigServerHide.links_delay,
+               "Links rehash delay"
+       },
+       /* --[  END OF TABLE  ]---------------------------------------------- */
+       { (char *) 0, (unsigned int) 0, (void *) 0, (char *) 0}
+};
+/* *INDENT-ON* */
+
+/*
+** m_info
+**  parv[0] = sender prefix
+**  parv[1] = servername
+*/
+static int
+m_info(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       static time_t last_used = 0L;
+
+       if((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
+       {
+               /* safe enough to give this on a local connect only */
+               sendto_one(source_p, form_str(RPL_LOAD2HI),
+                          me.name, source_p->name, "INFO");
+               sendto_one_numeric(source_p, RPL_ENDOFINFO, form_str(RPL_ENDOFINFO));
+               return 0;
+       }
+       else
+               last_used = CurrentTime;
+
+       if(hunt_server(client_p, source_p, ":%s INFO :%s", 1, parc, parv) != HUNTED_ISME)
+               return 0;
+
+       info_spy(source_p);
+
+       send_info_text(source_p);
+       send_birthdate_online_time(source_p);
+
+       sendto_one_numeric(source_p, RPL_ENDOFINFO, form_str(RPL_ENDOFINFO));
+       return 0;
+}
+
+/*
+** mo_info
+**  parv[0] = sender prefix
+**  parv[1] = servername
+*/
+static int
+mo_info(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       if(hunt_server(client_p, source_p, ":%s INFO :%s", 1, parc, parv) == HUNTED_ISME)
+       {
+               info_spy(source_p);
+
+               send_info_text(source_p);
+
+               if(IsOper(source_p))
+                       send_conf_options(source_p);
+
+               send_birthdate_online_time(source_p);
+
+               sendto_one_numeric(source_p, RPL_ENDOFINFO, form_str(RPL_ENDOFINFO));
+       }
+
+       return 0;
+}
+
+/*
+ * send_info_text
+ *
+ * inputs      - client pointer to send info text to
+ * output      - none
+ * side effects        - info text is sent to client
+ */
+static void
+send_info_text(struct Client *source_p)
+{
+       const char **text = infotext;
+
+       while (*text)
+       {
+               sendto_one_numeric(source_p, RPL_INFO, form_str(RPL_INFO), *text++);
+       }
+
+       sendto_one_numeric(source_p, RPL_INFO, form_str(RPL_INFO), "");
+}
+
+/*
+ * send_birthdate_online_time
+ *
+ * inputs      - client pointer to send to
+ * output      - none
+ * side effects        - birthdate and online time are sent
+ */
+static void
+send_birthdate_online_time(struct Client *source_p)
+{
+       sendto_one(source_p, ":%s %d %s :Birth Date: %s, compile # %s",
+                  get_id(&me, source_p), RPL_INFO, 
+                  get_id(source_p, source_p), creation, generation);
+
+       sendto_one(source_p, ":%s %d %s :On-line since %s",
+                  get_id(&me, source_p), RPL_INFO, 
+                  get_id(source_p, source_p), myctime(startup_time));
+}
+
+/*
+ * send_conf_options
+ *
+ * inputs      - client pointer to send to
+ * output      - none
+ * side effects        - send config options to client
+ */
+static void
+send_conf_options(struct Client *source_p)
+{
+       Info *infoptr;
+       int i = 0;
+
+       /*
+        * Now send them a list of all our configuration options
+        * (mostly from config.h)
+        */
+       for (infoptr = MyInformation; infoptr->name; infoptr++)
+       {
+               if(infoptr->intvalue)
+               {
+                       sendto_one(source_p, ":%s %d %s :%-30s %-5d [%-30s]",
+                                  get_id(&me, source_p), RPL_INFO,
+                                  get_id(source_p, source_p),
+                                  infoptr->name, infoptr->intvalue, 
+                                  infoptr->desc);
+               }
+               else
+               {
+                       sendto_one(source_p, ":%s %d %s :%-30s %-5s [%-30s]",
+                                  get_id(&me, source_p), RPL_INFO,
+                                  get_id(source_p, source_p),
+                                  infoptr->name, infoptr->strvalue, 
+                                  infoptr->desc);
+               }
+       }
+
+       /*
+        * Parse the info_table[] and do the magic.
+        */
+       for (i = 0; info_table[i].name; i++)
+       {
+               switch (info_table[i].output_type)
+               {
+                       /*
+                        * For "char *" references
+                        */
+               case OUTPUT_STRING:
+                       {
+                               char *option = *((char **) info_table[i].option);
+
+                               sendto_one(source_p, ":%s %d %s :%-30s %-5s [%-30s]",
+                                          get_id(&me, source_p), RPL_INFO,
+                                          get_id(source_p, source_p),
+                                          info_table[i].name,
+                                          option ? option : "NONE",
+                                          info_table[i].desc ? info_table[i].desc : "<none>");
+
+                               break;
+                       }
+                       /*
+                        * For "char foo[]" references
+                        */
+               case OUTPUT_STRING_PTR:
+                       {
+                               char *option = (char *) info_table[i].option;
+
+                               sendto_one(source_p, ":%s %d %s :%-30s %-5s [%-30s]",
+                                          get_id(&me, source_p), RPL_INFO,
+                                          get_id(source_p, source_p),
+                                          info_table[i].name,
+                                          EmptyString(option) ? "NONE" : option,
+                                          info_table[i].desc ? info_table[i].desc : "<none>");
+
+                               break;
+                       }
+                       /*
+                        * Output info_table[i].option as a decimal value.
+                        */
+               case OUTPUT_DECIMAL:
+                       {
+                               int option = *((int *) info_table[i].option);
+
+                               sendto_one(source_p, ":%s %d %s :%-30s %-5d [%-30s]",
+                                          get_id(&me, source_p), RPL_INFO,
+                                          get_id(source_p, source_p),
+                                          info_table[i].name,
+                                          option,
+                                          info_table[i].desc ? info_table[i].desc : "<none>");
+
+                               break;
+                       }
+
+                       /*
+                        * Output info_table[i].option as "ON" or "OFF"
+                        */
+               case OUTPUT_BOOLEAN:
+                       {
+                               int option = *((int *) info_table[i].option);
+
+                               sendto_one(source_p, ":%s %d %s :%-30s %-5s [%-30s]",
+                                          get_id(&me, source_p), RPL_INFO,
+                                          get_id(source_p, source_p),
+                                          info_table[i].name,
+                                          option ? "ON" : "OFF",
+                                          info_table[i].desc ? info_table[i].desc : "<none>");
+
+                               break;
+                       }
+                       /*
+                        * Output info_table[i].option as "YES" or "NO"
+                        */
+               case OUTPUT_BOOLEAN_YN:
+                       {
+                               int option = *((int *) info_table[i].option);
+
+                               sendto_one(source_p, ":%s %d %s :%-30s %-5s [%-30s]",
+                                          get_id(&me, source_p), RPL_INFO,
+                                          get_id(source_p, source_p),
+                                          info_table[i].name,
+                                          option ? "YES" : "NO",
+                                          info_table[i].desc ? info_table[i].desc : "<none>");
+
+                               break;
+                       }
+
+               case OUTPUT_BOOLEAN2:
+               {
+                       int option = *((int *) info_table[i].option);
+
+                       sendto_one(source_p, ":%s %d %s :%-30s %-5s [%-30s]",
+                                  me.name, RPL_INFO, source_p->name,
+                                  info_table[i].name,
+                                  option ? ((option == 1) ? "MASK" : "YES") : "NO",
+                                  info_table[i].desc ? info_table[i].desc : "<none>");
+               }               /* switch (info_table[i].output_type) */
+               }
+       }                       /* forloop */
+
+
+       /* Don't send oper_only_umodes...it's a bit mask, we will have to decode it
+        ** in order for it to show up properly to opers who issue INFO
+        */
+
+       sendto_one_numeric(source_p, RPL_INFO, form_str(RPL_INFO), "");
+}
+
+/* info_spy()
+ * 
+ * input        - pointer to client
+ * output       - none
+ * side effects - hook doing_info is called
+ */
+static void
+info_spy(struct Client *source_p)
+{
+       hook_data hd;
+
+       hd.client = source_p;
+       hd.arg1 = hd.arg2 = NULL;
+
+       call_hook(doing_info_hook, &hd);
+}
diff --git a/modules/m_invite.c b/modules/m_invite.c
new file mode 100644 (file)
index 0000000..8230a30
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_invite.c: Invites the user to join a channel.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_invite.c 718 2006-02-08 20:26:58Z jilles $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "common.h"
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "s_conf.h"
+#include "s_serv.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "packet.h"
+
+static int m_invite(struct Client *, struct Client *, int, const char **);
+
+struct Message invite_msgtab = {
+       "INVITE", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_invite, 3}, {m_invite, 3}, mg_ignore, mg_ignore, {m_invite, 3}}
+};
+mapi_clist_av1 invite_clist[] = { &invite_msgtab, NULL };
+DECLARE_MODULE_AV1(invite, NULL, NULL, invite_clist, NULL, NULL, "$Revision: 718 $");
+
+static void add_invite(struct Channel *, struct Client *);
+
+/* m_invite()
+ *      parv[0] - sender prefix
+ *      parv[1] - user to invite
+ *      parv[2] - channel name
+ */
+static int
+m_invite(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+       struct Channel *chptr;
+       struct membership *msptr;
+       int store_invite = 0;
+
+       if(MyClient(source_p) && !IsFloodDone(source_p))
+               flood_endgrace(source_p);
+
+       if((target_p = find_person(parv[1])) == NULL)
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHNICK, 
+                                  form_str(ERR_NOSUCHNICK), 
+                                  IsDigit(parv[1][0]) ? "*" : parv[1]);
+               return 0;
+       }
+
+       if(check_channel_name(parv[2]) == 0)
+       {
+               sendto_one_numeric(source_p, ERR_BADCHANNAME,
+                                  form_str(ERR_BADCHANNAME),
+                                  parv[2]);
+               return 0;
+       }
+
+       if(!IsChannelName(parv[2]))
+       {
+               if(MyClient(source_p))
+                       sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
+                                          form_str(ERR_NOSUCHCHANNEL), parv[2]);
+               return 0;
+       }
+
+       /* Do not send local channel invites to users if they are not on the
+        * same server as the person sending the INVITE message. 
+        */
+       if(parv[2][0] == '&' && !MyConnect(target_p))
+       {
+               sendto_one(source_p, form_str(ERR_USERNOTONSERV),
+                          me.name, source_p->name, target_p->name);
+               return 0;
+       }
+
+       if((chptr = find_channel(parv[2])) == NULL)
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
+                                  form_str(ERR_NOSUCHCHANNEL), parv[2]);
+               return 0;
+       }
+
+       msptr = find_channel_membership(chptr, source_p);
+       if(MyClient(source_p) && (msptr == NULL))
+       {
+               sendto_one_numeric(source_p, ERR_NOTONCHANNEL,
+                                  form_str(ERR_NOTONCHANNEL), parv[2]);
+               return 0;
+       }
+
+       if(IsMember(target_p, chptr))
+       {
+               sendto_one_numeric(source_p, ERR_USERONCHANNEL,
+                                  form_str(ERR_USERONCHANNEL),
+                                  target_p->name, parv[2]);
+               return 0;
+       }
+
+       /* only store invites for +i channels */
+       /* if the invite could allow someone to join who otherwise could not,
+        * unconditionally require ops, unless the channel is +g */
+       if(ConfigChannel.invite_ops_only || (chptr->mode.mode & MODE_INVITEONLY))
+       {
+               /* treat remote clients as chanops */
+               if(MyClient(source_p) && !is_chanop(msptr) &&
+                               !(chptr->mode.mode & MODE_FREEINVITE))
+               {
+                       sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
+                                  me.name, source_p->name, parv[2]);
+                       return 0;
+               }
+
+               if(chptr->mode.mode & MODE_INVITEONLY)
+                       store_invite = 1;
+       }
+
+       if(MyConnect(source_p))
+       {
+               sendto_one(source_p, form_str(RPL_INVITING), 
+                          me.name, source_p->name,
+                          target_p->name, parv[2]);
+               if(target_p->user->away)
+                       sendto_one_numeric(source_p, RPL_AWAY, form_str(RPL_AWAY),
+                                          target_p->name, target_p->user->away);
+       }
+       /* invite timestamp */
+       else if(parc > 3 && !EmptyString(parv[3]))
+       {
+               /* this should never be less than */
+               if(atol(parv[3]) > chptr->channelts)
+                       return 0;
+       }
+
+       if(MyConnect(target_p))
+       {
+               sendto_one(target_p, ":%s!%s@%s INVITE %s :%s", 
+                          source_p->name, source_p->username, source_p->host, 
+                          target_p->name, chptr->chname);
+
+               if(store_invite)
+                       add_invite(chptr, target_p);
+       }
+       else if(target_p->from != client_p)
+       {
+               sendto_one_prefix(target_p, source_p, "INVITE", "%s %lu",
+                                 chptr->chname, (unsigned long) chptr->channelts);
+       }
+
+       return 0;
+}
+
+/* add_invite()
+ *
+ * input       - channel to add invite to, client to add
+ * output      -
+ * side effects - client is added to invite list.
+ */
+static void
+add_invite(struct Channel *chptr, struct Client *who)
+{
+       dlink_node *ptr;
+
+       /* already invited? */
+       DLINK_FOREACH(ptr, who->user->invited.head)
+       {
+               if(ptr->data == chptr)
+                       return;
+       }
+
+       /* ok, if their invite list is too long, remove the tail */
+       if((int)dlink_list_length(&who->user->invited) >= 
+          ConfigChannel.max_chans_per_user)
+       {
+               ptr = who->user->invited.tail;
+               del_invite(ptr->data, who);
+       }
+
+       /* add user to channel invite list */
+       dlinkAddAlloc(who, &chptr->invites);
+
+       /* add channel to user invite list */
+       dlinkAddAlloc(chptr, &who->user->invited);
+}
+
+
diff --git a/modules/m_ison.c b/modules/m_ison.c
new file mode 100644 (file)
index 0000000..cfb15f3
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_ison.c: Provides a single line answer of whether a user is online.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_ison.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_conf.h"            /* ConfigFileEntry */
+#include "s_serv.h"            /* uplink/IsCapable */
+#include "hash.h"
+
+#include <string.h>
+
+static int m_ison(struct Client *, struct Client *, int, const char **);
+
+struct Message ison_msgtab = {
+       "ISON", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_ison, 2}, mg_ignore, mg_ignore, mg_ignore, {m_ison, 2}}
+};
+
+mapi_clist_av1 ison_clist[] = { &ison_msgtab, NULL };
+DECLARE_MODULE_AV1(ison, NULL, NULL, ison_clist, NULL, NULL, "$Revision: 254 $");
+
+static char buf[BUFSIZE];
+static char buf2[BUFSIZE];
+
+
+/*
+ * m_ison added by Darren Reed 13/8/91 to act as an efficent 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
+ */
+static int
+m_ison(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+       char *nick;
+       char *p;
+       char *current_insert_point, *current_insert_point2;
+       int len;
+       int i;
+       int done = 0;
+
+       current_insert_point2 = buf2;
+       *buf2 = '\0';
+
+       ircsprintf(buf, form_str(RPL_ISON), me.name, source_p->name);
+       len = strlen(buf);
+       current_insert_point = buf + len;
+
+       /* rfc1489 is ambigious about how to handle ISON
+        * this should handle both interpretations.
+        */
+       for (i = 1; i < parc; i++)
+       {
+               char *cs = LOCAL_COPY(parv[i]);
+               for (nick = strtoken(&p, cs, " "); nick; nick = strtoken(&p, NULL, " "))
+               {
+                       target_p = find_named_client(nick);
+
+                       if(target_p != NULL)
+                       {
+                               len = strlen(target_p->name);
+                               if((current_insert_point + (len + 5)) < (buf + sizeof(buf)))
+                               {
+                                       memcpy((void *) current_insert_point,
+                                              (void *) target_p->name, len);
+                                       current_insert_point += len;
+                                       *current_insert_point++ = ' ';
+                               }
+                               else
+                               {
+                                       done = 1;
+                                       break;
+                               }
+                       }
+               }
+               if(done)
+                       break;
+       }
+
+       /*  current_insert_point--;
+        *  Do NOT take out the trailing space, it breaks ircII
+        *  --Rodder */
+
+       *current_insert_point = '\0';
+       *current_insert_point2 = '\0';
+
+       sendto_one(source_p, "%s", buf);
+
+       return 0;
+}
diff --git a/modules/m_kline.c b/modules/m_kline.c
new file mode 100644 (file)
index 0000000..cbe6829
--- /dev/null
@@ -0,0 +1,918 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_kline.c: Bans/unbans a user.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_kline.c 3063 2006-12-27 00:47:45Z jilles $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "channel.h"
+#include "class.h"
+#include "client.h"
+#include "common.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "hostmask.h"
+#include "numeric.h"
+#include "commio.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "s_log.h"
+#include "send.h"
+#include "hash.h"
+#include "s_serv.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "event.h"
+
+static int mo_kline(struct Client *, struct Client *, int, const char **);
+static int ms_kline(struct Client *, struct Client *, int, const char **);
+static int me_kline(struct Client *, struct Client *, int, const char **);
+static int mo_unkline(struct Client *, struct Client *, int, const char **);
+static int ms_unkline(struct Client *, struct Client *, int, const char **);
+static int me_unkline(struct Client *, struct Client *, int, const char **);
+
+struct Message kline_msgtab = {
+       "KLINE", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, {ms_kline, 5}, {ms_kline, 5}, {me_kline, 5}, {mo_kline, 3}}
+};
+
+struct Message unkline_msgtab = {
+       "UNKLINE", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, {ms_unkline, 4}, {ms_unkline, 4}, {me_unkline, 3}, {mo_unkline, 2}}
+};
+
+mapi_clist_av1 kline_clist[] = { &kline_msgtab, &unkline_msgtab, NULL };
+DECLARE_MODULE_AV1(kline, NULL, NULL, kline_clist, NULL, NULL, "$Revision: 3063 $");
+
+/* Local function prototypes */
+static int find_user_host(struct Client *source_p, const char *userhost, char *user, char *host);
+static int valid_comment(struct Client *source_p, char *comment);
+static int valid_user_host(struct Client *source_p, const char *user, const char *host);
+static int valid_wild_card(struct Client *source_p, const char *user, const char *host);
+
+static void handle_remote_kline(struct Client *source_p, int tkline_time,
+               const char *user, const char *host, const char *reason);
+static void apply_kline(struct Client *source_p, struct ConfItem *aconf,
+                       const char *reason, const char *oper_reason, const char *current_date);
+static void apply_tkline(struct Client *source_p, struct ConfItem *aconf,
+                        const char *, const char *, const char *, int);
+static int already_placed_kline(struct Client *, const char *, const char *, int);
+
+static void handle_remote_unkline(struct Client *source_p, 
+                       const char *user, const char *host);
+static void remove_permkline_match(struct Client *, const char *, const char *);
+static int flush_write(struct Client *, FILE *, const char *, const char *);
+static int remove_temp_kline(const char *, const char *);
+
+/* mo_kline()
+ *
+ *   parv[1] - temp time or user@host
+ *   parv[2] - user@host, "ON", or reason
+ *   parv[3] - "ON", reason, or server to target
+ *   parv[4] - server to target, or reason
+ *   parv[5] - reason
+ */
+static int
+mo_kline(struct Client *client_p, struct Client *source_p,
+        int parc, const char **parv)
+{
+       char def[] = "No Reason";
+       char user[USERLEN + 2];
+       char host[HOSTLEN + 2];
+       char buffer[IRCD_BUFSIZE];
+       char *reason = def;
+       char *oper_reason;
+       const char *current_date;
+       const char *target_server = NULL;
+       struct ConfItem *aconf;
+       int tkline_time = 0;
+       int loc = 1;
+
+       if(!IsOperK(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS),
+                          me.name, source_p->name, "kline");
+               return 0;
+       }
+
+       if((tkline_time = valid_temp_time(parv[loc])) >= 0)
+               loc++;
+       /* we just set tkline_time to -1! */
+       else
+               tkline_time = 0;
+
+       if(find_user_host(source_p, parv[loc], user, host) == 0)
+               return 0;
+
+       loc++;
+
+       if(parc >= loc+2 && !irccmp(parv[loc], "ON"))
+       {
+               if(!IsOperRemoteBan(source_p))
+               {
+                       sendto_one(source_p, form_str(ERR_NOPRIVS),
+                               me.name, source_p->name, "remoteban");
+                       return 0;
+               }
+
+               target_server = parv[loc+1];
+               loc += 2;
+       }
+
+       if(parc <= loc || EmptyString(parv[loc]))
+       {
+               sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+                          me.name, source_p->name, "KLINE");
+               return 0;
+       }
+
+       reason = LOCAL_COPY(parv[loc]);
+
+       if(target_server != NULL)
+       {
+               propagate_generic(source_p, "KLINE", target_server, CAP_KLN,
+                               "%d %s %s :%s",
+                               tkline_time, user, host, reason);
+
+               /* If we are sending it somewhere that doesnt include us, stop */
+               if(!match(target_server, me.name))
+                       return 0;
+       }
+       /* if we have cluster servers, send it to them.. */
+       else if(dlink_list_length(&cluster_conf_list) > 0)
+               cluster_generic(source_p, "KLINE", 
+                               (tkline_time > 0) ? SHARED_TKLINE : SHARED_PKLINE, CAP_KLN,
+                               "%lu %s %s :%s",
+                               tkline_time, user, host, reason);
+
+       if(!valid_user_host(source_p, user, host) || 
+          !valid_wild_card(source_p, user, host) ||
+          !valid_comment(source_p, reason))
+               return 0;
+
+       if(already_placed_kline(source_p, user, host, tkline_time))
+               return 0;
+
+       set_time();
+       current_date = smalldate();
+       aconf = make_conf();
+       aconf->status = CONF_KILL;
+       DupString(aconf->host, host);
+       DupString(aconf->user, user);
+       aconf->port = 0;
+
+       /* Look for an oper reason */
+       if((oper_reason = strchr(reason, '|')) != NULL)
+       {
+               *oper_reason = '\0';
+               oper_reason++;
+
+               if(!EmptyString(oper_reason))
+                       DupString(aconf->spasswd, oper_reason);
+       }
+
+       if(tkline_time > 0)
+       {
+               ircsnprintf(buffer, sizeof(buffer),
+                          "Temporary K-line %d min. - %s (%s)",
+                          (int) (tkline_time / 60), reason, current_date);
+               DupString(aconf->passwd, buffer);
+               apply_tkline(source_p, aconf, reason, oper_reason, current_date, tkline_time);
+       }
+       else
+       {
+               ircsnprintf(buffer, sizeof(buffer), "%s (%s)", reason, current_date);
+               DupString(aconf->passwd, buffer);
+               apply_kline(source_p, aconf, reason, oper_reason, current_date);
+       }
+
+       if(ConfigFileEntry.kline_delay)
+       {
+               if(kline_queued == 0)
+               {
+                       eventAddOnce("check_klines", check_klines_event, NULL,
+                                    ConfigFileEntry.kline_delay);
+                       kline_queued = 1;
+               }
+       }
+       else
+               check_klines();
+
+       return 0;
+}
+
+/* ms_kline()
+ *
+ *   parv[1] - server targeted at
+ *   parv[2] - tkline time (0 if perm)
+ *   parv[3] - user
+ *   parv[4] - host
+ *   parv[5] - reason
+ */
+static int
+ms_kline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       int tkline_time = atoi(parv[2]);
+
+       /* 1.5-3 and earlier contains a bug that allows remote klines to be
+        * sent with an empty reason field.  This is a protocol violation,
+        * but its not worth dropping the link over.. --anfl
+        */
+       if(parc < 6 || EmptyString(parv[5]))
+               return 0;
+
+       propagate_generic(source_p, "KLINE", parv[1], CAP_KLN,
+                       "%d %s %s :%s",
+                       tkline_time, parv[3], parv[4], parv[5]);
+
+       if(!match(parv[1], me.name))
+               return 0;
+
+       if(!IsPerson(source_p))
+               return 0;
+
+       handle_remote_kline(source_p, tkline_time, parv[3], parv[4], parv[5]);
+       return 0;
+}
+
+static int
+me_kline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       /* <tkline_time> <user> <host> :<reason> */
+       if(!IsPerson(source_p))
+               return 0;
+
+       handle_remote_kline(source_p, atoi(parv[1]), parv[2], parv[3], parv[4]);
+       return 0;
+}
+
+static void
+handle_remote_kline(struct Client *source_p, int tkline_time,
+               const char *user, const char *host, const char *kreason)
+{
+       char buffer[BUFSIZE];
+       const char *current_date;
+       char *reason = LOCAL_COPY(kreason);
+       struct ConfItem *aconf = NULL;
+       char *oper_reason;
+
+       if(!find_shared_conf(source_p->username, source_p->host,
+                               source_p->user->server, 
+                               (tkline_time > 0) ? SHARED_TKLINE : SHARED_PKLINE))
+               return;
+
+       if(!valid_user_host(source_p, user, host) ||
+          !valid_wild_card(source_p, user, host) ||
+          !valid_comment(source_p, reason))
+               return;
+
+       if(already_placed_kline(source_p, user, host, tkline_time))
+               return;
+
+       aconf = make_conf();
+
+       aconf->status = CONF_KILL;
+       DupString(aconf->user, user);
+       DupString(aconf->host, host);
+
+       /* Look for an oper reason */
+       if((oper_reason = strchr(reason, '|')) != NULL)
+       {
+               *oper_reason = '\0';
+               oper_reason++;
+
+               if(!EmptyString(oper_reason))
+                       DupString(aconf->spasswd, oper_reason);
+       }
+
+       current_date = smalldate();
+
+       if(tkline_time > 0)
+       {
+               ircsnprintf(buffer, sizeof(buffer),
+                          "Temporary K-line %d min. - %s (%s)",
+                          (int) (tkline_time / 60), reason, current_date);
+               DupString(aconf->passwd, buffer);
+               apply_tkline(source_p, aconf, reason, oper_reason, current_date, tkline_time);
+       }
+       else
+       {
+               ircsnprintf(buffer, sizeof(buffer), "%s (%s)", reason, current_date);
+               DupString(aconf->passwd, buffer);
+               apply_kline(source_p, aconf, reason, oper_reason, current_date);
+       }
+
+       if(ConfigFileEntry.kline_delay)
+       {
+               if(kline_queued == 0)
+               {
+                       eventAddOnce("check_klines", check_klines_event, NULL,
+                                    ConfigFileEntry.kline_delay);
+                       kline_queued = 1;
+               }
+       }
+       else
+               check_klines();
+
+       return;
+}
+
+/* mo_unkline()
+ *
+ *   parv[1] - kline to remove
+ *   parv[2] - optional "ON"
+ *   parv[3] - optional target server
+ */
+static int
+mo_unkline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       const char *user;
+       char *host;
+       char splat[] = "*";
+       char *h = LOCAL_COPY(parv[1]);
+
+       if(!IsOperUnkline(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS),
+                          me.name, source_p->name, "unkline");
+               return 0;
+       }
+
+       if((host = strchr(h, '@')) || *h == '*' || strchr(h, '.') || strchr(h, ':'))
+       {
+               /* Explicit user@host mask given */
+
+               if(host)        /* Found user@host */
+               {
+                       *host++ = '\0';
+
+                       /* check for @host */
+                       if(*h)
+                               user = h;
+                       else
+                               user = splat;
+
+                       /* check for user@ */
+                       if(!*host)
+                               host = splat;
+               }
+               else
+               {
+                       user = splat;   /* no @ found, assume its *@somehost */
+                       host = h;
+               }
+       }
+       else
+       {
+               sendto_one(source_p, ":%s NOTICE %s :Invalid parameters", me.name, source_p->name);
+               return 0;
+       }
+
+       /* possible remote kline.. */
+       if((parc > 3) && (irccmp(parv[2], "ON") == 0))
+       {
+               if(!IsOperRemoteBan(source_p))
+               {
+                       sendto_one(source_p, form_str(ERR_NOPRIVS),
+                               me.name, source_p->name, "remoteban");
+                       return 0;
+               }
+
+               propagate_generic(source_p, "UNKLINE", parv[3], CAP_UNKLN,
+                               "%s %s", user, host);
+
+               if(match(parv[3], me.name) == 0)
+                       return 0;
+       }
+       else if(dlink_list_length(&cluster_conf_list) > 0)
+               cluster_generic(source_p, "UNKLINE", SHARED_UNKLINE, CAP_UNKLN,
+                               "%s %s", user, host);
+
+       if(remove_temp_kline(user, host))
+       {
+               sendto_one(source_p,
+                          ":%s NOTICE %s :Un-klined [%s@%s] from temporary k-lines",
+                          me.name, parv[0], user, host);
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "%s has removed the temporary K-Line for: [%s@%s]",
+                                    get_oper_name(source_p), user, host);
+               ilog(L_KLINE, "UK %s %s %s",
+                       get_oper_name(source_p), user, host);
+               return 0;
+       }
+
+       remove_permkline_match(source_p, host, user);
+
+       return 0;
+}
+
+/* ms_unkline()
+ *
+ *   parv[1] - target server
+ *   parv[2] - user to unkline
+ *   parv[3] - host to unkline
+ */
+static int
+ms_unkline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       /* parv[0]  parv[1]        parv[2]  parv[3]
+        * oper     target server  user     host    */
+       propagate_generic(source_p, "UNKLINE", parv[1], CAP_UNKLN,
+                       "%s %s", parv[2], parv[3]);
+
+       if(!match(parv[1], me.name))
+               return 0;
+
+       if(!IsPerson(source_p))
+               return 0;
+
+       handle_remote_unkline(source_p, parv[2], parv[3]);
+       return 0;
+}
+
+static int
+me_unkline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       /* user host */
+       if(!IsPerson(source_p))
+               return 0;
+
+       handle_remote_unkline(source_p, parv[1], parv[2]);
+       return 0;
+}
+
+static void
+handle_remote_unkline(struct Client *source_p, const char *user, const char *host)
+{
+       if(!find_shared_conf(source_p->username, source_p->host,
+                               source_p->user->server, SHARED_UNKLINE))
+               return;
+
+       if(remove_temp_kline(user, host))
+       {
+               sendto_one_notice(source_p,
+                               ":Un-klined [%s@%s] from temporary k-lines",
+                               user, host);
+
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                               "%s has removed the temporary K-Line for: [%s@%s]",
+                               get_oper_name(source_p), user, host);
+
+               ilog(L_KLINE, "UK %s %s %s",
+                       get_oper_name(source_p), user, host);
+               return;
+       }
+
+       remove_permkline_match(source_p, host, user);
+}
+
+/* apply_kline()
+ *
+ * inputs      - 
+ * output      - NONE
+ * side effects        - kline as given, is added to the hashtable
+ *               and conf file
+ */
+static void
+apply_kline(struct Client *source_p, struct ConfItem *aconf,
+           const char *reason, const char *oper_reason, const char *current_date)
+{
+       add_conf_by_address(aconf->host, CONF_KILL, aconf->user, aconf);
+       write_confitem(KLINE_TYPE, source_p, aconf->user, aconf->host,
+                      reason, oper_reason, current_date, 0);
+}
+
+/* apply_tkline()
+ *
+ * inputs      -
+ * output      - NONE
+ * side effects        - tkline as given is placed
+ */
+static void
+apply_tkline(struct Client *source_p, struct ConfItem *aconf,
+            const char *reason, const char *oper_reason, const char *current_date, int tkline_time)
+{
+       aconf->hold = CurrentTime + tkline_time;
+       add_temp_kline(aconf);
+
+       /* no oper reason.. */
+       if(EmptyString(oper_reason))
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "%s added temporary %d min. K-Line for [%s@%s] [%s]",
+                                    get_oper_name(source_p), tkline_time / 60,
+                                    aconf->user, aconf->host, reason);
+               ilog(L_KLINE, "K %s %d %s %s %s",
+                       get_oper_name(source_p), tkline_time / 60,
+                       aconf->user, aconf->host, reason);
+       }
+       else
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "%s added temporary %d min. K-Line for [%s@%s] [%s|%s]",
+                                    get_oper_name(source_p), tkline_time / 60,
+                                    aconf->user, aconf->host, reason, oper_reason);
+               ilog(L_KLINE, "K %s %d %s %s %s|%s",
+                       get_oper_name(source_p), tkline_time / 60,
+                       aconf->user, aconf->host, reason, oper_reason);
+       }
+
+       sendto_one_notice(source_p, ":Added temporary %d min. K-Line [%s@%s]",
+                         tkline_time / 60, aconf->user, aconf->host);
+}
+
+/* find_user_host()
+ * 
+ * inputs      - client placing kline, user@host, user buffer, host buffer
+ * output      - 0 if not ok to kline, 1 to kline i.e. if valid user host
+ * side effects -
+ */
+static int
+find_user_host(struct Client *source_p, const char *userhost, char *luser, char *lhost)
+{
+       char *hostp;
+
+       hostp = strchr(userhost, '@');
+       
+       if(hostp != NULL)       /* I'm a little user@host */
+       {
+               *(hostp++) = '\0';      /* short and squat */
+               if(*userhost)
+                       strlcpy(luser, userhost, USERLEN + 1);  /* here is my user */
+               else
+                       strcpy(luser, "*");
+               if(*hostp)
+                       strlcpy(lhost, hostp, HOSTLEN + 1);     /* here is my host */
+               else
+                       strcpy(lhost, "*");
+               }
+       else
+       {
+               /* no '@', no '.', so its not a user@host or host, therefore
+                * its a nick, which support was removed for.
+                */
+               if(strchr(userhost, '.') == NULL && strchr(userhost, ':') == NULL)
+                       return 0;
+
+               luser[0] = '*'; /* no @ found, assume its *@somehost */
+               luser[1] = '\0';
+               strlcpy(lhost, userhost, HOSTLEN + 1);
+       }
+
+       return 1;
+}
+
+/* valid_user_host()
+ *
+ * inputs       - user buffer, host buffer
+ * output      - 0 if invalid, 1 if valid
+ * side effects -
+ */
+static int
+valid_user_host(struct Client *source_p, const char *luser, const char *lhost)
+{
+       /* # is invalid, as is '!' (n!u@h kline) */
+       if(strchr(lhost, '#') || strchr(luser, '#') || strchr(luser, '!'))
+       {
+               sendto_one_notice(source_p, ":Invalid K-Line");
+               return 0;
+       }
+
+       return 1;
+}
+
+/* valid_wild_card()
+ * 
+ * input        - user buffer, host buffer
+ * output       - 0 if invalid, 1 if valid
+ * side effects -
+ */
+static int
+valid_wild_card(struct Client *source_p, const char *luser, const char *lhost)
+{
+       const char *p;
+       char tmpch;
+       int nonwild = 0;
+
+       /* check there are enough non wildcard chars */
+       p = luser;
+       while ((tmpch = *p++))
+       {
+               if(!IsKWildChar(tmpch))
+               {
+                       /* found enough chars, return */
+                       if(++nonwild >= ConfigFileEntry.min_nonwildcard)
+                               return 1;
+               }
+       }
+
+       /* try host, as user didnt contain enough */
+       p = lhost;
+       while ((tmpch = *p++))
+       {
+               if(!IsKWildChar(tmpch))
+                       if(++nonwild >= ConfigFileEntry.min_nonwildcard)
+                               return 1;
+       }
+
+       sendto_one_notice(source_p,
+                         ":Please include at least %d non-wildcard "
+                         "characters with the user@host",
+                         ConfigFileEntry.min_nonwildcard);
+       return 0;
+}
+
+/*
+ * valid_comment
+ * inputs      - pointer to client
+ *              - pointer to comment
+ * output       - 0 if no valid comment, 1 if valid
+ * side effects - NONE
+ */
+static int
+valid_comment(struct Client *source_p, char *comment)
+{
+       if(strchr(comment, '"'))
+       {
+               sendto_one_notice(source_p, ":Invalid character '\"' in comment");
+               return 0;
+       }
+
+       if(strlen(comment) > REASONLEN)
+               comment[REASONLEN] = '\0';
+
+       return 1;
+}
+
+/* already_placed_kline()
+ *
+ * inputs       - source to notify, user@host to check, tkline time
+ * outputs      - 1 if a perm kline or a tkline when a tkline is being
+ *                set exists, else 0
+ * side effects - notifies source_p kline exists
+ */
+/* Note: This currently works if the new K-line is a special case of an
+ *       existing K-line, but not the other way round. To do that we would
+ *       have to walk the hash and check every existing K-line. -A1kmm.
+ */
+static int
+already_placed_kline(struct Client *source_p, const char *luser, const char *lhost, int tkline)
+{
+       const char *reason;
+       struct irc_sockaddr_storage iphost, *piphost;
+       struct ConfItem *aconf;
+        int t;
+       if(ConfigFileEntry.non_redundant_klines)
+       {
+               if((t = parse_netmask(lhost, (struct sockaddr *)&iphost, NULL)) != HM_HOST)
+               {
+#ifdef IPV6
+                       if(t == HM_IPV6)
+                               t = AF_INET6;
+                       else
+#endif
+                               t = AF_INET;
+                               
+                       piphost = &iphost;
+               }
+               else
+                       piphost = NULL;
+
+               if((aconf = find_conf_by_address(lhost, NULL, NULL, (struct sockaddr *)piphost, CONF_KILL, t, luser)))
+               {
+                       /* setting a tkline, or existing one is perm */
+                       if(tkline || ((aconf->flags & CONF_FLAGS_TEMPORARY) == 0))
+                       {
+                               reason = aconf->passwd ? aconf->passwd : "<No Reason>";
+
+                               sendto_one_notice(source_p,
+                                                 ":[%s@%s] already K-Lined by [%s@%s] - %s",
+                                                 luser, lhost, aconf->user,
+                                                 aconf->host, reason);
+                               return 1;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+/* remove_permkline_match()
+ *
+ * hunts for a permanent kline, and removes it.
+ */
+static void
+remove_permkline_match(struct Client *source_p, const char *host, const char *user)
+{
+       FILE *in, *out;
+       int pairme = 0;
+       int error_on_write = NO;
+       char buf[BUFSIZE];
+       char matchbuf[BUFSIZE];
+       char temppath[BUFSIZE];
+       const char *filename;
+       mode_t oldumask;
+       int matchlen;
+
+       ircsnprintf(temppath, sizeof(temppath),
+                "%s.tmp", ConfigFileEntry.klinefile);
+
+       filename = get_conf_name(KLINE_TYPE);
+
+       if((in = fopen(filename, "r")) == 0)
+       {
+               sendto_one_notice(source_p, ":Cannot open %s", filename);
+               return;
+       }
+
+       oldumask = umask(0);
+       if((out = fopen(temppath, "w")) == 0)
+       {
+               sendto_one_notice(source_p, ":Cannot open %s", temppath);
+               fclose(in);
+               umask(oldumask);
+               return;
+       }
+
+       umask(oldumask);
+
+       snprintf(matchbuf, sizeof(matchbuf), "\"%s\",\"%s\"", user, host);
+       matchlen = strlen(matchbuf);
+
+       while (fgets(buf, sizeof(buf), in))
+       {
+               if(error_on_write)
+                       break;
+
+               if(!strncasecmp(buf, matchbuf, matchlen))
+               {
+                       pairme++;
+                       break;
+               }
+               else
+                       error_on_write = flush_write(source_p, out, buf, temppath);
+       }
+
+       /* we dropped out of the loop early because we found a match,
+        * to drop into this somewhat faster loop as we presume we'll never
+        * have two matching klines --anfl
+        */
+       if(pairme && !error_on_write)
+       {
+               while(fgets(buf, sizeof(buf), in))
+               {
+                       if(error_on_write)
+                               break;
+
+                       error_on_write = flush_write(source_p, out, buf, temppath);
+               }
+       }
+
+       fclose(in);
+       if (fclose(out))
+               error_on_write = YES;
+
+       /* The result of the rename should be checked too... oh well */
+       /* If there was an error on a write above, then its been reported
+        * and I am not going to trash the original kline /conf file
+        */
+       if(error_on_write)
+       {
+               sendto_one_notice(source_p, ":Couldn't write temp kline file, aborted");
+               return;
+       }
+       else if(!pairme)
+       {
+               sendto_one_notice(source_p, ":No K-Line for %s@%s",
+                                 user, host);
+
+               if(temppath != NULL)
+                       (void) unlink(temppath);
+
+               return;
+       }
+               
+       if (rename(temppath, filename))
+       {
+               sendto_one_notice(source_p, ":Couldn't rename temp file, aborted");
+               return;
+       }
+       rehash_bans(0);
+
+       sendto_one_notice(source_p, ":K-Line for [%s@%s] is removed",
+                         user, host);
+
+       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                            "%s has removed the K-Line for: [%s@%s]",
+                            get_oper_name(source_p), user, host);
+
+       ilog(L_KLINE, "UK %s %s %s",
+               get_oper_name(source_p), user, host);
+       return;
+}
+
+/*
+ * flush_write()
+ *
+ * inputs       - pointer to client structure of oper requesting unkline
+ *              - out is the file descriptor
+ *              - buf is the buffer to write
+ *              - ntowrite is the expected number of character to be written
+ *              - temppath is the temporary file name to be written
+ * output       - YES for error on write
+ *              - NO for success
+ * side effects - if successful, the buf is written to output file
+ *                if a write failure happesn, and the file pointed to
+ *                by temppath, if its non NULL, is removed.
+ *
+ * The idea here is, to be as robust as possible when writing to the 
+ * kline file.
+ *
+ * -Dianora
+ */
+
+static int
+flush_write(struct Client *source_p, FILE * out, const char *buf, const char *temppath)
+{
+       int error_on_write = (fputs(buf, out) < 0) ? YES : NO;
+
+       if(error_on_write)
+       {
+               sendto_one_notice(source_p, ":Unable to write to %s",
+                                 temppath);
+               if(temppath != NULL)
+                       (void) unlink(temppath);
+       }
+       return (error_on_write);
+}
+
+/* remove_temp_kline()
+ *
+ * inputs       - username, hostname to unkline
+ * outputs      -
+ * side effects - tries to unkline anything that matches
+ */
+static int
+remove_temp_kline(const char *user, const char *host)
+{
+       struct ConfItem *aconf;
+       dlink_node *ptr;
+       struct irc_sockaddr_storage addr, caddr;
+       int bits, cbits;
+       int mtype, ktype;
+       int i;
+
+       mtype = parse_netmask(host, (struct sockaddr *)&addr, &bits);
+
+       for (i = 0; i < LAST_TEMP_TYPE; i++)
+       {
+               DLINK_FOREACH(ptr, temp_klines[i].head)
+               {
+                       aconf = ptr->data;
+
+                       ktype = parse_netmask(aconf->host, (struct sockaddr *)&caddr, &cbits);
+
+                       if(ktype != mtype || (user && irccmp(user, aconf->user)))
+                               continue;
+
+                       if(ktype == HM_HOST)
+                       {
+                               if(irccmp(aconf->host, host))
+                                       continue;
+                       }
+                       else if(bits != cbits || 
+                               !comp_with_mask_sock((struct sockaddr *)&addr,
+                                               (struct sockaddr *)&caddr, bits))
+                               continue;
+
+                       dlinkDestroy(ptr, &temp_klines[i]);
+                       delete_one_address_conf(aconf->host, aconf);
+                       return YES;
+               }
+       }
+
+       return NO;
+}
diff --git a/modules/m_knock.c b/modules/m_knock.c
new file mode 100644 (file)
index 0000000..ed7c359
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_knock.c: Requests to be invited to a channel.
+ *
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_knock.c 752 2006-02-11 20:55:03Z jilles $
+ */
+
+#include "stdinc.h"
+#include "sprintf_irc.h"
+#include "tools.h"
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "s_conf.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_serv.h"
+
+static int m_knock(struct Client *, struct Client *, int, const char **);
+
+struct Message knock_msgtab = {
+       "KNOCK", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_knock, 2}, {m_knock, 2}, mg_ignore, mg_ignore, {m_knock, 2}}
+};
+
+mapi_clist_av1 knock_clist[] = { &knock_msgtab, NULL };
+DECLARE_MODULE_AV1(knock, NULL, NULL, knock_clist, NULL, NULL, "$Revision: 752 $");
+
+/* m_knock
+ *    parv[0] = sender prefix
+ *    parv[1] = channel
+ *
+ *  The KNOCK command has the following syntax:
+ *   :<sender> KNOCK <channel>
+ *
+ *  If a user is not banned from the channel they can use the KNOCK
+ *  command to have the server NOTICE the channel operators notifying
+ *  they would like to join.  Helpful if the channel is invite-only, the
+ *  key is forgotten, or the channel is full (INVITE can bypass each one
+ *  of these conditions.  Concept by Dianora <db@db.net> and written by
+ *  <anonymous>
+ */
+static int
+m_knock(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Channel *chptr;
+       char *p, *name;
+
+       if(MyClient(source_p) && ConfigChannel.use_knock == 0)
+       {
+               sendto_one(source_p, form_str(ERR_KNOCKDISABLED),
+                          me.name, source_p->name);
+               return 0;
+       }
+
+       name = LOCAL_COPY(parv[1]);
+
+       /* dont allow one knock to multiple chans */
+       if((p = strchr(name, ',')))
+               *p = '\0';
+
+       if(!IsChannelName(name))
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
+                                  form_str(ERR_NOSUCHCHANNEL), name);
+               return 0;
+       }
+
+       if((chptr = find_channel(name)) == NULL)
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
+                                  form_str(ERR_NOSUCHCHANNEL), name);
+               return 0;
+       }
+
+       if(IsMember(source_p, chptr))
+       {
+               if(MyClient(source_p))
+                       sendto_one(source_p, form_str(ERR_KNOCKONCHAN),
+                                  me.name, source_p->name, name);
+               return 0;
+       }
+
+       if(!((chptr->mode.mode & MODE_INVITEONLY) || (*chptr->mode.key) || 
+            (chptr->mode.limit && 
+             dlink_list_length(&chptr->members) >= (unsigned long)chptr->mode.limit)))
+       {
+               sendto_one_numeric(source_p, ERR_CHANOPEN,
+                                  form_str(ERR_CHANOPEN), name);
+               return 0;
+       }
+
+       /* cant knock to a +p channel */
+       if(HiddenChannel(chptr))
+       {
+               sendto_one_numeric(source_p, ERR_CANNOTSENDTOCHAN,
+                                  form_str(ERR_CANNOTSENDTOCHAN), name);
+               return 0;
+       }
+
+       
+       if(MyClient(source_p))
+       {
+               /* don't allow a knock if the user is banned */
+               if(is_banned(chptr, source_p, NULL, NULL, NULL) == CHFL_BAN ||
+                               is_quieted(chptr, source_p, NULL, NULL, NULL) == CHFL_BAN)
+               {
+                       sendto_one_numeric(source_p, ERR_CANNOTSENDTOCHAN,
+                                          form_str(ERR_CANNOTSENDTOCHAN), name);
+                       return 0;
+               }
+
+               /* local flood protection:
+                * allow one knock per user per knock_delay
+                * allow one knock per channel per knock_delay_channel
+                */
+               if(!IsOper(source_p) && 
+                  (source_p->localClient->last_knock + ConfigChannel.knock_delay) > CurrentTime)
+               {
+                       sendto_one(source_p, form_str(ERR_TOOMANYKNOCK),
+                                       me.name, source_p->name, name, "user");
+                       return 0;
+               }
+               else if((chptr->last_knock + ConfigChannel.knock_delay_channel) > CurrentTime)
+               {
+                       sendto_one(source_p, form_str(ERR_TOOMANYKNOCK),
+                                       me.name, source_p->name, name, "channel");
+                       return 0;
+               }
+
+               /* ok, we actually can send the knock, tell client */
+               source_p->localClient->last_knock = CurrentTime;
+
+               sendto_one(source_p, form_str(RPL_KNOCKDLVR),
+                          me.name, source_p->name, name);
+       }
+
+       chptr->last_knock = CurrentTime;
+
+       if(ConfigChannel.use_knock)
+               sendto_channel_local(ONLY_CHANOPS, chptr, form_str(RPL_KNOCK),
+                                    me.name, name, name, source_p->name,
+                                    source_p->username, source_p->host);
+
+       sendto_server(client_p, chptr, CAP_KNOCK|CAP_TS6, NOCAPS,
+                     ":%s KNOCK %s", use_id(source_p), name);
+       sendto_server(client_p, chptr, CAP_KNOCK, CAP_TS6,
+                     ":%s KNOCK %s", source_p->name, name);
+       return 0;
+}
+
diff --git a/modules/m_links.c b/modules/m_links.c
new file mode 100644 (file)
index 0000000..30f23e5
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_links.c: Shows what servers are currently connected.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_links.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_serv.h"
+#include "send.h"
+#include "s_conf.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "hook.h"
+#include "cache.h"
+
+static int m_links(struct Client *, struct Client *, int, const char **);
+static int mo_links(struct Client *, struct Client *, int, const char **);
+
+struct Message links_msgtab = {
+       "LINKS", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_links, 0}, {mo_links, 0}, mg_ignore, mg_ignore, {mo_links, 0}}
+};
+
+int doing_links_hook;
+
+mapi_clist_av1 links_clist[] = { &links_msgtab, NULL };
+mapi_hlist_av1 links_hlist[] = {
+       { "doing_links",        &doing_links_hook },
+       { NULL, NULL }
+};
+
+DECLARE_MODULE_AV1(links, NULL, NULL, links_clist, links_hlist, NULL, "$Revision: 254 $");
+
+static void send_links_cache(struct Client *source_p);
+
+/*
+ * m_links - LINKS message handler
+ *      parv[0] = sender prefix
+ *      parv[1] = servername mask
+ * or
+ *      parv[0] = sender prefix
+ *      parv[1] = server to query 
+ *      parv[2] = servername mask
+ */
+static int
+m_links(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       if(ConfigServerHide.flatten_links && !IsExemptShide(source_p))
+               send_links_cache(source_p);
+       else
+               mo_links(client_p, source_p, parc, parv);
+
+       return 0;
+}
+
+static int
+mo_links(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       const char *mask = "";
+       struct Client *target_p;
+       char clean_mask[2 * HOSTLEN + 4];
+       hook_data hd;
+
+       dlink_node *ptr;
+
+       if(parc > 2)
+       {
+               if(hunt_server(client_p, source_p, ":%s LINKS %s :%s", 1, parc, parv)
+                  != HUNTED_ISME)
+                       return 0;
+
+               mask = parv[2];
+       }
+       else if(parc == 2)
+               mask = parv[1];
+
+       if(*mask)               /* only necessary if there is a mask */
+               mask = collapse(clean_string
+                               (clean_mask, (const unsigned char *) mask, 2 * HOSTLEN));
+
+       hd.client = source_p;
+       hd.arg1 = mask;
+       hd.arg2 = NULL;
+
+       call_hook(doing_links_hook, &hd);
+
+       DLINK_FOREACH(ptr, global_serv_list.head)
+       {
+               target_p = ptr->data;
+
+               if(*mask && !match(mask, target_p->name))
+                       continue;
+
+               /* We just send the reply, as if theyre here theres either no SHIDE,
+                * or theyre an oper..  
+                */
+               sendto_one_numeric(source_p, RPL_LINKS, form_str(RPL_LINKS),
+                                  target_p->name, target_p->serv->up,
+                                  target_p->hopcount,
+                                  target_p->info[0] ? target_p->info : "(Unknown Location)");
+       }
+
+       sendto_one_numeric(source_p, RPL_ENDOFLINKS, form_str(RPL_ENDOFLINKS),
+                          EmptyString(mask) ? "*" : mask);
+
+       return 0;
+}
+
+/* send_links_cache()
+ *
+ * inputs      - client to send to
+ * outputs     - the cached links, us, and RPL_ENDOFLINKS
+ * side effects        -
+ */
+static void
+send_links_cache(struct Client *source_p)
+{
+       dlink_node *ptr;
+
+       DLINK_FOREACH(ptr, links_cache_list.head)
+       {
+               sendto_one(source_p, ":%s 364 %s %s",
+                          me.name, source_p->name, (const char *)ptr->data);
+       }
+
+       sendto_one_numeric(source_p, RPL_LINKS, form_str(RPL_LINKS), 
+                          me.name, me.name, 0, me.info);
+
+       sendto_one_numeric(source_p, RPL_ENDOFLINKS, form_str(RPL_ENDOFLINKS), "*");
+}
+
diff --git a/modules/m_list_ratbox.c b/modules/m_list_ratbox.c
new file mode 100644 (file)
index 0000000..be8eb26
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_list.c: Shows what servers are currently connected.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_list_ratbox.c 722 2006-02-08 21:51:28Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_conf.h"
+#include "s_serv.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "linebuf.h"
+
+static int m_list(struct Client *, struct Client *, int, const char **);
+static int mo_list(struct Client *, struct Client *, int, const char **);
+
+struct Message list_msgtab = {
+       "LIST", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_list, 0}, mg_ignore, mg_ignore, mg_ignore, {mo_list, 0}}
+};
+
+mapi_clist_av1 list_clist[] = { &list_msgtab, NULL };
+DECLARE_MODULE_AV1(list, NULL, NULL, list_clist, NULL, NULL, "$Revision: 722 $");
+
+static void list_all_channels(struct Client *source_p);
+static void list_limit_channels(struct Client *source_p, const char *param);
+static void list_named_channel(struct Client *source_p, const char *name);
+
+/* m_list()
+ *      parv[0] = sender prefix
+ *      parv[1] = channel
+ */
+static int
+m_list(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       static time_t last_used = 0L;
+
+       /* pace this due to the sheer traffic involved */
+       if(((last_used + ConfigFileEntry.pace_wait) > CurrentTime))
+       {
+               sendto_one(source_p, form_str(RPL_LOAD2HI),
+                          me.name, source_p->name, "LIST");
+               sendto_one(source_p, form_str(RPL_LISTEND), me.name, source_p->name);
+               return 0;
+       }
+       else
+               last_used = CurrentTime;
+
+       /* If no arg, do all channels *whee*, else just one channel */
+       if(parc < 2 || EmptyString(parv[1]))
+               list_all_channels(source_p);
+       else if(IsChannelName(parv[1]))
+               list_named_channel(source_p, parv[1]);
+       else
+               list_limit_channels(source_p, parv[1]);
+
+       return 0;
+}
+
+/* mo_list()
+ *      parv[0] = sender prefix
+ *      parv[1] = channel
+ */
+static int
+mo_list(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       /* If no arg, do all channels *whee*, else just one channel */
+       if(parc < 2 || EmptyString(parv[1]))
+               list_all_channels(source_p);
+       else if(IsChannelName(parv[1]))
+               list_named_channel(source_p, parv[1]);
+       else
+               list_limit_channels(source_p, parv[1]);
+
+       return 0;
+}
+
+/* list_all_channels()
+ *
+ * inputs      - pointer to client requesting list
+ * output      -
+ * side effects        - list all channels to source_p
+ */
+static void
+list_all_channels(struct Client *source_p)
+{
+       struct Channel *chptr;
+       dlink_node *ptr;
+       int sendq_limit;
+
+       /* give them an output limit of 90% of their sendq. --fl */
+       sendq_limit = (int) get_sendq(source_p);
+       sendq_limit /= 10;
+       sendq_limit *= 9;
+
+       sendto_one(source_p, form_str(RPL_LISTSTART), me.name, source_p->name);
+
+       DLINK_FOREACH(ptr, global_channel_list.head)
+       {
+               chptr = ptr->data;
+
+               /* if theyre overflowing their sendq, stop. --fl */
+               if(linebuf_len(&source_p->localClient->buf_sendq) > sendq_limit)
+               {
+                       sendto_one(source_p, form_str(ERR_TOOMANYMATCHES),
+                                  me.name, source_p->name, "LIST");
+                       break;
+               }
+
+               if(SecretChannel(chptr) && !IsMember(source_p, chptr))
+                       continue;
+
+               sendto_one(source_p, form_str(RPL_LIST), 
+                          me.name, source_p->name, chptr->chname, 
+                          dlink_list_length(&chptr->members), 
+                          chptr->topic == NULL ? "" : chptr->topic);
+       }
+
+       sendto_one(source_p, form_str(RPL_LISTEND), me.name, source_p->name);
+       return;
+}
+
+static void
+list_limit_channels(struct Client *source_p, const char *param)
+{
+       struct Channel *chptr;
+       char *args;
+       char *p;
+       dlink_node *ptr;
+       unsigned int sendq_limit;
+       int max = INT_MAX;
+       int min = 0;
+       int i;
+
+       args = LOCAL_COPY(param);
+
+       for(i = 0; i < 2; i++)
+       {
+               if((p = strchr(args, ',')) != NULL)
+                       *p++ = '\0';
+
+               if(*args == '<')
+               {
+                       args++;
+                       if((max = atoi(args)) <= 0)
+                               max = INT_MAX;
+               }
+               else if(*args == '>')
+               {
+                       args++;
+                       if((min = atoi(args)) < 0)
+                               min = 0;
+               }
+
+               if(EmptyString(p))
+                       break;
+               else
+                       args = p;
+       }
+
+       /* give them an output limit of 90% of their sendq. --fl */
+       sendq_limit = (unsigned int) get_sendq(source_p);
+       sendq_limit /= 10;
+       sendq_limit *= 9;
+
+       sendto_one(source_p, form_str(RPL_LISTSTART), me.name, source_p->name);
+
+       DLINK_FOREACH(ptr, global_channel_list.head)
+       {
+               chptr = ptr->data;
+
+               /* if theyre overflowing their sendq, stop. --fl */
+               if(linebuf_len(&source_p->localClient->buf_sendq) > sendq_limit)
+               {
+                       sendto_one(source_p, form_str(ERR_TOOMANYMATCHES),
+                                  me.name, source_p->name, "LIST");
+                       break;
+               }
+
+               if(dlink_list_length(&chptr->members) >= max ||
+                  dlink_list_length(&chptr->members) <= min)
+                       continue;
+
+               if(SecretChannel(chptr) && !IsMember(source_p, chptr))
+                       continue;
+
+               sendto_one(source_p, form_str(RPL_LIST), 
+                          me.name, source_p->name, chptr->chname, 
+                          dlink_list_length(&chptr->members), 
+                          chptr->topic == NULL ? "" : chptr->topic);
+       }
+
+       sendto_one(source_p, form_str(RPL_LISTEND), me.name, source_p->name);
+       return;
+}
+
+
+/* list_named_channel()
+ * 
+ * inputs       - pointer to client requesting list
+ * output       -
+ * side effects        - list single channel to source
+ */
+static void
+list_named_channel(struct Client *source_p, const char *name)
+{
+       struct Channel *chptr;
+       char *p;
+       char *n = LOCAL_COPY(name);
+
+       sendto_one(source_p, form_str(RPL_LISTSTART), me.name, source_p->name);
+
+       if((p = strchr(n, ',')))
+               *p = '\0';
+
+       if(*n == '\0')
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHNICK, 
+                                  form_str(ERR_NOSUCHNICK), name);
+               sendto_one(source_p, form_str(RPL_LISTEND), me.name, source_p->name);
+               return;
+       }
+
+       chptr = find_channel(n);
+
+       if(chptr == NULL)
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHNICK,
+                                  form_str(ERR_NOSUCHNICK), n);
+               sendto_one(source_p, form_str(RPL_LISTEND), me.name, source_p->name);
+               return;
+       }
+
+       if(ShowChannel(source_p, chptr))
+               sendto_one(source_p, form_str(RPL_LIST),
+                          me.name, source_p->name, chptr->chname, 
+                          dlink_list_length(&chptr->members),
+                          chptr->topic == NULL ? "" : chptr->topic);
+
+       sendto_one(source_p, form_str(RPL_LISTEND), me.name, source_p->name);
+       return;
+}
diff --git a/modules/m_list_safelist.c b/modules/m_list_safelist.c
new file mode 100644 (file)
index 0000000..9b411cd
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ * charybdis: An advanced ircd.
+ * m_list_safelist.c: Version of /list that uses the safelist code.
+ *
+ * Copyright (c) 2006 William Pitcock <nenolod@nenolod.net>
+ *
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: m_list_safelist.c 1393 2006-05-20 19:28:16Z jilles $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_conf.h"
+#include "s_serv.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "event.h"
+
+static dlink_list safelisting_clients = { NULL, NULL, 0 };
+
+static int _modinit(void);
+static void _moddeinit(void);
+
+static int m_list(struct Client *, struct Client *, int, const char **);
+static int mo_list(struct Client *, struct Client *, int, const char **);
+
+static void safelist_check_cliexit(hook_data_client_exit * hdata);
+static void safelist_client_instantiate(struct Client *, struct ListClient *);
+static void safelist_client_release(struct Client *);
+static void safelist_one_channel(struct Client *source_p, struct Channel *chptr);
+static void safelist_iterate_client(struct Client *source_p);
+static void safelist_iterate_clients(void *unused);
+static void safelist_channel_named(struct Client *source_p, const char *name);
+
+struct Message list_msgtab = {
+       "LIST", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_list, 0}, mg_ignore, mg_ignore, mg_ignore, {mo_list, 0}}
+};
+
+mapi_clist_av1 list_clist[] = { &list_msgtab, NULL };
+
+mapi_hfn_list_av1 list_hfnlist[] = {
+       {"client_exit", (hookfn) safelist_check_cliexit},
+       {NULL, NULL}
+};
+
+DECLARE_MODULE_AV1(list, _modinit, _moddeinit, list_clist, NULL, list_hfnlist, "$Revision: 1393 $");
+
+static int _modinit(void)
+{
+       eventAdd("safelist_iterate_clients", safelist_iterate_clients, NULL, 3);
+
+       return 0;
+}
+
+static void _moddeinit(void)
+{
+       eventDelete(safelist_iterate_clients, NULL);
+}
+
+static void safelist_check_cliexit(hook_data_client_exit * hdata)
+{
+       /* Cancel the safelist request if we are disconnecting
+        * from the server. That way it doesn't core. :P --nenolod
+        */
+       if (MyClient(hdata->target) && hdata->target->localClient->safelist_data != NULL)
+       {
+               safelist_client_release(hdata->target);
+       }
+}
+
+/* m_list()
+ *      parv[0] = sender prefix
+ *      parv[1] = channel
+ *
+ * XXX - With SAFELIST, do we really need to continue pacing?
+ *       In theory, the server cannot be lagged by this. --nenolod
+ */
+static int m_list(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       static time_t last_used = 0L;
+
+       if (source_p->localClient->safelist_data != NULL)
+       {
+               sendto_one_notice(source_p, ":/LIST aborted");
+               sendto_one(source_p, form_str(RPL_LISTEND), me.name, source_p->name);
+               safelist_client_release(source_p);
+               return 0;
+       }
+
+       if (parc < 2 || !IsChannelName(parv[1]))
+       {
+               /* pace this due to the sheer traffic involved */
+               if (((last_used + ConfigFileEntry.pace_wait) > CurrentTime))
+               {
+                       sendto_one(source_p, form_str(RPL_LOAD2HI), me.name, source_p->name, "LIST");
+                       sendto_one(source_p, form_str(RPL_LISTEND), me.name, source_p->name);
+                       return 0;
+               }
+               else
+                       last_used = CurrentTime;
+       }
+
+       return mo_list(client_p, source_p, parc, parv);
+}
+
+/* mo_list()
+ *      parv[0] = sender prefix
+ *      parv[1] = channel
+ */
+static int mo_list(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct ListClient params;
+       char *p, *args;
+       int i;
+
+       if (source_p->localClient->safelist_data != NULL)
+       {
+               sendto_one_notice(source_p, ":/LIST aborted");
+               sendto_one(source_p, form_str(RPL_LISTEND), me.name, source_p->name);
+               safelist_client_release(source_p);
+               return 0;
+       }
+
+       /* XXX rather arbitrary -- jilles */
+       params.users_min = 3;
+       params.users_max = INT_MAX;
+
+       if (parc > 1 && parv[1] != NULL && !IsChannelName(parv[1]))
+       {
+               args = LOCAL_COPY(parv[1]);
+               /* Make any specification cancel out defaults */
+               if (*args == '<')
+                       params.users_min = 0;
+
+               for (i = 0; i < 2; i++)
+               {
+                       if ((p = strchr(args, ',')) != NULL)
+                               *p++ = '\0';
+
+                       if (*args == '<')
+                       {
+                               args++;
+                               if (IsDigit(*args))
+                               {
+                                       params.users_max = atoi(args);
+                                       if (params.users_max == 0)
+                                               params.users_max = INT_MAX;
+                                       else
+                                               params.users_max--;
+                               }
+                               else
+                                       params.users_max = INT_MAX;
+                       }
+                       else if (*args == '>')
+                       {
+                               args++;
+                               if (IsDigit(*args))
+                                       params.users_min = atoi(args) + 1;
+                               else
+                                       params.users_min = 0;
+                       }
+
+                       if (EmptyString(p))
+                               break;
+                       else
+                               args = p;
+               }
+       }
+       else if (parc > 1 && IsChannelName(parv[1]))
+       {
+               safelist_channel_named(source_p, parv[1]);
+               return 0;
+       }
+
+       safelist_client_instantiate(source_p, &params);
+
+       return 0;
+}
+
+/*
+ * safelist_sendq_exceeded()
+ *
+ * inputs       - pointer to client that needs checking
+ * outputs      - 1 if a client has exceeded the reserved
+ *                sendq limit, 0 if not
+ * side effects - none
+ *
+ * When safelisting, we only use half of the SendQ at any
+ * given time.
+ */
+static int safelist_sendq_exceeded(struct Client *client_p)
+{
+       if (linebuf_len(&client_p->localClient->buf_sendq) > (get_sendq(client_p) / 2))
+               return YES;
+       else
+               return NO;
+}
+
+/*
+ * safelist_client_instantiate()
+ *
+ * inputs       - pointer to Client to be listed,
+ *                struct ListClient to copy for params
+ * outputs      - none
+ * side effects - the safelist process begins for a
+ *                client.
+ *
+ * Please do not ever call this on a non-local client.
+ * If you do, you will get SIGSEGV.
+ */
+static void safelist_client_instantiate(struct Client *client_p, struct ListClient *params)
+{
+       struct ListClient *self;
+
+       s_assert(MyClient(client_p));
+       s_assert(params != NULL);
+
+       self = MyMalloc(sizeof(struct ListClient));
+
+       self->hash_indice = 0;
+       self->users_min = params->users_min;
+       self->users_max = params->users_max;
+
+       client_p->localClient->safelist_data = self;
+
+       sendto_one(client_p, form_str(RPL_LISTSTART), me.name, client_p->name);
+
+       /* pop the client onto the queue for processing */
+       dlinkAddAlloc(client_p, &safelisting_clients);
+
+       /* give the user some initial data to work with */
+       safelist_iterate_client(client_p);
+}
+
+/*
+ * safelist_client_release()
+ *
+ * inputs       - pointer to Client being listed on
+ * outputs      - none
+ * side effects - the client is no longer being
+ *                listed
+ *
+ * Please do not ever call this on a non-local client.
+ * If you do, you will get SIGSEGV.
+ */
+static void safelist_client_release(struct Client *client_p)
+{
+       s_assert(MyClient(client_p));
+
+       dlinkFindDestroy(client_p, &safelisting_clients);
+
+       MyFree(client_p->localClient->safelist_data);
+
+       client_p->localClient->safelist_data = NULL;
+
+       sendto_one(client_p, form_str(RPL_LISTEND), me.name, client_p->name);
+}
+
+/*
+ * safelist_channel_named()
+ *
+ * inputs       - client pointer, channel name
+ * outputs      - none
+ * side effects - a named channel is listed
+ */
+static void safelist_channel_named(struct Client *source_p, const char *name)
+{
+       struct Channel *chptr;
+       char *p;
+       char *n = LOCAL_COPY(name);
+
+       sendto_one(source_p, form_str(RPL_LISTSTART), me.name, source_p->name);
+
+       if ((p = strchr(n, ',')))
+               *p = '\0';
+
+       if (*n == '\0')
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), name);
+               sendto_one(source_p, form_str(RPL_LISTEND), me.name, source_p->name);
+               return;
+       }
+
+       chptr = find_channel(n);
+
+       if (chptr == NULL)
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), n);
+               sendto_one(source_p, form_str(RPL_LISTEND), me.name, source_p->name);
+               return;
+       }
+
+       if (ShowChannel(source_p, chptr))
+               sendto_one(source_p, form_str(RPL_LIST), me.name, source_p->name, chptr->chname,
+                          dlink_list_length(&chptr->members),
+                          chptr->topic == NULL ? "" : chptr->topic);
+
+       sendto_one(source_p, form_str(RPL_LISTEND), me.name, source_p->name);
+       return;
+}
+
+/*
+ * safelist_one_channel()
+ *
+ * inputs       - client pointer and channel pointer
+ * outputs      - none
+ * side effects - a channel is listed if it meets the
+ *                requirements
+ */
+static void safelist_one_channel(struct Client *source_p, struct Channel *chptr)
+{
+       struct ListClient *safelist_data = source_p->localClient->safelist_data;
+
+       if (SecretChannel(chptr) && !IsMember(source_p, chptr))
+               return;
+
+       if ((unsigned int)chptr->members.length < safelist_data->users_min
+           || (unsigned int)chptr->members.length > safelist_data->users_max)
+               return;
+
+       sendto_one(source_p, form_str(RPL_LIST), me.name, source_p->name, chptr->chname,
+                  chptr->members.length, chptr->topic == NULL ? "" : chptr->topic);
+}
+
+/*
+ * safelist_iterate_client()
+ *
+ * inputs       - client pointer
+ * outputs      - none
+ * side effects - the client's sendq is filled up again
+ */
+static void safelist_iterate_client(struct Client *source_p)
+{
+       dlink_node *ptr;
+       int iter;
+
+       for (iter = source_p->localClient->safelist_data->hash_indice; iter < CH_MAX; iter++)
+       {
+               if (safelist_sendq_exceeded(source_p->from) == YES)
+               {
+                       source_p->localClient->safelist_data->hash_indice = iter;
+                       return;
+               }
+
+               DLINK_FOREACH(ptr, channelTable[iter].head) 
+                       safelist_one_channel(source_p, (struct Channel *) ptr->data);
+       }
+
+       safelist_client_release(source_p);
+}
+
+static void safelist_iterate_clients(void *unused)
+{
+       dlink_node *n, *n2;
+
+       DLINK_FOREACH_SAFE(n, n2, safelisting_clients.head) 
+               safelist_iterate_client((struct Client *)n->data);
+}
diff --git a/modules/m_locops.c b/modules/m_locops.c
new file mode 100644 (file)
index 0000000..bd2a175
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_locops.c: Sends a message to all operators on the local server.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_locops.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "ircd.h"
+#include "irc_string.h"
+#include "numeric.h"
+#include "send.h"
+#include "s_user.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "hash.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_serv.h"
+
+static int m_locops(struct Client *, struct Client *, int, const char **);
+static int ms_locops(struct Client *, struct Client *, int, const char **);
+static int me_locops(struct Client *, struct Client *, int, const char **);
+
+struct Message locops_msgtab = {
+       "LOCOPS", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, {ms_locops, 3}, mg_ignore, {me_locops, 2}, {m_locops, 2}}
+};
+
+mapi_clist_av1 locops_clist[] = { &locops_msgtab, NULL };
+DECLARE_MODULE_AV1(locops, NULL, NULL, locops_clist, NULL, NULL, "$Revision: 254 $");
+
+/*
+ * m_locops - LOCOPS message handler
+ * (write to *all* local opers currently online)
+ *      parv[0] = sender prefix
+ *      parv[1] = message text
+ */
+static int
+m_locops(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       sendto_wallops_flags(UMODE_LOCOPS, source_p, "LOCOPS - %s", parv[1]);
+       
+       if(dlink_list_length(&cluster_conf_list) > 0)
+               cluster_generic(source_p, "LOCOPS", SHARED_LOCOPS, CAP_CLUSTER,
+                               ":%s", parv[1]);
+
+       return 0;
+}
+
+static int
+ms_locops(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       /* parv[0]  parv[1]      parv[2]
+        * oper     target serv  message
+        */
+       propagate_generic(source_p, "LOCOPS", parv[1], CAP_CLUSTER, 
+                               ":%s", parv[2]);
+
+       if(!match(parv[1], me.name))
+               return 0;
+
+       if(find_shared_conf("*", "*", source_p->user->server, SHARED_LOCOPS))
+               sendto_wallops_flags(UMODE_LOCOPS, source_p, "SLOCOPS - %s", parv[2]);
+
+       return 0;
+}
+
+static int
+me_locops(struct Client *client_p, struct Client *source_p,
+               int parc, const char *parv[])
+{
+       if(!IsPerson(source_p))
+               return 0;
+
+       if(find_shared_conf("*", "*", source_p->user->server, SHARED_LOCOPS))
+               sendto_wallops_flags(UMODE_LOCOPS, source_p, "SLOCOPS - %s", parv[1]);
+
+       return 0;
+}
+
diff --git a/modules/m_lusers.c b/modules/m_lusers.c
new file mode 100644 (file)
index 0000000..f819dbe
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_lusers.c: Sends user statistics.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_lusers.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_serv.h"            /* hunt_server */
+#include "s_user.h"            /* show_lusers */
+#include "send.h"
+#include "s_conf.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+
+static int m_lusers(struct Client *, struct Client *, int, const char **);
+static int ms_lusers(struct Client *, struct Client *, int, const char **);
+
+struct Message lusers_msgtab = {
+       "LUSERS", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_lusers, 0}, {ms_lusers, 0}, mg_ignore, mg_ignore, {ms_lusers, 0}}
+};
+
+mapi_clist_av1 lusers_clist[] = { &lusers_msgtab, NULL };
+DECLARE_MODULE_AV1(lusers, NULL, NULL, lusers_clist, NULL, NULL, "$Revision: 254 $");
+
+/*
+ * m_lusers - LUSERS message handler
+ * parv[0] = sender
+ * parv[1] = host/server mask.
+ * parv[2] = server to query
+ * 
+ * 199970918 JRL hacked to ignore parv[1] completely and require parc > 3
+ * to cause a force
+ */
+static int
+m_lusers(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       static time_t last_used = 0;
+
+       if (parc > 2)
+       {
+               if((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
+               {
+                       /* safe enough to give this on a local connect only */
+                       sendto_one(source_p, form_str(RPL_LOAD2HI),
+                                  me.name, source_p->name, "LUSERS");
+                       return 0;
+               }
+               else
+                       last_used = CurrentTime;
+
+               if(hunt_server(client_p, source_p, ":%s LUSERS %s :%s", 2, parc, parv) !=
+                          HUNTED_ISME)
+                       return 0;
+       }
+
+       show_lusers(source_p);
+
+       return 0;
+}
+
+/*
+ * ms_lusers - LUSERS message handler for servers and opers
+ * parv[0] = sender
+ * parv[1] = host/server mask.
+ * parv[2] = server to query
+ * 
+ * 199970918 JRL hacked to ignore parv[1] completely and require parc > 3
+ * to cause a force
+ */
+static int
+ms_lusers(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       if(parc > 2)
+       {
+               if(hunt_server(client_p, source_p, ":%s LUSERS %s :%s", 2, parc, parv)
+                  != HUNTED_ISME)
+                       return 0;
+       }
+
+       show_lusers(source_p);
+
+       return 0;
+}
diff --git a/modules/m_map.c b/modules/m_map.c
new file mode 100644 (file)
index 0000000..423f055
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_map.c: Sends an Undernet compatible map to a user.
+ *
+ *  Copyright (C) 2002 by the past and present ircd coders, and others.
+ *
+ *  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: m_map.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "modules.h"
+#include "numeric.h"
+#include "send.h"
+#include "s_conf.h"
+#include "sprintf_irc.h"
+
+#define USER_COL       50      /* display | Users: %d at col 50 */
+
+static int m_map(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
+static int mo_map(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
+
+struct Message map_msgtab = {
+       "MAP", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_map, 0}, mg_ignore, mg_ignore, mg_ignore, {mo_map, 0}}
+};
+
+mapi_clist_av1 map_clist[] = { &map_msgtab, NULL };
+DECLARE_MODULE_AV1(map, NULL, NULL, map_clist, NULL, NULL, "$Revision: 254 $");
+
+static void dump_map(struct Client *client_p, struct Client *root, char *pbuf);
+
+static char buf[BUFSIZE];
+
+/* m_map
+**     parv[0] = sender prefix
+*/
+static int
+m_map(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       if((!IsExemptShide(source_p) && ConfigServerHide.flatten_links) ||
+          ConfigFileEntry.map_oper_only)
+       {
+               m_not_oper(client_p, source_p, parc, parv);
+               return 0;
+       }
+
+       dump_map(client_p, &me, buf);
+       sendto_one(client_p, form_str(RPL_MAPEND), me.name, client_p->name);
+       return 0;
+}
+
+/*
+** mo_map
+**      parv[0] = sender prefix
+*/
+static int
+mo_map(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       dump_map(client_p, &me, buf);
+       sendto_one(client_p, form_str(RPL_MAPEND), me.name, client_p->name);
+
+       return 0;
+}
+
+/*
+** dump_map
+**   dumps server map, called recursively.
+*/
+static void
+dump_map(struct Client *client_p, struct Client *root_p, char *pbuf)
+{
+       int cnt = 0, i = 0, len;
+       struct Client *server_p;
+       dlink_node *ptr;
+       *pbuf = '\0';
+
+       strlcat(pbuf, root_p->name, BUFSIZE);
+       if (has_id(root_p))
+       {
+               strlcat(pbuf, "[", BUFSIZE);
+               strlcat(pbuf, root_p->id, BUFSIZE);
+               strlcat(pbuf, "]", BUFSIZE);
+       }
+       len = strlen(buf);
+       buf[len] = ' ';
+
+       if(len < USER_COL)
+       {
+               for (i = len + 1; i < USER_COL; i++)
+               {
+                       buf[i] = '-';
+               }
+       }
+
+       ircsnprintf(buf + USER_COL, BUFSIZE - USER_COL,
+                " | Users: %5lu (%4.1f%%)", dlink_list_length(&root_p->serv->users),
+                100 * (float) dlink_list_length(&root_p->serv->users) / (float) Count.total);
+
+       sendto_one(client_p, form_str(RPL_MAP), me.name, client_p->name, buf);
+
+       if(root_p->serv->servers.head != NULL)
+       {
+               cnt += dlink_list_length(&root_p->serv->servers);
+
+               if(cnt)
+               {
+                       if(pbuf > buf + 3)
+                       {
+                               pbuf[-2] = ' ';
+                               if(pbuf[-3] == '`')
+                                       pbuf[-3] = ' ';
+                       }
+               }
+       }
+       i = 1;
+       DLINK_FOREACH(ptr, root_p->serv->servers.head)
+       {
+               server_p = ptr->data;
+               *pbuf = ' ';
+               if(i < cnt)
+                       *(pbuf + 1) = '|';
+               else
+                       *(pbuf + 1) = '`';
+
+               *(pbuf + 2) = '-';
+               *(pbuf + 3) = ' ';
+               dump_map(client_p, server_p, pbuf + 4);
+
+               i++;
+       }
+}
diff --git a/modules/m_monitor.c b/modules/m_monitor.c
new file mode 100644 (file)
index 0000000..989c3ef
--- /dev/null
@@ -0,0 +1,354 @@
+/* modules/m_monitor.c
+ * 
+ *  Copyright (C) 2005 Lee Hardy <lee@leeh.co.uk>
+ *  Copyright (C) 2005 ircd-ratbox development team
+ *
+ * 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.The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: m_monitor.c 312 2005-11-07 10:47:33Z jilles $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "client.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "monitor.h"
+#include "numeric.h"
+#include "s_conf.h"
+
+static int m_monitor(struct Client *, struct Client *, int, const char **);
+
+struct Message monitor_msgtab = {
+       "MONITOR", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_monitor, 2}, mg_ignore, mg_ignore, mg_ignore, {m_monitor, 2}}
+};
+
+mapi_clist_av1 monitor_clist[] = { &monitor_msgtab, NULL };
+DECLARE_MODULE_AV1(monitor, NULL, NULL, monitor_clist, NULL, NULL, "$Revision: 312 $");
+
+static void
+add_monitor(struct Client *client_p, const char *nicks)
+{
+       char onbuf[BUFSIZE], offbuf[BUFSIZE];
+       struct Client *target_p;
+       struct monitor *monptr;
+       const char *name;
+       char *tmp;
+       char *p;
+       char *onptr, *offptr;
+       int mlen, arglen;
+       int cur_onlen, cur_offlen;
+
+       /* these two are same length, just diff numeric */
+       cur_offlen = cur_onlen = mlen = sprintf(onbuf, form_str(RPL_MONONLINE),
+                                               me.name, client_p->name, "");
+       sprintf(offbuf, form_str(RPL_MONOFFLINE),
+                       me.name, client_p->name, "");
+
+       onptr = onbuf + mlen;
+       offptr = offbuf + mlen;
+
+       tmp = LOCAL_COPY(nicks);
+
+       for(name = strtoken(&p, tmp, ","); name; name = strtoken(&p, NULL, ","))
+       {
+               if(EmptyString(name) || strlen(name) > NICKLEN-1)
+                       continue;
+
+               if(dlink_list_length(&client_p->localClient->monitor_list) >=
+                       ConfigFileEntry.max_monitor)
+               {
+                       char buf[100];
+
+                       if(cur_onlen != mlen)
+                               sendto_one(client_p, "%s", onbuf);
+                       if(cur_offlen != mlen)
+                               sendto_one(client_p, "%s", offbuf);
+
+                       if(p)
+                               snprintf(buf, sizeof(buf), "%s,%s", name, p);
+                       else
+                               snprintf(buf, sizeof(buf), "%s", name);
+
+                       sendto_one(client_p, form_str(ERR_MONLISTFULL),
+                                       me.name, client_p->name,
+                                       ConfigFileEntry.max_monitor, buf);
+                       return;
+               }
+
+               monptr = find_monitor(name, 1);
+
+               /* already monitoring this nick */
+               if(dlinkFind(client_p, &monptr->users))
+                       continue;
+
+               dlinkAddAlloc(client_p, &monptr->users);
+               dlinkAddAlloc(monptr, &client_p->localClient->monitor_list);
+
+               if((target_p = find_named_person(name)) != NULL)
+               {
+                       if(cur_onlen + strlen(target_p->name) + 
+                          strlen(target_p->username) + strlen(target_p->host) + 3 >= BUFSIZE-3)
+                       {
+                               sendto_one(client_p, "%s", onbuf);
+                               cur_onlen = mlen;
+                               onptr = onbuf + mlen;
+                       }
+
+                       if(cur_onlen != mlen)
+                       {
+                               *onptr++ = ',';
+                               cur_onlen++;
+                       }
+
+                       arglen = sprintf(onptr, "%s!%s@%s",
+                                       target_p->name, target_p->username,
+                                       target_p->host);
+                       onptr += arglen;
+                       cur_onlen += arglen;
+               }
+               else
+               {
+                       if(cur_offlen + strlen(name) + 1 >= BUFSIZE-3)
+                       {
+                               sendto_one(client_p, "%s", offbuf);
+                               cur_offlen = mlen;
+                               offptr = offbuf + mlen;
+                       }
+
+                       if(cur_offlen != mlen)
+                       {
+                               *offptr++ = ',';
+                               cur_offlen++;
+                       }
+
+                       arglen = sprintf(offptr, "%s", name);
+                       offptr += arglen;
+                       cur_offlen += arglen;
+               }
+       }
+
+       if(cur_onlen != mlen)
+               sendto_one(client_p, "%s", onbuf);
+       if(cur_offlen != mlen)
+               sendto_one(client_p, "%s", offbuf);
+}
+
+static void
+del_monitor(struct Client *client_p, const char *nicks)
+{
+       struct monitor *monptr;
+       const char *name;
+       char *tmp;
+       char *p;
+
+       if(!dlink_list_length(&client_p->localClient->monitor_list))
+               return;
+
+       tmp = LOCAL_COPY(nicks);
+
+       for(name = strtoken(&p, tmp, ","); name; name = strtoken(&p, NULL, ","))
+       {
+               if(EmptyString(name))
+                       continue;
+
+               /* not monitored */
+               if((monptr = find_monitor(name, 0)) == NULL)
+                       continue;
+
+               dlinkFindDestroy(client_p, &monptr->users);
+               dlinkFindDestroy(monptr, &client_p->localClient->monitor_list);
+       }
+}
+
+static void
+list_monitor(struct Client *client_p)
+{
+       char buf[BUFSIZE];
+       struct monitor *monptr;
+       char *nbuf;
+       dlink_node *ptr;
+       int mlen, arglen, cur_len;
+
+       if(!dlink_list_length(&client_p->localClient->monitor_list))
+       {
+               sendto_one(client_p, form_str(RPL_ENDOFMONLIST),
+                               me.name, client_p->name);
+               return;
+       }
+
+       cur_len = mlen = sprintf(buf, form_str(RPL_MONLIST),
+                               me.name, client_p->name, "");
+       nbuf = buf + mlen;
+
+       DLINK_FOREACH(ptr, client_p->localClient->monitor_list.head)
+       {
+               monptr = ptr->data;
+
+               if(cur_len + strlen(monptr->name) + 1 >= BUFSIZE-3)
+               {
+                       sendto_one(client_p, "%s", buf);
+                       nbuf = buf + mlen;
+                       cur_len = mlen;
+               }
+
+               if(cur_len != mlen)
+               {
+                       *nbuf++ = ',';
+                       cur_len++;
+               }
+
+               arglen = sprintf(nbuf, "%s", monptr->name);
+               cur_len += arglen;
+               nbuf += arglen;
+       }
+
+       sendto_one(client_p, "%s", buf);
+       sendto_one(client_p, form_str(RPL_ENDOFMONLIST), 
+                       me.name, client_p->name);
+}
+
+static void
+show_monitor_status(struct Client *client_p)
+{
+       char onbuf[BUFSIZE], offbuf[BUFSIZE];
+       struct Client *target_p;
+       struct monitor *monptr;
+       char *onptr, *offptr;
+       int cur_onlen, cur_offlen;
+       int mlen, arglen;
+       dlink_node *ptr;
+
+       mlen = cur_onlen = sprintf(onbuf, form_str(RPL_MONONLINE),
+                                       me.name, client_p->name, "");
+       cur_offlen = sprintf(offbuf, form_str(RPL_MONOFFLINE),
+                               me.name, client_p->name, "");
+
+       onptr = onbuf + mlen;
+       offptr = offbuf + mlen;
+
+       DLINK_FOREACH(ptr, client_p->localClient->monitor_list.head)
+       {
+               monptr = ptr->data;
+
+               if((target_p = find_named_person(monptr->name)) != NULL)
+               {
+                       if(cur_onlen + strlen(target_p->name) + 
+                          strlen(target_p->username) + strlen(target_p->host) + 3 >= BUFSIZE-3)
+                       {
+                               sendto_one(client_p, "%s", onbuf);
+                               cur_onlen = mlen;
+                               onptr = onbuf + mlen;
+                       }
+
+                       if(cur_onlen != mlen)
+                       {
+                               *onptr++ = ',';
+                               cur_onlen++;
+                       }
+
+                       arglen = sprintf(onptr, "%s!%s@%s",
+                                       target_p->name, target_p->username,
+                                       target_p->host);
+                       onptr += arglen;
+                       cur_onlen += arglen;
+               }
+               else
+               {
+                       if(cur_offlen + strlen(monptr->name) + 1 >= BUFSIZE-3)
+                       {
+                               sendto_one(client_p, "%s", offbuf);
+                               cur_offlen = mlen;
+                               offptr = offbuf + mlen;
+                       }
+
+                       if(cur_offlen != mlen)
+                       {
+                               *offptr++ = ',';
+                               cur_offlen++;
+                       }
+
+                       arglen = sprintf(offptr, "%s", monptr->name);
+                       offptr += arglen;
+                       cur_offlen += arglen;
+               }
+       }
+
+       if(cur_onlen != mlen)
+               sendto_one(client_p, "%s", onbuf);
+       if(cur_offlen != mlen)
+               sendto_one(client_p, "%s", offbuf);
+}
+
+static int
+m_monitor(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       switch(parv[1][0])
+       {
+               case '+':
+                       if(parc < 3 || EmptyString(parv[2]))
+                       {
+                               sendto_one(client_p, form_str(ERR_NEEDMOREPARAMS),
+                                               me.name, source_p->name, "MONITOR");
+                               return 0;
+                       }
+
+                       add_monitor(source_p, parv[2]);
+                       break;
+               case '-':
+                       if(parc < 3 || EmptyString(parv[2]))
+                       {
+                               sendto_one(client_p, form_str(ERR_NEEDMOREPARAMS),
+                                               me.name, source_p->name, "MONITOR");
+                               return 0;
+                       }
+
+                       del_monitor(source_p, parv[2]);
+                       break;
+
+               case 'C':
+               case 'c':
+                       clear_monitor(source_p);
+                       break;
+
+               case 'L':
+               case 'l':
+                       list_monitor(source_p);
+                       break;
+
+               case 'S':
+               case 's':
+                       show_monitor_status(source_p);
+                       break;
+
+               default:
+                       break;
+       }
+
+       return 0;
+}
+
diff --git a/modules/m_motd.c b/modules/m_motd.c
new file mode 100644 (file)
index 0000000..802b407
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_motd.c: Shows the current message of the day.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_motd.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "tools.h"
+#include "ircd.h"
+#include "send.h"
+#include "numeric.h"
+#include "hook.h"
+#include "msg.h"
+#include "s_serv.h"            /* hunt_server */
+#include "parse.h"
+#include "modules.h"
+#include "s_conf.h"
+#include "cache.h"
+
+static int m_motd(struct Client *, struct Client *, int, const char **);
+static int mo_motd(struct Client *, struct Client *, int, const char **);
+
+struct Message motd_msgtab = {
+       "MOTD", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_motd, 0}, {mo_motd, 0}, mg_ignore, mg_ignore, {mo_motd, 0}}
+};
+
+int doing_motd_hook;
+
+mapi_clist_av1 motd_clist[] = { &motd_msgtab, NULL };
+mapi_hlist_av1 motd_hlist[] = {
+       { "doing_motd", &doing_motd_hook },
+       { NULL, NULL }
+};
+
+DECLARE_MODULE_AV1(motd, NULL, NULL, motd_clist, motd_hlist, NULL, "$Revision: 254 $");
+
+static void motd_spy(struct Client *);
+
+/*
+** m_motd
+**      parv[0] = sender prefix
+**      parv[1] = servername
+*/
+static int
+m_motd(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       static time_t last_used = 0;
+
+       if((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
+       {
+               /* safe enough to give this on a local connect only */
+               sendto_one(source_p, form_str(RPL_LOAD2HI),
+                          me.name, source_p->name, "MOTD");
+               sendto_one(source_p, form_str(RPL_ENDOFMOTD),
+                          me.name, source_p->name);
+               return 0;
+       }
+       else
+               last_used = CurrentTime;
+
+       if(hunt_server(client_p, source_p, ":%s MOTD :%s", 1, parc, parv) != HUNTED_ISME)
+               return 0;
+
+       motd_spy(source_p);
+       send_user_motd(source_p);
+
+       return 0;
+}
+
+/*
+** mo_motd
+**      parv[0] = sender prefix
+**      parv[1] = servername
+*/
+static int
+mo_motd(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       if(hunt_server(client_p, source_p, ":%s MOTD :%s", 1, parc, parv) != HUNTED_ISME)
+               return 0;
+
+       motd_spy(source_p);
+       send_user_motd(source_p);
+
+       return 0;
+}
+
+/* motd_spy()
+ *
+ * input        - pointer to client
+ * output       - none
+ * side effects - hook doing_motd is called
+ */
+static void
+motd_spy(struct Client *source_p)
+{
+       hook_data data;
+
+       data.client = source_p;
+       data.arg1 = data.arg2 = NULL;
+
+       call_hook(doing_motd_hook, &data);
+}
diff --git a/modules/m_names.c b/modules/m_names.c
new file mode 100644 (file)
index 0000000..e307ab9
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_names.c: Shows the users who are online.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_names.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "sprintf_irc.h"
+#include "tools.h"
+#include "channel.h"
+#include "client.h"
+#include "common.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "s_serv.h"
+#include "s_conf.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+
+static int m_names(struct Client *, struct Client *, int, const char **);
+
+struct Message names_msgtab = {
+       "NAMES", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_names, 0}, mg_ignore, mg_ignore, mg_ignore, {m_names, 0}}
+};
+
+mapi_clist_av1 names_clist[] = { &names_msgtab, NULL };
+DECLARE_MODULE_AV1(names, NULL, NULL, names_clist, NULL, NULL, "$Revision: 254 $");
+
+static void names_global(struct Client *source_p);
+
+/************************************************************************
+ * m_names() - Added by Jto 27 Apr 1989
+ ************************************************************************/
+
+/*
+ * m_names
+ *      parv[0] = sender prefix
+ *      parv[1] = channel
+ */
+static int
+m_names(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       static time_t last_used = 0;
+       struct Channel *chptr = NULL;
+       char *s;
+
+       if(parc > 1 && !EmptyString(parv[1]))
+       {
+               char *p = LOCAL_COPY(parv[1]);
+               if((s = strchr(p, ',')))
+                       *s = '\0';
+
+               if(!check_channel_name(p))
+               {
+                       sendto_one_numeric(source_p, ERR_BADCHANNAME,
+                                          form_str(ERR_BADCHANNAME),
+                                          (unsigned char *) p);
+                       return 0;
+               }
+
+               if((chptr = find_channel(p)) != NULL)
+                       channel_member_names(chptr, source_p, 1);
+               else
+                       sendto_one(source_p, form_str(RPL_ENDOFNAMES), 
+                                  me.name, source_p->name, p);
+       }
+       else
+       {
+               if(!IsOper(source_p))
+               {
+                       if((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
+                       {
+                               sendto_one(source_p, form_str(RPL_LOAD2HI),
+                                          me.name, source_p->name, "NAMES");
+                               sendto_one(source_p, form_str(RPL_ENDOFNAMES),
+                                          me.name, source_p->name, "*");
+                               return 0;
+                       }
+                       else
+                               last_used = CurrentTime;
+               }
+
+               names_global(source_p);
+               sendto_one(source_p, form_str(RPL_ENDOFNAMES), 
+                          me.name, source_p->name, "*");
+       }
+
+       return 0;
+}
+
+/*
+ * names_global
+ *
+ * inputs       - pointer to client struct requesting names
+ * output       - none
+ * side effects - lists all non public non secret channels
+ */
+static void
+names_global(struct Client *source_p)
+{
+       int mlen;
+       int tlen;
+       int cur_len;
+       int dont_show = NO;
+       dlink_node *lp, *ptr;
+       struct Client *target_p;
+       struct Channel *chptr = NULL;
+       struct membership *msptr;
+       char buf[BUFSIZE];
+       char *t;
+
+       /* first do all visible channels */
+       DLINK_FOREACH(ptr, global_channel_list.head)
+       {
+               chptr = ptr->data;
+               channel_member_names(chptr, source_p, 0);
+       }
+       cur_len = mlen = ircsprintf(buf, form_str(RPL_NAMREPLY), 
+                                   me.name, source_p->name, "*", "*");
+       t = buf + mlen;
+
+       /* Second, do all clients in one big sweep */
+       DLINK_FOREACH(ptr, global_client_list.head)
+       {
+               target_p = ptr->data;
+               dont_show = NO;
+
+               if(!IsPerson(target_p) || IsInvisible(target_p))
+                       continue;
+
+               /* we want to show -i clients that are either:
+                *   a) not on any channels
+                *   b) only on +p channels
+                *
+                * both were missed out above.  if the target is on a
+                * common channel with source, its already been shown.
+                */
+               DLINK_FOREACH(lp, target_p->user->channel.head)
+               {
+                       msptr = lp->data;
+                       chptr = msptr->chptr;
+
+                       if(PubChannel(chptr) || IsMember(source_p, chptr) ||
+                          SecretChannel(chptr))
+                       {
+                               dont_show = YES;
+                               break;
+                       }
+               }
+
+               if(dont_show)
+                       continue;
+
+               if((cur_len + NICKLEN + 2) > (BUFSIZE - 3))
+               {
+                       sendto_one(source_p, "%s", buf);
+                       cur_len = mlen;
+                       t = buf + mlen;
+               }
+
+               tlen = ircsprintf(t, "%s ", target_p->name);
+               cur_len += tlen;
+               t += tlen;
+       }
+
+       if(cur_len > mlen)
+               sendto_one(source_p, "%s", buf);
+}
diff --git a/modules/m_oper.c b/modules/m_oper.c
new file mode 100644 (file)
index 0000000..ac7a1d3
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_oper.c: Makes a user an IRC Operator.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_oper.c 1483 2006-05-27 18:58:12Z jilles $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "client.h"
+#include "common.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "commio.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "s_log.h"
+#include "s_user.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "packet.h"
+#include "cache.h"
+
+static int m_oper(struct Client *, struct Client *, int, const char **);
+
+struct Message oper_msgtab = {
+       "OPER", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_oper, 3}, mg_ignore, mg_ignore, mg_ignore, {m_oper, 3}}
+};
+
+mapi_clist_av1 oper_clist[] = { &oper_msgtab, NULL };
+DECLARE_MODULE_AV1(oper, NULL, NULL, oper_clist, NULL, NULL, "$Revision: 1483 $");
+
+static int match_oper_password(const char *password, struct oper_conf *oper_p);
+extern char *crypt();
+
+/*
+ * m_oper
+ *      parv[0] = sender prefix
+ *      parv[1] = oper name
+ *      parv[2] = oper password
+ */
+static int
+m_oper(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct oper_conf *oper_p;
+       const char *name;
+       const char *password;
+
+       name = parv[1];
+       password = parv[2];
+
+       if(IsOper(source_p))
+       {
+               sendto_one(source_p, form_str(RPL_YOUREOPER), me.name, source_p->name);
+               send_oper_motd(source_p);
+               return 0;
+       }
+
+       /* end the grace period */
+       if(!IsFloodDone(source_p))
+               flood_endgrace(source_p);
+
+       oper_p = find_oper_conf(source_p->username, source_p->orighost, 
+                               source_p->sockhost, name);
+
+       if(oper_p == NULL)
+       {
+               sendto_one(source_p, form_str(ERR_NOOPERHOST), me.name, source_p->name);
+               ilog(L_FOPER, "FAILED OPER (%s) by (%s!%s@%s) (%s)",
+                    name, source_p->name,
+                    source_p->username, source_p->host, source_p->sockhost);
+
+               if(ConfigFileEntry.failed_oper_notice)
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
+                                            "Failed OPER attempt - host mismatch by %s (%s@%s)",
+                                            source_p->name, source_p->username, source_p->host);
+               }
+
+               return 0;
+       }
+
+       if(match_oper_password(password, oper_p))
+       {
+               oper_up(source_p, oper_p);
+
+               ilog(L_OPERED, "OPER %s by %s!%s@%s (%s)",
+                    name, source_p->name, source_p->username, source_p->host,
+                    source_p->sockhost);
+               return 0;
+       }
+       else
+       {
+               sendto_one(source_p, form_str(ERR_PASSWDMISMATCH),
+                          me.name, source_p->name);
+
+               ilog(L_FOPER, "FAILED OPER (%s) by (%s!%s@%s) (%s)",
+                    name, source_p->name, source_p->username, source_p->host,
+                    source_p->sockhost);
+
+               if(ConfigFileEntry.failed_oper_notice)
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
+                                            "Failed OPER attempt by %s (%s@%s)",
+                                            source_p->name, source_p->username, source_p->host);
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * match_oper_password
+ *
+ * inputs       - pointer to given password
+ *              - pointer to Conf 
+ * output       - YES or NO if match
+ * side effects - none
+ */
+static int
+match_oper_password(const char *password, struct oper_conf *oper_p)
+{
+       const char *encr;
+
+       /* passwd may be NULL pointer. Head it off at the pass... */
+       if(EmptyString(oper_p->passwd))
+               return NO;
+
+       if(IsOperConfEncrypted(oper_p))
+       {
+               /* use first two chars of the password they send in as salt */
+               /* If the password in the conf is MD5, and ircd is linked   
+                * to scrypt on FreeBSD, or the standard crypt library on
+                * glibc Linux, then this code will work fine on generating
+                * the proper encrypted hash for comparison.
+                */
+               if(!EmptyString(password))
+                       encr = crypt(password, oper_p->passwd);
+               else
+                       encr = "";
+       }
+       else
+               encr = password;
+
+       if(strcmp(encr, oper_p->passwd) == 0)
+               return YES;
+       else
+               return NO;
+}
diff --git a/modules/m_operspy.c b/modules/m_operspy.c
new file mode 100644 (file)
index 0000000..f8a02d3
--- /dev/null
@@ -0,0 +1,103 @@
+/*  modules/m_operspy.c
+ *  Copyright (C) 2003-2005 ircd-ratbox development team
+ *  Copyright (C) 2003 Lee Hardy <lee@leeh.co.uk>
+ *
+ * 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.The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: m_operspy.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "send.h"
+#include "channel.h"
+#include "client.h"
+#include "common.h"
+#include "config.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "memory.h"
+#include "s_serv.h"
+#include "hash.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "sprintf_irc.h"
+
+static int ms_operspy(struct Client *client_p, struct Client *source_p,
+                     int parc, const char *parv[]);
+
+struct Message operspy_msgtab = {
+       "OPERSPY", 0, 0, 0, MFLG_SLOW,
+       {mg_ignore, mg_ignore, mg_ignore, mg_ignore, {ms_operspy, 2}, mg_ignore}
+};
+
+mapi_clist_av1 operspy_clist[] = { &operspy_msgtab, NULL };
+DECLARE_MODULE_AV1(operspy, NULL, NULL, operspy_clist, NULL, NULL, "$Revision: 254 $");
+
+/* ms_operspy()
+ *
+ * parv[1] - operspy command
+ * parv[2] - optional params
+ */
+static int
+ms_operspy(struct Client *client_p, struct Client *source_p,
+          int parc, const char *parv[])
+{
+       static char buffer[BUFSIZE];
+       char *ptr;
+       int cur_len = 0;
+       int len, i;
+
+       if(parc < 4)
+       {
+               report_operspy(source_p, parv[1],
+                           parc < 3 ? NULL : parv[2]);
+       }
+       /* buffer all remaining into one param */
+       else
+       {
+               ptr = buffer;
+               cur_len = 0;
+
+               for(i = 2; i < parc; i++)
+               {
+                       len = strlen(parv[i]) + 1;
+
+                       if((size_t)(cur_len + len) >= sizeof(buffer))
+                               return 0;
+
+                       ircsnprintf(ptr, sizeof(buffer) - cur_len, "%s ",
+                                parv[i]);
+                       ptr += len;
+                       cur_len += len;
+               }
+
+               report_operspy(source_p, parv[1], buffer);
+       }
+
+       return 0;
+}
+
diff --git a/modules/m_pass.c b/modules/m_pass.c
new file mode 100644 (file)
index 0000000..1cfe284
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_pass.c: Used to send a password for a server or client{} block.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_pass.c 1291 2006-05-05 19:00:19Z jilles $
+ */
+
+#include "stdinc.h"
+#include "client.h"            /* client struct */
+#include "irc_string.h"
+#include "send.h"              /* sendto_one */
+#include "numeric.h"           /* ERR_xxx */
+#include "ircd.h"              /* me */
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_serv.h"
+#include "hash.h"
+#include "s_conf.h"
+
+static int mr_pass(struct Client *, struct Client *, int, const char **);
+
+struct Message pass_msgtab = {
+       "PASS", 0, 0, 0, MFLG_SLOW | MFLG_UNREG,
+       {{mr_pass, 2}, mg_reg, mg_ignore, mg_ignore, mg_ignore, mg_reg}
+};
+
+mapi_clist_av1 pass_clist[] = { &pass_msgtab, NULL };
+DECLARE_MODULE_AV1(pass, NULL, NULL, pass_clist, NULL, NULL, "$Revision: 1291 $");
+
+/*
+ * m_pass() - Added Sat, 4 March 1989
+ *
+ *
+ * mr_pass - PASS message handler
+ *      parv[0] = sender prefix
+ *      parv[1] = password
+ *      parv[2] = "TS" if this server supports TS.
+ *      parv[3] = optional TS version field -- needed for TS6
+ */
+static int
+mr_pass(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       if(client_p->localClient->passwd)
+       {
+               memset(client_p->localClient->passwd, 0,
+                       strlen(client_p->localClient->passwd));
+               MyFree(client_p->localClient->passwd);
+       }
+
+       DupNString(client_p->localClient->passwd, parv[1], PASSWDLEN);
+
+       /* These are for servers only */
+       if(parc > 2 && client_p->user == NULL)
+       {
+               /* 
+                * It looks to me as if orabidoo wanted to have more
+                * than one set of option strings possible here...
+                * i.e. ":AABBTS" as long as TS was the last two chars
+                * however, as we are now using CAPAB, I think we can
+                * safely assume if there is a ":TS" then its a TS server
+                * -Dianora
+                */
+               if(irccmp(parv[2], "TS") == 0 && client_p->tsinfo == 0)
+                       client_p->tsinfo = TS_DOESTS;
+
+               /* kludge, if we're not using ts6, dont ever mark a server
+                * as TS6 capable, that way we'll never send them TS6 data.
+                */
+               if(ServerInfo.use_ts6 && parc == 5 && atoi(parv[3]) >= 6)
+               {
+                       /* only mark as TS6 if the SID is valid.. */
+                       if(IsDigit(parv[4][0]) && IsIdChar(parv[4][1]) &&
+                          IsIdChar(parv[4][2]) && parv[4][3] == '\0' &&
+                          EmptyString(client_p->id))
+                       {
+                               client_p->localClient->caps |= CAP_TS6;
+                               strcpy(client_p->id, parv[4]);
+                       }
+               }
+       }
+
+       return 0;
+}
diff --git a/modules/m_ping.c b/modules/m_ping.c
new file mode 100644 (file)
index 0000000..f2a0be3
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_ping.c: Requests that a PONG message be sent back.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_ping.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "irc_string.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "hash.h"
+#include "s_conf.h"
+#include "s_serv.h"
+
+static int m_ping(struct Client *, struct Client *, int, const char **);
+static int ms_ping(struct Client *, struct Client *, int, const char **);
+
+struct Message ping_msgtab = {
+       "PING", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_ping, 2}, {ms_ping, 2}, {ms_ping, 2}, mg_ignore, {m_ping, 2}}
+};
+
+mapi_clist_av1 ping_clist[] = { &ping_msgtab, NULL };
+DECLARE_MODULE_AV1(ping, NULL, NULL, ping_clist, NULL, NULL, "$Revision: 254 $");
+
+/*
+** m_ping
+**      parv[0] = sender prefix
+**      parv[1] = origin
+**      parv[2] = destination
+*/
+static int
+m_ping(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+       const char *destination;
+
+       destination = parv[2];  /* Will get NULL or pointer (parc >= 2!!) */
+
+       if(!EmptyString(destination) && !match(destination, me.name))
+       {
+               if((target_p = find_server(source_p, destination)))
+               {
+                       sendto_one(target_p, ":%s PING %s :%s",
+                                  get_id(source_p, target_p),
+                                  source_p->name, get_id(target_p, target_p));
+               }
+               else
+               {
+                       sendto_one_numeric(source_p, ERR_NOSUCHSERVER,
+                                          form_str(ERR_NOSUCHSERVER),
+                                          destination);
+                       return 0;
+               }
+       }
+       else
+               sendto_one(source_p, ":%s PONG %s :%s", me.name,
+                          (destination) ? destination : me.name, parv[1]);
+
+       return 0;
+}
+
+static int
+ms_ping(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+       const char *destination;
+
+       destination = parv[2];  /* Will get NULL or pointer (parc >= 2!!) */
+
+       if(!EmptyString(destination) && irccmp(destination, me.name) &&
+          irccmp(destination, me.id))
+       {
+               if((target_p = find_client(destination)) && IsServer(target_p))
+                       sendto_one(target_p, ":%s PING %s :%s", 
+                                  get_id(source_p, target_p), source_p->name,
+                                  get_id(target_p, target_p));
+               /* not directed at an id.. */
+               else if(!IsDigit(*destination))
+                       sendto_one_numeric(source_p, ERR_NOSUCHSERVER,
+                                          form_str(ERR_NOSUCHSERVER),
+                                          destination);
+       }
+       else
+               sendto_one(source_p, ":%s PONG %s :%s", 
+                          get_id(&me, source_p), me.name, 
+                          get_id(source_p, source_p));
+
+       return 0;
+}
diff --git a/modules/m_pong.c b/modules/m_pong.c
new file mode 100644 (file)
index 0000000..7900f48
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_pong.c: The reply to a ping message.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_pong.c 522 2006-01-15 20:55:27Z jilles $
+ */
+
+#include "stdinc.h"
+#include "ircd.h"
+#include "s_user.h"
+#include "client.h"
+#include "hash.h"              /* for find_client() */
+#include "hook.h"
+#include "numeric.h"
+#include "s_conf.h"
+#include "send.h"
+#include "channel.h"
+#include "irc_string.h"
+#include "msg.h"
+#include "parse.h"
+#include "hash.h"
+#include "modules.h"
+
+static int mr_pong(struct Client *, struct Client *, int, const char **);
+static int ms_pong(struct Client *, struct Client *, int, const char **);
+
+struct Message pong_msgtab = {
+       "PONG", 0, 0, 0, MFLG_SLOW | MFLG_UNREG,
+       {{mr_pong, 0}, mg_ignore, mg_ignore, {ms_pong, 2}, mg_ignore, mg_ignore}
+};
+
+mapi_clist_av1 pong_clist[] = { &pong_msgtab, NULL };
+DECLARE_MODULE_AV1(pong, NULL, NULL, pong_clist, NULL, NULL, "$Revision: 522 $");
+
+static int
+ms_pong(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+       const char *destination;
+
+       destination = parv[2];
+       source_p->flags &= ~FLAGS_PINGSENT;
+
+       /* Now attempt to route the PONG, comstud pointed out routable PING
+        * is used for SPING.  routable PING should also probably be left in
+        *        -Dianora
+        * That being the case, we will route, but only for registered clients (a
+        * case can be made to allow them only from servers). -Shadowfax
+        */
+       if(!EmptyString(destination) && !match(destination, me.name) &&
+          irccmp(destination, me.id))
+       {
+               if((target_p = find_client(destination)) || 
+                  (target_p = find_server(NULL, destination)))
+                       sendto_one(target_p, ":%s PONG %s %s", 
+                                  get_id(source_p, target_p), parv[1], 
+                                  get_id(target_p, target_p));
+               else
+               {
+                       if(!IsDigit(*destination))
+                               sendto_one_numeric(source_p, ERR_NOSUCHSERVER,
+                                                  form_str(ERR_NOSUCHSERVER), destination);
+                       return 0;
+               }
+       }
+
+       /* destination is us, emulate EOB */
+       if(IsServer(source_p) && !HasSentEob(source_p))
+       {
+               if(MyConnect(source_p))
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "End of burst (emulated) from %s (%d seconds)",
+                                            source_p->name,
+                                            (signed int) (CurrentTime - source_p->localClient->firsttime));
+               SetEob(source_p);
+               eob_count++;
+               call_hook(h_server_eob, source_p);
+       }
+
+       return 0;
+}
+
+static int
+mr_pong(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       if(parc == 2 && !EmptyString(parv[1]))
+       {
+               if(ConfigFileEntry.ping_cookie && source_p->user && source_p->name[0])
+               {
+                       unsigned long incoming_ping = strtoul(parv[1], NULL, 16);
+                       if(incoming_ping)
+                       {
+                               if(source_p->localClient->random_ping == incoming_ping)
+                               {
+                                       char buf[USERLEN + 1];
+                                       strlcpy(buf, source_p->username, sizeof(buf));
+                                       source_p->flags2 |= FLAGS2_PING_COOKIE;
+                                       register_local_user(client_p, source_p, buf);
+                               }
+                               else
+                               {
+                                       sendto_one(source_p, form_str(ERR_WRONGPONG),
+                                                  me.name, source_p->name,
+                                                  source_p->localClient->random_ping);
+                                       return 0;
+                               }
+                       }
+               }
+
+       }
+       else
+               sendto_one(source_p, form_str(ERR_NOORIGIN), me.name, parv[0]);
+
+       source_p->flags &= ~FLAGS_PINGSENT;
+
+       return 0;
+}
diff --git a/modules/m_post.c b/modules/m_post.c
new file mode 100644 (file)
index 0000000..50367e1
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_post.c: Exits the user if unregistered, it is a web form.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_post.c 498 2006-01-15 16:40:33Z jilles $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_serv.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_conf.h"
+
+static int mr_dumb_proxy(struct Client *, struct Client *, int, const char **);
+
+struct Message post_msgtab = {
+       "POST", 0, 0, 0, MFLG_SLOW | MFLG_UNREG,
+       {{mr_dumb_proxy, 0}, mg_ignore, mg_ignore, mg_ignore, mg_ignore, mg_ignore}
+};
+struct Message get_msgtab = {
+       "GET", 0, 0, 0, MFLG_SLOW | MFLG_UNREG,
+       {{mr_dumb_proxy, 0}, mg_ignore, mg_ignore, mg_ignore, mg_ignore, mg_ignore}
+};
+struct Message put_msgtab = {
+       "PUT", 0, 0, 0, MFLG_SLOW | MFLG_UNREG,
+       {{mr_dumb_proxy, 0}, mg_ignore, mg_ignore, mg_ignore, mg_ignore, mg_ignore}
+};
+
+
+mapi_clist_av1 post_clist[] = {
+       &post_msgtab, &get_msgtab, &put_msgtab, NULL
+};
+DECLARE_MODULE_AV1(post, NULL, NULL, post_clist, NULL, NULL, "$Revision: 498 $");
+
+
+/*
+** mr_dumb_proxy
+**      parv[0] = sender prefix
+**      parv[1] = comment
+*/
+static int
+mr_dumb_proxy(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       sendto_realops_snomask(SNO_REJ, L_ALL,
+                            "HTTP Proxy disconnected: [%s@%s]",
+                            client_p->username, client_p->host);
+       exit_client(client_p, source_p, source_p, "Client Exit");
+
+       return 0;
+}
diff --git a/modules/m_rehash.c b/modules/m_rehash.c
new file mode 100644 (file)
index 0000000..db0ab4d
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_rehash.c: Re-reads the configuration file.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_rehash.c 932 2006-03-05 03:39:14Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "channel.h"
+#include "common.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "s_gline.h"
+#include "s_serv.h"
+#include "numeric.h"
+#include "res.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "s_log.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "hostmask.h"
+#include "reject.h"
+#include "hash.h"
+#include "cache.h"
+
+static int mo_rehash(struct Client *, struct Client *, int, const char **);
+static int me_rehash(struct Client *, struct Client *, int, const char **);
+
+struct Message rehash_msgtab = {
+       "REHASH", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_rehash, 0}, {mo_rehash, 0}}
+};
+
+mapi_clist_av1 rehash_clist[] = { &rehash_msgtab, NULL };
+DECLARE_MODULE_AV1(rehash, NULL, NULL, rehash_clist, NULL, NULL, "$Revision: 932 $");
+
+struct hash_commands
+{
+       const char *cmd;
+       void (*handler) (struct Client * source_p);
+};
+
+static void
+rehash_bans_loc(struct Client *source_p)
+{
+       sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s is rehashing bans",
+                               get_oper_name(source_p));
+
+       rehash_bans(0);
+}
+
+static void
+rehash_dns(struct Client *source_p)
+{
+       sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s is rehashing DNS", 
+                            get_oper_name(source_p));
+
+       /* reread /etc/resolv.conf and reopen res socket */
+       restart_resolver();
+}
+
+static void
+rehash_motd(struct Client *source_p)
+{
+       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                            "%s is forcing re-reading of MOTD file",
+                            get_oper_name(source_p));
+
+       free_cachefile(user_motd);
+       user_motd = cache_file(MPATH, "ircd.motd", 0);
+}
+
+static void
+rehash_omotd(struct Client *source_p)
+{
+       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                            "%s is forcing re-reading of OPER MOTD file",
+                            get_oper_name(source_p));
+
+       free_cachefile(oper_motd);
+       oper_motd = cache_file(OPATH, "opers.motd", 0);
+}
+
+static void
+rehash_glines(struct Client *source_p)
+{
+       struct ConfItem *aconf;
+       dlink_node *ptr, *next_ptr;
+
+       sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s is clearing G-lines",
+                               get_oper_name(source_p));
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, glines.head)
+       {
+               aconf = ptr->data;
+
+               delete_one_address_conf(aconf->host, aconf);
+               dlinkDestroy(ptr, &glines);
+       }
+}
+
+static void
+rehash_pglines(struct Client *source_p)
+{
+       struct gline_pending *glp_ptr;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+
+       sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s is clearing pending glines",
+                               get_oper_name(source_p));
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, pending_glines.head)
+       {
+               glp_ptr = ptr->data;
+
+               MyFree(glp_ptr->reason1);
+               MyFree(glp_ptr->reason2);
+               MyFree(glp_ptr);
+               dlinkDestroy(ptr, &pending_glines);
+       }
+}
+
+static void
+rehash_tklines(struct Client *source_p)
+{
+       struct ConfItem *aconf;
+       dlink_node *ptr, *next_ptr;
+       int i;
+
+       sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s is clearing temp klines",
+                               get_oper_name(source_p));
+
+       for(i = 0; i < LAST_TEMP_TYPE; i++)
+       {
+               DLINK_FOREACH_SAFE(ptr, next_ptr, temp_klines[i].head)
+               {
+                       aconf = ptr->data;
+
+                       delete_one_address_conf(aconf->host, aconf);
+                       dlinkDestroy(ptr, &temp_klines[i]);
+               }
+       }
+}
+
+static void
+rehash_tdlines(struct Client *source_p)
+{
+       struct ConfItem *aconf;
+       dlink_node *ptr, *next_ptr;
+       int i;
+
+       sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s is clearing temp dlines",
+                               get_oper_name(source_p));
+
+       for(i = 0; i < LAST_TEMP_TYPE; i++)
+       {
+               DLINK_FOREACH_SAFE(ptr, next_ptr, temp_dlines[i].head)
+               {
+                       aconf = ptr->data;
+
+                       delete_one_address_conf(aconf->host, aconf);
+                       dlinkDestroy(ptr, &temp_dlines[i]);
+               }
+       }
+}
+
+static void
+rehash_txlines(struct Client *source_p)
+{
+       struct ConfItem *aconf;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+
+       sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s is clearing temp xlines",
+                               get_oper_name(source_p));
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, xline_conf_list.head)
+       {
+               aconf = ptr->data;
+
+               if(!aconf->hold)
+                       continue;
+
+               free_conf(aconf);
+               dlinkDestroy(ptr, &xline_conf_list);
+       }
+}
+
+static void
+rehash_tresvs(struct Client *source_p)
+{
+       struct ConfItem *aconf;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+       int i;
+
+       sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s is clearing temp resvs",
+                               get_oper_name(source_p));
+
+       HASH_WALK_SAFE(i, R_MAX, ptr, next_ptr, resvTable)
+       {
+               aconf = ptr->data;
+
+               if(!aconf->hold)
+                       continue;
+
+               free_conf(aconf);
+               dlinkDestroy(ptr, &resvTable[i]);
+       }
+       HASH_WALK_END
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, resv_conf_list.head)
+       {
+               aconf = ptr->data;
+
+               if(!aconf->hold)
+                       continue;
+
+               free_conf(aconf);
+               dlinkDestroy(ptr, &resv_conf_list);
+       }
+}
+
+static void
+rehash_rejectcache(struct Client *source_p)
+{
+       sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s is clearing reject cache",
+                               get_oper_name(source_p));
+       flush_reject();
+
+}
+
+static void
+rehash_help(struct Client *source_p)
+{
+       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                            "%s is forcing re-reading of HELP files", 
+                            get_oper_name(source_p));
+       clear_help_hash();
+       load_help();
+}
+
+static void
+rehash_nickdelay(struct Client *source_p)
+{
+       struct nd_entry *nd;
+       dlink_node *ptr;
+       dlink_node *safe_ptr;
+
+       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                            "%s is clearing the nick delay table",
+                            get_oper_name(source_p));
+
+       DLINK_FOREACH_SAFE(ptr, safe_ptr, nd_list.head)
+       {
+               nd = ptr->data;
+       
+               free_nd_entry(nd);
+       }
+}
+
+/* *INDENT-OFF* */
+static struct hash_commands rehash_commands[] =
+{
+       {"BANS",        rehash_bans_loc         },
+       {"DNS",         rehash_dns              },
+       {"MOTD",        rehash_motd             },
+       {"OMOTD",       rehash_omotd            },
+       {"GLINES",      rehash_glines           },
+       {"PGLINES",     rehash_pglines          },
+       {"TKLINES",     rehash_tklines          },
+       {"TDLINES",     rehash_tdlines          },
+       {"TXLINES",     rehash_txlines          },
+       {"TRESVS",      rehash_tresvs           },
+       {"REJECTCACHE", rehash_rejectcache      },
+       {"HELP",        rehash_help             },
+       {"NICKDELAY",   rehash_nickdelay        },
+       {NULL,          NULL                    }
+};
+/* *INDENT-ON* */
+
+static void
+do_rehash(struct Client *source_p, const char *type)
+{
+       if (type != NULL)
+       {
+               int x;
+               char cmdbuf[100];
+
+               for (x = 0; rehash_commands[x].cmd != NULL && rehash_commands[x].handler != NULL;
+                    x++)
+               {
+                       if(irccmp(type, rehash_commands[x].cmd) == 0)
+                       {
+                               sendto_one(source_p, form_str(RPL_REHASHING), me.name,
+                                          source_p->name, rehash_commands[x].cmd);
+                               rehash_commands[x].handler(source_p);
+                               ilog(L_MAIN, "REHASH %s From %s[%s]", type,
+                                    get_oper_name(source_p), source_p->sockhost);
+                               return;
+                       }
+               }
+
+               /* We are still here..we didn't match */
+               cmdbuf[0] = '\0';
+               for (x = 0; rehash_commands[x].cmd != NULL && rehash_commands[x].handler != NULL;
+                    x++)
+               {
+                       strlcat(cmdbuf, " ", sizeof(cmdbuf));
+                       strlcat(cmdbuf, rehash_commands[x].cmd, sizeof(cmdbuf));
+               }
+               sendto_one(source_p, ":%s NOTICE %s :rehash one of:%s", me.name, source_p->name,
+                          cmdbuf);
+       }
+       else
+       {
+               sendto_one(source_p, form_str(RPL_REHASHING), me.name, source_p->name,
+                          ConfigFileEntry.configfile);
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "%s is rehashing server config file", get_oper_name(source_p));
+               ilog(L_MAIN, "REHASH From %s[%s]", get_oper_name(source_p),
+                    source_p->sockhost);
+               rehash(0);
+       }
+}
+
+/*
+ * mo_rehash - REHASH message handler
+ *
+ * parv[1] = rehash type or destination
+ * parv[2] = destination
+ */
+static int
+mo_rehash(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       const char *type = NULL, *target_server = NULL;
+
+       if(!IsOperRehash(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS),
+                          me.name, source_p->name, "rehash");
+               return 0;
+       }
+
+       if (parc > 2)
+               type = parv[1], target_server = parv[2];
+       else if (parc > 1 && (strchr(parv[1], '.') || strchr(parv[1], '?') || strchr(parv[1], '*')))
+               type = NULL, target_server = parv[1];
+       else if (parc > 1)
+               type = parv[1], target_server = NULL;
+       else
+               type = NULL, target_server = NULL;
+
+       if (target_server != NULL)
+       {
+               if(!IsOperRemoteBan(source_p))
+               {
+                       sendto_one(source_p, form_str(ERR_NOPRIVS),
+                               me.name, source_p->name, "remoteban");
+                       return 0;
+               }
+               sendto_match_servs(source_p, target_server,
+                               CAP_ENCAP, NOCAPS,
+                               "ENCAP %s REHASH %s",
+                               target_server, type != NULL ? type : "");
+               if (match(target_server, me.name) == 0)
+                       return 0;
+       }
+
+       do_rehash(source_p, type);
+
+       return 0;
+}
+
+static int
+me_rehash(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+
+       if (!IsPerson(source_p))
+               return 0;
+
+       if (!find_shared_conf(source_p->username, source_p->host,
+                               source_p->user->server, SHARED_REHASH))
+               return 0;
+
+       do_rehash(source_p, parc > 1 ? parv[1] : NULL);
+
+       return 0;
+}
diff --git a/modules/m_restart.c b/modules/m_restart.c
new file mode 100644 (file)
index 0000000..aac90db
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_restart.c: Exits and re-runs ircd.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_restart.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "common.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "restart.h"
+#include "s_log.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+
+static int mo_restart(struct Client *, struct Client *, int, const char **);
+
+struct Message restart_msgtab = {
+       "RESTART", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_restart, 0}}
+};
+
+mapi_clist_av1 restart_clist[] = { &restart_msgtab, NULL };
+DECLARE_MODULE_AV1(restart, NULL, NULL, restart_clist, NULL, NULL, "$Revision: 254 $");
+
+/*
+ * mo_restart
+ *
+ */
+static int
+mo_restart(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       char buf[BUFSIZE];
+       dlink_node *ptr;
+       struct Client *target_p;
+
+       if(!IsOperDie(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS),
+                          me.name, source_p->name, "die");
+               return 0;
+       }
+
+       if(parc < 2 || EmptyString(parv[1]))
+       {
+               sendto_one(source_p, ":%s NOTICE %s :Need server name /restart %s",
+                          me.name, source_p->name, me.name);
+               return 0;
+       }
+       else if(irccmp(parv[1], me.name))
+       {
+               sendto_one(source_p, ":%s NOTICE %s :Mismatch on /restart %s",
+                          me.name, source_p->name, me.name);
+               return 0;
+       }
+
+       DLINK_FOREACH(ptr, lclient_list.head)
+       {
+               target_p = ptr->data;
+
+               sendto_one(target_p,
+                          ":%s NOTICE %s :Server Restarting. %s",
+                          me.name, target_p->name, get_client_name(source_p, HIDE_IP));
+       }
+
+       DLINK_FOREACH(ptr, serv_list.head)
+       {
+               target_p = ptr->data;
+
+               sendto_one(target_p, ":%s ERROR :Restart by %s",
+                          me.name, get_client_name(source_p, HIDE_IP));
+       }
+
+       ircsprintf(buf, "Server RESTART by %s", get_client_name(source_p, HIDE_IP));
+       restart(buf);
+
+       return 0;
+}
diff --git a/modules/m_resv.c b/modules/m_resv.c
new file mode 100644 (file)
index 0000000..b2e2802
--- /dev/null
@@ -0,0 +1,611 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_resv.c: Reserves(jupes) a nickname or channel.
+ *
+ *  Copyright (C) 2001-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_resv.c 3045 2006-12-26 23:16:57Z jilles $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "channel.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_serv.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "hash.h"
+#include "s_log.h"
+#include "sprintf_irc.h"
+
+static int mo_resv(struct Client *, struct Client *, int, const char **);
+static int ms_resv(struct Client *, struct Client *, int, const char **);
+static int me_resv(struct Client *, struct Client *, int, const char **);
+static int mo_unresv(struct Client *, struct Client *, int, const char **);
+static int ms_unresv(struct Client *, struct Client *, int, const char **);
+static int me_unresv(struct Client *, struct Client *, int, const char **);
+
+struct Message resv_msgtab = {
+       "RESV", 0, 0, 0, MFLG_SLOW | MFLG_UNREG,
+       {mg_ignore, mg_not_oper, {ms_resv, 4}, {ms_resv, 4}, {me_resv, 5}, {mo_resv, 3}}
+};
+struct Message unresv_msgtab = {
+       "UNRESV", 0, 0, 0, MFLG_SLOW | MFLG_UNREG,
+       {mg_ignore, mg_not_oper, {ms_unresv, 3}, {ms_unresv, 3}, {me_unresv, 2}, {mo_unresv, 2}}
+};
+
+mapi_clist_av1 resv_clist[] = {        &resv_msgtab, &unresv_msgtab, NULL };
+DECLARE_MODULE_AV1(resv, NULL, NULL, resv_clist, NULL, NULL, "$Revision: 3045 $");
+
+static void parse_resv(struct Client *source_p, const char *name,
+                       const char *reason, int temp_time);
+static void propagate_resv(struct Client *source_p, const char *target,
+                       int temp_time, const char *name, const char *reason);
+static void cluster_resv(struct Client *source_p, int temp_time, 
+                       const char *name, const char *reason);
+
+static void handle_remote_unresv(struct Client *source_p, const char *name);
+static void remove_resv(struct Client *source_p, const char *name);
+static int remove_temp_resv(struct Client *source_p, const char *name);
+
+/*
+ * mo_resv()
+ *      parv[0] = sender prefix
+ *      parv[1] = channel/nick to forbid
+ *      parv[2] = reason
+ */
+static int
+mo_resv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       const char *name;
+       const char *reason;
+       const char *target_server = NULL;
+       int temp_time;
+       int loc = 1;
+
+       /* RESV [time] <name> [ON <server>] :<reason> */
+
+       if((temp_time = valid_temp_time(parv[loc])) >= 0)
+               loc++;
+       /* we just set temp_time to -1! */
+       else
+               temp_time = 0;
+
+       name = parv[loc];
+       loc++;
+
+       if((parc >= loc+2) && (irccmp(parv[loc], "ON") == 0))
+       {
+               if(!IsOperRemoteBan(source_p))
+               {
+                       sendto_one(source_p, form_str(ERR_NOPRIVS),
+                               me.name, source_p->name, "remoteban");
+                       return 0;
+               }
+
+               target_server = parv[loc+1];
+               loc += 2;
+       }
+
+       if(parc <= loc || EmptyString(parv[loc]))
+       {
+               sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+                          me.name, source_p->name, "RESV");
+               return 0;
+       }
+
+       reason = parv[loc];
+
+       /* remote resv.. */
+       if(target_server)
+       {
+               propagate_resv(source_p, target_server, temp_time, name, reason);
+
+               if(match(target_server, me.name) == 0)
+                       return 0;
+       }
+       else if(dlink_list_length(&cluster_conf_list) > 0)
+               cluster_resv(source_p, temp_time, name, reason);
+
+       parse_resv(source_p, name, reason, temp_time);
+
+       return 0;
+}
+
+/* ms_resv()
+ *     parv[0] = sender prefix
+ *     parv[1] = target server
+ *     parv[2] = channel/nick to forbid
+ *     parv[3] = reason
+ */
+static int
+ms_resv(struct Client *client_p, struct Client *source_p,
+       int parc, const char *parv[])
+{
+       /* parv[0]  parv[1]        parv[2]  parv[3]
+        * oper     target server  resv     reason
+        */
+       propagate_resv(source_p, parv[1], 0, parv[2], parv[3]);
+
+       if(!match(parv[1], me.name))
+               return 0;
+
+       if(!IsPerson(source_p))
+               return 0;
+
+       parse_resv(source_p, parv[2], parv[3], 0);
+       return 0;
+}
+
+static int
+me_resv(struct Client *client_p, struct Client *source_p,
+       int parc, const char *parv[])
+{
+       /* time name 0 :reason */
+       if(!IsPerson(source_p))
+               return 0;
+
+       parse_resv(source_p, parv[2], parv[4], atoi(parv[1]));
+       return 0;
+}
+
+/* parse_resv()
+ *
+ * inputs       - source_p if error messages wanted
+ *             - thing to resv
+ *             - reason for resv
+ * outputs     -
+ * side effects - will parse the resv and create it if valid
+ */
+static void
+parse_resv(struct Client *source_p, const char *name, 
+          const char *reason, int temp_time)
+{
+       struct ConfItem *aconf;
+
+       if(!MyClient(source_p) && 
+          !find_shared_conf(source_p->username, source_p->host,
+                       source_p->user->server, 
+                       (temp_time > 0) ? SHARED_TRESV : SHARED_PRESV))
+               return;
+
+       if(IsChannelName(name))
+       {
+               if(hash_find_resv(name))
+               {
+                       sendto_one_notice(source_p,
+                                       ":A RESV has already been placed on channel: %s",
+                                       name);
+                       return;
+               }
+
+               if(strlen(name) > CHANNELLEN)
+               {
+                       sendto_one_notice(source_p, ":Invalid RESV length: %s",
+                                         name);
+                       return;
+               }
+
+               if(strchr(reason, '"'))
+               {
+                       sendto_one_notice(source_p,
+                                       ":Invalid character '\"' in comment");
+                       return;
+               }
+
+               aconf = make_conf();
+               aconf->status = CONF_RESV_CHANNEL;
+               aconf->port = 0;
+               DupString(aconf->name, name);
+               DupString(aconf->passwd, reason);
+               add_to_resv_hash(aconf->name, aconf);
+
+               if(temp_time > 0)
+               {
+                       aconf->hold = CurrentTime + temp_time;
+
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "%s added temporary %d min. RESV for [%s] [%s]",
+                                    get_oper_name(source_p), temp_time / 60,
+                                    name, reason);
+                       ilog(L_KLINE, "R %s %d %s %s",
+                               get_oper_name(source_p), temp_time / 60,
+                               name, reason);
+                       sendto_one_notice(source_p, ":Added temporary %d min. RESV [%s]",
+                                       temp_time / 60, name);
+               }
+               else
+                       write_confitem(RESV_TYPE, source_p, NULL, aconf->name, 
+                                       aconf->passwd, NULL, NULL, 0);
+       }
+       else if(clean_resv_nick(name))
+       {
+               if(strlen(name) > NICKLEN*2)
+               {
+                       sendto_one_notice(source_p, ":Invalid RESV length: %s",
+                                          name);
+                       return;
+               }
+
+               if(strchr(reason, '"'))
+               {
+                       sendto_one_notice(source_p,
+                                       ":Invalid character '\"' in comment");
+                       return;
+               }
+
+               if(!valid_wild_card_simple(name))
+               {
+                       sendto_one_notice(source_p,
+                                          ":Please include at least %d non-wildcard "
+                                          "characters with the resv",
+                                          ConfigFileEntry.min_nonwildcard_simple);
+                       return;
+               }
+
+               if(find_nick_resv(name))
+               {
+                       sendto_one_notice(source_p,
+                                          ":A RESV has already been placed on nick: %s",
+                                          name);
+                       return;
+               }
+
+               aconf = make_conf();
+               aconf->status = CONF_RESV_NICK;
+               aconf->port = 0;
+               DupString(aconf->name, name);
+               DupString(aconf->passwd, reason);
+               dlinkAddAlloc(aconf, &resv_conf_list);
+
+               if(temp_time > 0)
+               {
+                       aconf->hold = CurrentTime + temp_time;
+
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "%s added temporary %d min. RESV for [%s] [%s]",
+                                    get_oper_name(source_p), temp_time / 60,
+                                    name, reason);
+                       ilog(L_KLINE, "R %s %d %s %s",
+                               get_oper_name(source_p), temp_time / 60,
+                               name, reason);
+                       sendto_one_notice(source_p, ":Added temporary %d min. RESV [%s]",
+                                       temp_time / 60, name);
+               }
+               else
+                       write_confitem(RESV_TYPE, source_p, NULL, aconf->name, 
+                                       aconf->passwd, NULL, NULL, 0);
+       }
+       else
+               sendto_one_notice(source_p,
+                                 ":You have specified an invalid resv: [%s]",
+                                 name);
+}
+
+static void 
+propagate_resv(struct Client *source_p, const char *target,
+               int temp_time, const char *name, const char *reason)
+{
+       if(!temp_time)
+       {
+               sendto_match_servs(source_p, target,
+                               CAP_CLUSTER, NOCAPS,
+                               "RESV %s %s :%s",
+                               target, name, reason);
+               sendto_match_servs(source_p, target,
+                               CAP_ENCAP, CAP_CLUSTER,
+                               "ENCAP %s RESV %d %s 0 :%s",
+                               target, temp_time, name, reason);
+       }
+       else
+               sendto_match_servs(source_p, target,
+                               CAP_ENCAP, NOCAPS,
+                               "ENCAP %s RESV %d %s 0 :%s",
+                               target, temp_time, name, reason);
+}
+
+static void
+cluster_resv(struct Client *source_p, int temp_time, const char *name,
+               const char *reason)
+{
+       struct remote_conf *shared_p;
+       dlink_node *ptr;
+
+       DLINK_FOREACH(ptr, cluster_conf_list.head)
+       {
+               shared_p = ptr->data;
+
+               /* old protocol cant handle temps, and we dont really want
+                * to convert them to perm.. --fl
+                */
+               if(!temp_time)
+               {
+                       if(!(shared_p->flags & SHARED_PRESV))
+                               continue;
+
+                       sendto_match_servs(source_p, shared_p->server,
+                                       CAP_CLUSTER, NOCAPS,
+                                       "RESV %s %s :%s",
+                                       shared_p->server, name, reason);
+                       sendto_match_servs(source_p, shared_p->server,
+                                       CAP_ENCAP, CAP_CLUSTER,
+                                       "ENCAP %s RESV 0 %s 0 :%s",
+                                       shared_p->server, name, reason);
+               }
+               else if(shared_p->flags & SHARED_TRESV)
+                       sendto_match_servs(source_p, shared_p->server,
+                                       CAP_ENCAP, NOCAPS,
+                                       "ENCAP %s RESV %d %s 0 :%s",
+                                       shared_p->server, temp_time, name, reason);
+       }
+}
+
+
+/*
+ * mo_unresv()
+ *     parv[0] = sender prefix
+ *     parv[1] = channel/nick to unforbid
+ */
+static int
+mo_unresv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       if((parc == 4) && (irccmp(parv[2], "ON") == 0))
+       {
+               if(!IsOperRemoteBan(source_p))
+               {
+                       sendto_one(source_p, form_str(ERR_NOPRIVS),
+                               me.name, source_p->name, "remoteban");
+                       return 0;
+               }
+
+               propagate_generic(source_p, "UNRESV", parv[3], CAP_CLUSTER,
+                               "%s", parv[1]);
+
+               if(match(parv[3], me.name) == 0)
+                       return 0;
+       }
+       else if(dlink_list_length(&cluster_conf_list) > 0)
+               cluster_generic(source_p, "UNRESV", SHARED_UNRESV, CAP_CLUSTER,
+                               "%s", parv[1]);
+
+       if(remove_temp_resv(source_p, parv[1]))
+               return 0;
+
+       remove_resv(source_p, parv[1]);
+       return 0;
+}
+
+/* ms_unresv()
+ *     parv[0] = sender prefix
+ *     parv[1] = target server
+ *     parv[2] = resv to remove
+ */
+static int
+ms_unresv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       /* parv[0]  parv[1]        parv[2]
+        * oper     target server  resv to remove
+        */
+       propagate_generic(source_p, "UNRESV", parv[1], CAP_CLUSTER,
+                       "%s", parv[2]);
+
+       if(!match(parv[1], me.name))
+               return 0;
+
+       if(!IsPerson(source_p))
+               return 0;
+
+       handle_remote_unresv(source_p, parv[2]);
+       return 0;
+}
+
+static int
+me_unresv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       /* name */
+       if(!IsPerson(source_p))
+               return 0;
+
+       handle_remote_unresv(source_p, parv[1]);
+       return 0;
+}
+
+static void
+handle_remote_unresv(struct Client *source_p, const char *name)
+{
+       if(!find_shared_conf(source_p->username, source_p->host,
+                               source_p->user->server, SHARED_UNRESV))
+               return;
+
+       if(remove_temp_resv(source_p, name))
+               return;
+
+       remove_resv(source_p, name);
+
+       return;
+}
+
+static int
+remove_temp_resv(struct Client *source_p, const char *name)
+{
+       struct ConfItem *aconf = NULL;
+
+       if(IsChannelName(name))
+       {
+               if((aconf = hash_find_resv(name)) == NULL)
+                       return 0;
+
+               /* its permanent, let remove_resv do it properly */
+               if(!aconf->hold)
+                       return 0;
+
+               del_from_resv_hash(name, aconf);
+               free_conf(aconf);
+       }
+       else
+       {
+               dlink_node *ptr;
+
+               DLINK_FOREACH(ptr, resv_conf_list.head)
+               {
+                       aconf = ptr->data;
+
+                       if(irccmp(aconf->name, name))
+                               aconf = NULL;
+                       else
+                               break;
+               }
+
+               if(aconf == NULL)
+                       return 0;
+
+               /* permanent, remove_resv() needs to do it properly */
+               if(!aconf->hold)
+                       return 0;
+
+               /* already have ptr from the loop above.. */
+               dlinkDestroy(ptr, &resv_conf_list);
+               free_conf(aconf);
+       }
+
+       sendto_one_notice(source_p, ":RESV for [%s] is removed", name);
+       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                       "%s has removed the RESV for: [%s]", 
+                       get_oper_name(source_p), name);
+       ilog(L_KLINE, "UR %s %s", get_oper_name(source_p), name);
+
+       return 1;
+}
+
+/* remove_resv()
+ *
+ * inputs      - client removing the resv
+ *             - resv to remove
+ * outputs     -
+ * side effects - resv if found, is removed
+ */
+static void
+remove_resv(struct Client *source_p, const char *name)
+{
+       FILE *in, *out;
+       char buf[BUFSIZE];
+       char buff[BUFSIZE];
+       char temppath[BUFSIZE];
+       const char *filename;
+       mode_t oldumask;
+       char *p;
+       int error_on_write = 0;
+       int found_resv = 0;
+
+       ircsprintf(temppath, "%s.tmp", ConfigFileEntry.resvfile);
+       filename = get_conf_name(RESV_TYPE);
+
+       if((in = fopen(filename, "r")) == NULL)
+       {
+               sendto_one_notice(source_p, ":Cannot open %s", filename);
+               return;
+       }
+
+       oldumask = umask(0);
+
+       if((out = fopen(temppath, "w")) == NULL)
+       {
+               sendto_one_notice(source_p, ":Cannot open %s", temppath);
+               fclose(in);
+               umask(oldumask);
+               return;
+       }
+
+       umask(oldumask);
+
+       while (fgets(buf, sizeof(buf), in))
+       {
+               const char *resv_name;
+
+               if(error_on_write)
+               {
+                       if(temppath != NULL)
+                               (void) unlink(temppath);
+
+                       break;
+               }
+
+               strlcpy(buff, buf, sizeof(buff));
+
+               if((p = strchr(buff, '\n')) != NULL)
+                       *p = '\0';
+
+               if((*buff == '\0') || (*buff == '#'))
+               {
+                       error_on_write = (fputs(buf, out) < 0) ? YES : NO;
+                       continue;
+               }
+
+               if((resv_name = getfield(buff)) == NULL)
+               {
+                       error_on_write = (fputs(buf, out) < 0) ? YES : NO;
+                       continue;
+               }
+
+               if(irccmp(resv_name, name) == 0)
+               {
+                       found_resv++;
+               }
+               else
+               {
+                       error_on_write = (fputs(buf, out) < 0) ? YES : NO;
+               }
+       }
+
+       fclose(in);
+       if (fclose(out))
+               error_on_write = YES;
+
+       if(error_on_write)
+       {
+               sendto_one_notice(source_p, ":Couldn't write temp resv file, aborted");
+               return;
+       }
+       else if(!found_resv)
+       {
+               sendto_one_notice(source_p, ":No RESV for %s", name);
+
+               if(temppath != NULL)
+                       (void) unlink(temppath);
+
+               return;
+       }
+
+       if (rename(temppath, filename))
+       {
+               sendto_one_notice(source_p, ":Couldn't rename temp file, aborted");
+               return;
+       }
+       rehash_bans(0);
+
+       sendto_one_notice(source_p, ":RESV for [%s] is removed", name);
+       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                            "%s has removed the RESV for: [%s]", get_oper_name(source_p), name);
+       ilog(L_KLINE, "UR %s %s", get_oper_name(source_p), name);
+}
diff --git a/modules/m_sasl.c b/modules/m_sasl.c
new file mode 100644 (file)
index 0000000..451cb44
--- /dev/null
@@ -0,0 +1,208 @@
+/* modules/m_sasl.c
+ *   Copyright (C) 2006 Michael Tharp <gxti@partiallystapled.com>
+ *   Copyright (C) 2006 charybdis development team
+ *
+ * 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.The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: m_sasl.c 1409 2006-05-21 14:46:17Z jilles $
+ */
+
+#include "stdinc.h"
+
+#include "client.h"
+#include "hash.h"
+#include "send.h"
+#include "msg.h"
+#include "modules.h"
+#include "numeric.h"
+#include "s_serv.h"
+#include "s_stats.h"
+#include "string.h"
+
+static int mr_authenticate(struct Client *, struct Client *, int, const char **);
+static int me_sasl(struct Client *, struct Client *, int, const char **);
+
+static void abort_sasl(struct Client *);
+static void abort_sasl_exit(hook_data_client_exit *);
+
+struct Message authenticate_msgtab = {
+       "AUTHENTICATE", 0, 0, 0, MFLG_SLOW,
+       {{mr_authenticate, 2}, mg_reg, mg_ignore, mg_ignore, mg_ignore, mg_reg}
+};
+struct Message sasl_msgtab = {
+       "SASL", 0, 0, 0, MFLG_SLOW,
+       {mg_ignore, mg_ignore, mg_ignore, mg_ignore, {me_sasl, 5}, mg_ignore}
+};
+
+mapi_clist_av1 sasl_clist[] = { 
+       &authenticate_msgtab, &sasl_msgtab, NULL
+};
+mapi_hfn_list_av1 sasl_hfnlist[] = {
+       { "new_local_user",     (hookfn) abort_sasl },
+       { "client_exit",        (hookfn) abort_sasl_exit },
+       { NULL, NULL }
+};
+
+DECLARE_MODULE_AV1(sasl, NULL, NULL, sasl_clist, NULL, sasl_hfnlist, "$Revision: 1409 $");
+
+static int
+mr_authenticate(struct Client *client_p, struct Client *source_p,
+       int parc, const char *parv[])
+{
+       struct Client *agent_p = NULL;
+
+       /* They really should use CAP for their own sake. */
+       if(!IsCapable(source_p, CLICAP_SASL))
+               return 0;
+
+       if (strlen(client_p->id) == 3)
+       {
+               exit_client(client_p, client_p, client_p, "Mixing client and server protocol");
+               return 0;
+       }
+
+       if(source_p->preClient->sasl_complete)
+       {
+               sendto_one(source_p, form_str(ERR_SASLALREADY), me.name, EmptyString(source_p->name) ? "*" : source_p->name);
+               return 0;
+       }
+
+       if(strlen(parv[1]) > 400)
+       {
+               sendto_one(source_p, form_str(ERR_SASLTOOLONG), me.name, EmptyString(source_p->name) ? "*" : source_p->name);
+               return 0;
+       }
+
+       if(!*source_p->id)
+       {
+               /* Allocate a UID. */
+               strcpy(source_p->id, generate_uid());
+               add_to_id_hash(source_p->id, source_p);
+       }
+
+       if(*source_p->preClient->sasl_agent)
+               agent_p = find_id(source_p->preClient->sasl_agent);
+
+       if(agent_p == NULL)
+               sendto_server(NULL, NULL, CAP_TS6|CAP_ENCAP, NOCAPS, ":%s ENCAP * SASL %s * S %s", me.id,
+                               source_p->id, parv[1]);
+       else
+               sendto_one(agent_p, ":%s ENCAP %s SASL %s %s C %s", me.id, agent_p->servptr->name,
+                               source_p->id, agent_p->id, parv[1]);
+       source_p->preClient->sasl_out++;
+
+       return 0;
+}
+
+static int
+me_sasl(struct Client *client_p, struct Client *source_p,
+       int parc, const char *parv[])
+{
+       struct Client *target_p, *agent_p;
+
+       /* Let propagate if not addressed to us, or if broadcast.
+        * Only SASL agents can answer global requests.
+        */
+       if(strncmp(parv[2], me.id, 3))
+               return 0;
+
+       if((target_p = find_id(parv[2])) == NULL)
+               return 0;
+
+       if(target_p->preClient == NULL)
+               return 0;
+
+       if((agent_p = find_id(parv[1])) == NULL)
+               return 0;
+
+       if(source_p != agent_p->servptr) /* WTF?! */
+               return 0;
+
+       /* We only accept messages from SASL agents; these must have umode +S
+        * (so the server must be listed in a service{} block).
+        */
+       if(!IsService(agent_p))
+               return 0;
+
+       /* Reject if someone has already answered. */
+       if(*target_p->preClient->sasl_agent && strncmp(parv[1], target_p->preClient->sasl_agent, IDLEN))
+               return 0;
+       else if(!*target_p->preClient->sasl_agent)
+               strlcpy(target_p->preClient->sasl_agent, parv[1], IDLEN);
+
+       if(*parv[3] == 'C')
+               sendto_one(target_p, "AUTHENTICATE %s", parv[4]);
+       else if(*parv[3] == 'D')
+       {
+               if(*parv[4] == 'F')
+                       sendto_one(target_p, form_str(ERR_SASLFAIL), me.name, EmptyString(target_p->name) ? "*" : target_p->name);
+               else if(*parv[4] == 'S') {
+                       sendto_one(target_p, form_str(RPL_SASLSUCCESS), me.name, EmptyString(target_p->name) ? "*" : target_p->name);
+                       target_p->preClient->sasl_complete = 1;
+                       ServerStats->is_ssuc++;
+               }
+               *target_p->preClient->sasl_agent = '\0'; /* Blank the stored agent so someone else can answer */
+       }
+       
+       return 0;
+}
+
+/* If the client never finished authenticating but is
+ * registering anyway, abort the exchange.
+ */
+static void
+abort_sasl(struct Client *data)
+{
+       if(data->preClient->sasl_out == 0 || data->preClient->sasl_complete)
+               return;
+
+       data->preClient->sasl_out = data->preClient->sasl_complete = 0;
+       ServerStats->is_sbad++;
+
+       if(!IsClosing(data))
+               sendto_one(data, form_str(ERR_SASLABORTED), me.name, EmptyString(data->name) ? "*" : data->name);
+
+       if(*data->preClient->sasl_agent)
+       {
+               struct Client *agent_p = find_id(data->preClient->sasl_agent);
+               if(agent_p)
+               {
+                       sendto_one(agent_p, ":%s ENCAP %s SASL %s %s D A", me.id, agent_p->servptr->name,
+                                       data->id, agent_p->id);
+                       return;
+               }
+       }
+
+       sendto_server(NULL, NULL, CAP_TS6|CAP_ENCAP, NOCAPS, ":%s ENCAP * SASL %s * D A", me.id,
+                       data->id);
+}
+
+static void
+abort_sasl_exit(hook_data_client_exit *data)
+{
+       if (data->target->preClient)
+               abort_sasl(data->target);
+}
+
diff --git a/modules/m_scan.c b/modules/m_scan.c
new file mode 100644 (file)
index 0000000..7fdb688
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ *  charybdis: an advanced Internet Relay Chat Daemon(ircd).
+ *  m_scan.c: Provides information about various targets on various topics
+ *
+ *  Copyright (c) 2006 William Pitcock <nenolod -at- nenolod.net>
+ *
+ *  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.The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ *  $Id: m_scan.c 1853 2006-08-24 18:30:52Z jilles $
+ */
+
+#include "stdinc.h"
+#include "class.h"
+#include "hook.h"
+#include "client.h"
+#include "hash.h"
+#include "common.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "commio.h"
+#include "s_serv.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "s_user.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+
+static int mo_scan(struct Client *, struct Client *, int, const char **);
+static int scan_umodes(struct Client *, struct Client *, int, const char **);
+/*static int scan_cmodes(struct Client *, struct Client *, int, const char **);*/
+
+struct Message scan_msgtab = {
+       "SCAN", 0, 0, 0, MFLG_SLOW,
+       {mg_ignore, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_scan, 2}}
+};
+
+mapi_clist_av1 scan_clist[] = { &scan_msgtab, NULL };
+DECLARE_MODULE_AV1(scan, NULL, NULL, scan_clist, NULL, NULL, "$Revision: 1853 $");
+
+typedef int (*scan_handler)(struct Client *, struct Client *, int, 
+       const char **);
+
+struct scan_cmd {
+       const char *name;
+       int operlevel;
+       scan_handler handler;
+} scan_cmds[] = {
+       {"UMODES", L_OPER, scan_umodes},
+       {NULL, 0, NULL}
+};
+
+static const char *empty_sockhost = "255.255.255.255";
+static const char *spoofed_sockhost = "0";
+
+/*
+ * m_scan
+ *      parv[0] = sender prefix
+ *      parv[1] = options [or target]
+ *     parv[2] = [target]
+ */
+static int
+mo_scan(struct Client *client_p, struct Client *source_p, int parc, 
+       const char *parv[])
+{
+       struct scan_cmd *sptr;
+
+       for (sptr = scan_cmds; sptr->name != NULL; sptr++)
+       {
+               if (!irccmp(sptr->name, parv[1]))
+               {
+                       if (sptr->operlevel == L_ADMIN &&
+                               !IsOperAdmin(source_p))
+                               return -1;
+                       else
+                               return sptr->handler(client_p, source_p, parc, parv);
+               }
+       }
+
+       sendto_one_notice(source_p, ":*** %s is not an implemented SCAN target",
+                         parv[1]);
+
+       return 0;
+}
+
+static int
+scan_umodes(struct Client *client_p, struct Client *source_p, int parc,
+       const char *parv[])
+{
+       unsigned int allowed_umodes = 0, disallowed_umodes = 0;
+       int what = MODE_ADD;
+       int mode;
+       int list_users = YES;
+       int list_max = 0;
+       int list_count = 0, count = 0;
+       const char *mask = NULL;
+       const char *c;
+       struct Client *target_p;
+       dlink_list *target_list = &lclient_list;        /* local clients only by default */
+       dlink_node *tn;
+       int i;
+       const char *sockhost;
+       char buf[512];
+
+       if (parc < 3)
+       {
+               if (MyClient(source_p))
+                       sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+                               me.name, source_p->name, "SCAN UMODES");
+
+               return -1;
+       }
+
+       for (c = parv[2]; *c; c++)
+       {
+               switch(*c)
+               {
+                       case '+':
+                               what = MODE_ADD;
+                               break;
+                       case '-':
+                               what = MODE_DEL;
+                               break;
+                       default:
+                               if ((mode = user_modes[(unsigned char) *c]) != 0)
+                               {
+                                       if (what == MODE_ADD)
+                                               allowed_umodes |= mode;
+                                       else
+                                               disallowed_umodes |= mode;
+                               }
+               }
+       }
+
+       for (i = 3; i < parc; i++)
+       {
+               if (!irccmp(parv[i], "no-list"))
+                       list_users = NO;
+               else if (!irccmp(parv[i], "list"))
+                       list_users = YES;
+               else if (!irccmp(parv[i], "global"))
+                       target_list = &global_client_list;
+               else if (i < (parc - 1))
+               {
+                       if (!irccmp(parv[i], "list-max"))
+                               list_max = atoi(parv[++i]);
+                       else if (!irccmp(parv[i], "mask"))
+                               mask = parv[++i];
+               }
+       }
+       if (target_list == &global_client_list && (list_users || mask))
+       {
+               if (IsOperSpy(source_p))
+               {
+                       if (!ConfigFileEntry.operspy_dont_care_user_info)
+                       {
+                               strlcpy(buf, "UMODES", sizeof buf);
+                               for (i = 2; i < parc; i++)
+                               {
+                                       strlcat(buf, " ", sizeof buf);
+                                       strlcat(buf, parv[i], sizeof buf);
+                               }
+                               report_operspy(source_p, "SCAN", buf);
+                       }
+               }
+               else
+               {
+                       sendto_one(source_p, form_str(ERR_NOPRIVS),
+                                  me.name, source_p->name, "oper_spy");
+                       return -1;
+               }
+       }
+
+       DLINK_FOREACH(tn, target_list->head)
+       {
+               unsigned int working_umodes = 0;
+               char maskbuf[BUFSIZE];
+
+               target_p = tn->data;
+
+               if (!IsClient(target_p))
+                       continue;
+
+               if(EmptyString(target_p->sockhost))
+                       sockhost = empty_sockhost;
+               else if(!show_ip(source_p, target_p))
+                       sockhost = spoofed_sockhost;
+               else
+                       sockhost = target_p->sockhost;
+
+               working_umodes = target_p->umodes;
+
+               /* require that we have the allowed umodes... */
+               if ((working_umodes & allowed_umodes) != allowed_umodes)
+                       continue;
+
+               /* require that we have NONE of the disallowed ones */
+               if ((working_umodes & disallowed_umodes) != 0)
+                       continue;
+
+               if (mask != NULL)
+               {
+                       ircsnprintf(maskbuf, BUFSIZE, "%s!%s@%s",
+                               target_p->name, target_p->username, target_p->host);
+
+                       if (!match(mask, maskbuf))
+                               continue;
+               }
+
+               if (list_users && (!list_max || (list_count < list_max)))
+               {
+                       char modebuf[BUFSIZE];
+                       char *m = modebuf;
+
+                       *m++ = '+';
+
+                       for (i = 0; i < 128; i++)
+                       {
+                               if (target_p->umodes & user_modes[i])
+                                       *m++ = (char) i;
+                       }
+
+                       *m++ = '\0';
+
+                       list_count++;
+
+                       sendto_one_numeric(source_p, RPL_SCANUMODES,
+                                               form_str(RPL_SCANUMODES),
+                                               target_p->name, target_p->username,
+                                               target_p->host, sockhost, 
+                                               target_p->servptr->name, modebuf,
+                                               target_p->info);
+               }
+               count++;
+       }
+
+       sendto_one_numeric(source_p, RPL_SCANMATCHED,
+                       form_str(RPL_SCANMATCHED), count);
+
+       return 0;
+}
diff --git a/modules/m_services.c b/modules/m_services.c
new file mode 100644 (file)
index 0000000..f124fc4
--- /dev/null
@@ -0,0 +1,331 @@
+/* modules/m_services.c
+ *   Copyright (C) 2005 Lee Hardy <lee -at- leeh.co.uk>
+ *   Copyright (C) 2005 ircd-ratbox development team
+ *
+ * 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.The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: m_services.c 1907 2006-08-29 19:18:15Z jilles $
+ */
+
+#include "stdinc.h"
+
+#include "tools.h"
+#include "send.h"
+#include "channel.h"
+#include "client.h"
+#include "common.h"
+#include "config.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "memory.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "s_serv.h"
+#include "hash.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "sprintf_irc.h"
+#include "whowas.h"
+#include "monitor.h"
+
+static int me_su(struct Client *, struct Client *, int, const char **);
+static int me_login(struct Client *, struct Client *, int, const char **);
+static int me_rsfnc(struct Client *, struct Client *, int, const char **);
+static int me_nickdelay(struct Client *, struct Client *, int, const char **);
+
+static void h_svc_server_introduced(hook_data_client *);
+static void h_svc_whois(hook_data_client *);
+static void h_svc_stats(hook_data_int *);
+
+struct Message su_msgtab = {
+       "SU", 0, 0, 0, MFLG_SLOW,
+       {mg_ignore, mg_ignore, mg_ignore, mg_ignore, {me_su, 2}, mg_ignore}
+};
+struct Message login_msgtab = {
+       "LOGIN", 0, 0, 0, MFLG_SLOW,
+       {mg_ignore, mg_ignore, mg_ignore, mg_ignore, {me_login, 2}, mg_ignore}
+};
+struct Message rsfnc_msgtab = {
+       "RSFNC", 0, 0, 0, MFLG_SLOW,
+       {mg_ignore, mg_ignore, mg_ignore, mg_ignore, {me_rsfnc, 4}, mg_ignore}
+};
+struct Message nickdelay_msgtab = {
+       "NICKDELAY", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_ignore, mg_ignore, mg_ignore, {me_nickdelay, 3}, mg_ignore}
+};
+
+mapi_clist_av1 services_clist[] = { 
+       &su_msgtab, &login_msgtab, &rsfnc_msgtab, &nickdelay_msgtab, NULL
+};
+mapi_hfn_list_av1 services_hfnlist[] = {
+       { "doing_stats",        (hookfn) h_svc_stats },
+       { "doing_whois",        (hookfn) h_svc_whois },
+       { "doing_whois_global", (hookfn) h_svc_whois },
+       { "server_introduced",  (hookfn) h_svc_server_introduced },
+       { NULL, NULL }
+};
+
+DECLARE_MODULE_AV1(services, NULL, NULL, services_clist, NULL, services_hfnlist, "$Revision: 1907 $");
+
+static int
+me_su(struct Client *client_p, struct Client *source_p,
+       int parc, const char *parv[])
+{
+       struct Client *target_p;
+
+       if(!(source_p->flags & FLAGS_SERVICE))
+               return 0;
+
+       if((target_p = find_client(parv[1])) == NULL)
+               return 0;
+
+       if(!target_p->user)
+               return 0;
+
+       if(EmptyString(parv[2]))
+               target_p->user->suser[0] = '\0';
+       else
+               strlcpy(target_p->user->suser, parv[2], sizeof(target_p->user->suser));
+
+       invalidate_bancache_user(target_p);
+
+       return 0;
+}
+
+static int
+me_login(struct Client *client_p, struct Client *source_p,
+       int parc, const char *parv[])
+{
+       if(!IsPerson(source_p))
+               return 0;
+
+       strlcpy(source_p->user->suser, parv[1], sizeof(source_p->user->suser));
+       return 0;
+}
+
+static int
+clean_nick(const char *nick)
+{
+       int len = 0;
+
+       if(EmptyString(nick) || *nick == '-' || IsDigit(*nick))
+               return 0;
+
+       for(; *nick; nick++)
+       {
+               len++;
+               if(!IsNickChar(*nick))
+                       return 0;
+       }
+
+       if(len >= NICKLEN)
+               return 0;
+
+       return 1;
+}
+
+static int
+me_rsfnc(struct Client *client_p, struct Client *source_p,
+       int parc, const char *parv[])
+{
+       struct Client *target_p;
+       struct Client *exist_p;
+       time_t newts, curts;
+
+       if(!(source_p->flags & FLAGS_SERVICE))
+               return 0;
+
+       if((target_p = find_person(parv[1])) == NULL)
+               return 0;
+
+       if(!MyClient(target_p))
+               return 0;
+
+       if(!clean_nick(parv[2]))
+               return 0;
+
+       curts = atol(parv[4]);
+
+       /* if tsinfo is different from what it was when services issued the
+        * RSFNC, then we ignore it.  This can happen when a client changes
+        * nicknames before the RSFNC arrives.. --anfl
+        */
+       if(target_p->tsinfo != curts)
+               return 0;
+
+       if((exist_p = find_named_client(parv[2])))
+       {
+               char buf[BUFSIZE];
+
+               /* this would be one hell of a race condition to trigger
+                * this one given the tsinfo check above, but its here for 
+                * safety --anfl
+                */
+               if(target_p == exist_p)
+                       return 0;
+
+               if(MyClient(exist_p))
+                       sendto_one(exist_p, ":%s KILL %s :(Nickname regained by services)",
+                               me.name, exist_p->name);
+
+               exist_p->flags |= FLAGS_KILLED;
+               /* Do not send kills to servers for unknowns -- jilles */
+               if(IsClient(exist_p))
+                       kill_client_serv_butone(NULL, exist_p, "%s (Nickname regained by services)",
+                                               me.name);
+
+               snprintf(buf, sizeof(buf), "Killed (%s (Nickname regained by services))",
+                       me.name);
+               exit_client(NULL, exist_p, &me, buf);
+       }
+
+       newts = atol(parv[3]);
+
+       /* timestamp is older than 15mins, ignore it */
+       if(newts < (CurrentTime - 900))
+               newts = CurrentTime - 900;
+
+       target_p->tsinfo = newts;
+
+       monitor_signoff(target_p);
+
+       invalidate_bancache_user(target_p);
+
+       sendto_realops_snomask(SNO_NCHANGE, L_ALL,
+                       "Nick change: From %s to %s [%s@%s]",
+                       target_p->name, parv[2], target_p->username,
+                       target_p->host);
+
+       sendto_common_channels_local(target_p, ":%s!%s@%s NICK :%s",
+                               target_p->name, target_p->username,
+                               target_p->host, parv[2]);
+
+       add_history(target_p, 1);
+       sendto_server(NULL, NULL, CAP_TS6, NOCAPS, ":%s NICK %s :%ld",
+                       use_id(target_p), parv[2], (long) target_p->tsinfo);
+       sendto_server(NULL, NULL, NOCAPS, CAP_TS6, ":%s NICK %s :%ld",
+                       target_p->name, parv[2], (long) target_p->tsinfo);
+
+       del_from_client_hash(target_p->name, target_p);
+       strcpy(target_p->name, parv[2]);
+       add_to_client_hash(target_p->name, target_p);
+
+       monitor_signon(target_p);
+
+       del_all_accepts(target_p);
+
+       comm_note(target_p->localClient->fd, "Nick: %s", target_p->name);
+       return 0;
+}
+
+/*
+** me_nickdelay
+**      parv[0] = sender prefix
+**      parv[1] = duration in seconds (0 to remove)
+**      parv[2] = nick
+*/
+static int
+me_nickdelay(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       int duration;
+       struct nd_entry *nd;
+
+       if(!(source_p->flags & FLAGS_SERVICE))
+               return 0;
+
+       duration = atoi(parv[1]);
+       if (duration <= 0)
+       {
+               nd = hash_find_nd(parv[2]);
+               if (nd != NULL)
+                       free_nd_entry(nd);
+       }
+       else
+       {
+               if (duration > 86400)
+                       duration = 86400;
+               add_nd_entry(parv[2]);
+               nd = hash_find_nd(parv[2]);
+               if (nd != NULL)
+                       nd->expire = CurrentTime + duration;
+       }
+
+       return 0;
+}
+
+static void
+h_svc_server_introduced(hook_data_client *hdata)
+{
+       dlink_node *ptr;
+
+       DLINK_FOREACH(ptr, service_list.head)
+       {
+               if(!irccmp((const char *) ptr->data, hdata->target->name))
+               {
+                       hdata->target->flags |= FLAGS_SERVICE;
+                       return;
+               }
+       }
+}
+
+static void
+h_svc_whois(hook_data_client *data)
+{
+       char *p = data->target->user->suser;
+       if(!EmptyString(p))
+       {
+               /* Try to strip off any leading digits as this may be used to
+                * store both an ID number and an account name in one field.
+                * If only digits are present, leave as is.
+                */
+               while(IsDigit(*p))
+                       p++;
+               if(*p == '\0')
+                       p = data->target->user->suser;
+
+               sendto_one(data->client, form_str(RPL_WHOISLOGGEDIN),
+                               get_id(&me, data->client),
+                               get_id(data->client, data->client),
+                               data->target->name, p);
+       }
+}
+
+static void
+h_svc_stats(hook_data_int *data)
+{
+       char statchar = (char) data->arg2;
+       dlink_node *ptr;
+
+       if (statchar == 'U' && IsOper(data->client))
+       {
+               DLINK_FOREACH(ptr, service_list.head)
+               {
+                       sendto_one_numeric(data->client, RPL_STATSULINE,
+                                               form_str(RPL_STATSULINE),
+                                               ptr->data, "*", "*", "s");
+               }
+       }
+}
diff --git a/modules/m_set.c b/modules/m_set.c
new file mode 100644 (file)
index 0000000..d045b36
--- /dev/null
@@ -0,0 +1,612 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_set.c: Sets a server parameter.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_set.c 494 2006-01-15 16:08:28Z jilles $
+ */
+
+/* rewritten by jdc */
+
+#include "stdinc.h"
+#include "client.h"
+#include "event.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "commio.h"
+#include "s_serv.h"
+#include "send.h"
+#include "common.h"
+#include "channel.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+
+static int mo_set(struct Client *, struct Client *, int, const char **);
+
+struct Message set_msgtab = {
+       "SET", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_set, 0}}
+};
+
+mapi_clist_av1 set_clist[] = { &set_msgtab, NULL };
+DECLARE_MODULE_AV1(set, NULL, NULL, set_clist, NULL, NULL, "$Revision: 494 $");
+
+/* Structure used for the SET table itself */
+struct SetStruct
+{
+       const char *name;
+       void (*handler) ();
+       int wants_char;         /* 1 if it expects (char *, [int]) */
+       int wants_int;          /* 1 if it expects ([char *], int) */
+
+       /* eg:  0, 1 == only an int arg
+        * eg:  1, 1 == char and int args */
+};
+
+
+static void quote_adminstring(struct Client *, const char *);
+static void quote_autoconn(struct Client *, char *, int);
+static void quote_autoconnall(struct Client *, int);
+static void quote_floodcount(struct Client *, int);
+static void quote_identtimeout(struct Client *, int);
+static void quote_idletime(struct Client *, int);
+static void quote_max(struct Client *, int);
+static void quote_operstring(struct Client *, const char *);
+static void quote_spamnum(struct Client *, int);
+static void quote_spamtime(struct Client *, int);
+static void quote_splitmode(struct Client *, char *);
+static void quote_splitnum(struct Client *, int);
+static void quote_splitusers(struct Client *, int);
+static void list_quote_commands(struct Client *);
+
+
+/* 
+ * If this ever needs to be expanded to more than one arg of each
+ * type, want_char/want_int could be the count of the arguments,
+ * instead of just a boolean flag...
+ *
+ * -davidt
+ */
+
+static struct SetStruct set_cmd_table[] = {
+       /* name               function      string arg  int arg */
+       /* -------------------------------------------------------- */
+       {"ADMINSTRING", quote_adminstring,      1,      0       },
+       {"AUTOCONN",    quote_autoconn,         1,      1       },
+       {"AUTOCONNALL", quote_autoconnall,      0,      1       },
+       {"FLOODCOUNT",  quote_floodcount,       0,      1       },
+       {"IDENTTIMEOUT", quote_identtimeout,    0,      1       },
+       {"IDLETIME",    quote_idletime,         0,      1       },
+       {"MAX",         quote_max,              0,      1       },
+       {"MAXCLIENTS",  quote_max,              0,      1       },
+       {"OPERSTRING",  quote_operstring,       1,      0       },
+       {"SPAMNUM",     quote_spamnum,          0,      1       },
+       {"SPAMTIME",    quote_spamtime,         0,      1       },
+       {"SPLITMODE",   quote_splitmode,        1,      0       },
+       {"SPLITNUM",    quote_splitnum,         0,      1       },
+       {"SPLITUSERS",  quote_splitusers,       0,      1       },
+       /* -------------------------------------------------------- */
+       {(char *) 0, (void (*)()) 0, 0, 0}
+};
+
+
+/*
+ * list_quote_commands() sends the client all the available commands.
+ * Four to a line for now.
+ */
+static void
+list_quote_commands(struct Client *source_p)
+{
+       int i;
+       int j = 0;
+       const char *names[4];
+
+       sendto_one(source_p, ":%s NOTICE %s :Available QUOTE SET commands:",
+                  me.name, source_p->name);
+
+       names[0] = names[1] = names[2] = names[3] = "";
+
+       for (i = 0; set_cmd_table[i].handler; i++)
+       {
+               names[j++] = set_cmd_table[i].name;
+
+               if(j > 3)
+               {
+                       sendto_one(source_p, ":%s NOTICE %s :%s %s %s %s",
+                                  me.name, source_p->name, names[0], names[1], names[2], names[3]);
+                       j = 0;
+                       names[0] = names[1] = names[2] = names[3] = "";
+               }
+
+       }
+       if(j)
+               sendto_one(source_p, ":%s NOTICE %s :%s %s %s %s",
+                          me.name, source_p->name, names[0], names[1], names[2], names[3]);
+}
+
+/* SET AUTOCONN */
+static void
+quote_autoconn(struct Client *source_p, char *arg, int newval)
+{
+       set_server_conf_autoconn(source_p, arg, newval);
+}
+
+/* SET AUTOCONNALL */
+static void
+quote_autoconnall(struct Client *source_p, int newval)
+{
+       if(newval >= 0)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s has changed AUTOCONNALL to %i",
+                                    source_p->name, newval);
+
+               GlobalSetOptions.autoconn = newval;
+       }
+       else
+       {
+               sendto_one(source_p, ":%s NOTICE %s :AUTOCONNALL is currently %i",
+                          me.name, source_p->name, GlobalSetOptions.autoconn);
+       }
+}
+
+
+/* SET FLOODCOUNT */
+static void
+quote_floodcount(struct Client *source_p, int newval)
+{
+       if(newval >= 0)
+       {
+               GlobalSetOptions.floodcount = newval;
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "%s has changed FLOODCOUNT to %i", source_p->name,
+                                    GlobalSetOptions.floodcount);
+       }
+       else
+       {
+               sendto_one(source_p, ":%s NOTICE %s :FLOODCOUNT is currently %i",
+                          me.name, source_p->name, GlobalSetOptions.floodcount);
+       }
+}
+
+/* SET IDENTTIMEOUT */
+static void
+quote_identtimeout(struct Client *source_p, int newval)
+{
+       if(!IsOperAdmin(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS),
+                          me.name, source_p->name, "admin");
+               return;
+       }
+
+       if(newval > 0)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "%s has changed IDENTTIMEOUT to %d",
+                                    get_oper_name(source_p), newval);
+               GlobalSetOptions.ident_timeout = newval;
+       }
+       else
+               sendto_one(source_p, ":%s NOTICE %s :IDENTTIMEOUT is currently %d",
+                          me.name, source_p->name, GlobalSetOptions.ident_timeout);
+}
+
+/* SET IDLETIME */
+static void
+quote_idletime(struct Client *source_p, int newval)
+{
+       if(newval >= 0)
+       {
+               if(newval == 0)
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "%s has disabled idletime checking", source_p->name);
+                       GlobalSetOptions.idletime = 0;
+               }
+               else
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "%s has changed IDLETIME to %i",
+                                            source_p->name, newval);
+                       GlobalSetOptions.idletime = (newval * 60);
+               }
+       }
+       else
+       {
+               sendto_one(source_p, ":%s NOTICE %s :IDLETIME is currently %i",
+                          me.name, source_p->name, GlobalSetOptions.idletime / 60);
+       }
+}
+
+/* SET MAX */
+static void
+quote_max(struct Client *source_p, int newval)
+{
+       if(newval > 0)
+       {
+               if(newval > MASTER_MAX)
+               {
+                       sendto_one(source_p,
+                                  ":%s NOTICE %s :You cannot set MAXCLIENTS to > MASTER_MAX (%d)",
+                                  me.name, source_p->name, MASTER_MAX);
+                       return;
+               }
+
+               if(newval < 32)
+               {
+                       sendto_one(source_p,
+                                  ":%s NOTICE %s :You cannot set MAXCLIENTS to < 32 (%d:%d)",
+                                  me.name, source_p->name, GlobalSetOptions.maxclients,
+                                  highest_fd);
+                       return;
+               }
+
+               GlobalSetOptions.maxclients = newval;
+
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "%s!%s@%s set new MAXCLIENTS to %d (%lu current)",
+                                    source_p->name, source_p->username, source_p->host,
+                                    GlobalSetOptions.maxclients, 
+                                    dlink_list_length(&lclient_list));
+
+               return;
+       }
+       else
+       {
+               sendto_one(source_p, ":%s NOTICE %s :Current Maxclients = %d (%lu)",
+                          me.name, source_p->name, GlobalSetOptions.maxclients,
+                          dlink_list_length(&lclient_list));
+       }
+}
+
+/* SET OPERSTRING */
+static void
+quote_operstring(struct Client *source_p, const char *arg)
+{
+       if(EmptyString(arg))
+       {
+               sendto_one(source_p, ":%s NOTICE %s :OPERSTRING is currently '%s'",
+                          me.name, source_p->name, GlobalSetOptions.operstring);
+       }
+       else
+       {
+               strlcpy(GlobalSetOptions.operstring, arg,
+                       sizeof(GlobalSetOptions.operstring));
+               
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "%s has changed OPERSTRING to '%s'",
+                                    get_oper_name(source_p), arg);
+       }
+}
+
+/* SET ADMINSTRING */
+static void
+quote_adminstring(struct Client *source_p, const char *arg)
+{
+       if(EmptyString(arg))
+       {
+               sendto_one(source_p, ":%s NOTICE %s :ADMINSTRING is currently '%s'",
+                          me.name, source_p->name, GlobalSetOptions.adminstring);
+       }
+       else
+       {
+               strlcpy(GlobalSetOptions.adminstring, arg,
+                       sizeof(GlobalSetOptions.adminstring));
+               
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "%s has changed ADMINSTRING to '%s'",
+                                    get_oper_name(source_p), arg);
+       }
+}
+
+/* SET SPAMNUM */
+static void
+quote_spamnum(struct Client *source_p, int newval)
+{
+       if(newval > 0)
+       {
+               if(newval == 0)
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "%s has disabled ANTI_SPAMBOT", source_p->name);
+                       GlobalSetOptions.spam_num = newval;
+                       return;
+               }
+               if(newval < MIN_SPAM_NUM)
+               {
+                       GlobalSetOptions.spam_num = MIN_SPAM_NUM;
+               }
+               else            /* if (newval < MIN_SPAM_NUM) */
+               {
+                       GlobalSetOptions.spam_num = newval;
+               }
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s has changed SPAMNUM to %i",
+                                    source_p->name, GlobalSetOptions.spam_num);
+       }
+       else
+       {
+               sendto_one(source_p, ":%s NOTICE %s :SPAMNUM is currently %i",
+                          me.name, source_p->name, GlobalSetOptions.spam_num);
+       }
+}
+
+/* SET SPAMTIME */
+static void
+quote_spamtime(struct Client *source_p, int newval)
+{
+       if(newval > 0)
+       {
+               if(newval < MIN_SPAM_TIME)
+               {
+                       GlobalSetOptions.spam_time = MIN_SPAM_TIME;
+               }
+               else            /* if (newval < MIN_SPAM_TIME) */
+               {
+                       GlobalSetOptions.spam_time = newval;
+               }
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s has changed SPAMTIME to %i",
+                                    source_p->name, GlobalSetOptions.spam_time);
+       }
+       else
+       {
+               sendto_one(source_p, ":%s NOTICE %s :SPAMTIME is currently %i",
+                          me.name, source_p->name, GlobalSetOptions.spam_time);
+       }
+}
+
+/* this table is what splitmode may be set to */
+static const char *splitmode_values[] = {
+       "OFF",
+       "ON",
+       "AUTO",
+       NULL
+};
+
+/* this table is what splitmode may be */
+static const char *splitmode_status[] = {
+       "OFF",
+       "AUTO (OFF)",
+       "ON",
+       "AUTO (ON)",
+       NULL
+};
+
+/* SET SPLITMODE */
+static void
+quote_splitmode(struct Client *source_p, char *charval)
+{
+       if(charval)
+       {
+               int newval;
+
+               for (newval = 0; splitmode_values[newval]; newval++)
+               {
+                       if(!irccmp(splitmode_values[newval], charval))
+                               break;
+               }
+
+               /* OFF */
+               if(newval == 0)
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "%s is disabling splitmode", get_oper_name(source_p));
+
+                       splitmode = 0;
+                       splitchecking = 0;
+
+                       eventDelete(check_splitmode, NULL);
+               }
+               /* ON */
+               else if(newval == 1)
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "%s is enabling and activating splitmode",
+                                            get_oper_name(source_p));
+
+                       splitmode = 1;
+                       splitchecking = 0;
+
+                       /* we might be deactivating an automatic splitmode, so pull the event */
+                       eventDelete(check_splitmode, NULL);
+               }
+               /* AUTO */
+               else if(newval == 2)
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "%s is enabling automatic splitmode",
+                                            get_oper_name(source_p));
+
+                       splitchecking = 1;
+                       check_splitmode(NULL);
+               }
+       }
+       else
+               /* if we add splitchecking to splitmode*2 we get a unique table to 
+                * pull values back out of, splitmode can be four states - but you can
+                * only set to three, which means we cant use the same table --fl_
+                */
+               sendto_one(source_p, ":%s NOTICE %s :SPLITMODE is currently %s",
+                          me.name, source_p->name,
+                          splitmode_status[(splitchecking + (splitmode * 2))]);
+}
+
+/* SET SPLITNUM */
+static void
+quote_splitnum(struct Client *source_p, int newval)
+{
+       if(newval >= 0)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "%s has changed SPLITNUM to %i", source_p->name, newval);
+               split_servers = newval;
+
+               if(splitchecking)
+                       check_splitmode(NULL);
+       }
+       else
+               sendto_one(source_p, ":%s NOTICE %s :SPLITNUM is currently %i",
+                          me.name, source_p->name, split_servers);
+}
+
+/* SET SPLITUSERS */
+static void
+quote_splitusers(struct Client *source_p, int newval)
+{
+       if(newval >= 0)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "%s has changed SPLITUSERS to %i", source_p->name, newval);
+               split_users = newval;
+
+               if(splitchecking)
+                       check_splitmode(NULL);
+       }
+       else
+               sendto_one(source_p, ":%s NOTICE %s :SPLITUSERS is currently %i",
+                          me.name, source_p->name, split_users);
+}
+
+/*
+ * mo_set - SET command handler
+ * set options while running
+ */
+static int
+mo_set(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       int newval;
+       int i, n;
+       const char *arg = NULL;
+       const char *intarg = NULL;
+
+       if(parc > 1)
+       {
+               /*
+                * Go through all the commands in set_cmd_table, until one is
+                * matched.  I realize strcmp() is more intensive than a numeric
+                * lookup, but at least it's better than a big-ass switch/case
+                * statement.
+                */
+               for (i = 0; set_cmd_table[i].handler; i++)
+               {
+                       if(!irccmp(set_cmd_table[i].name, parv[1]))
+                       {
+                               /*
+                                * Command found; now execute the code
+                                */
+                               n = 2;
+
+                               if(set_cmd_table[i].wants_char)
+                               {
+                                       arg = parv[n++];
+                               }
+
+                               if(set_cmd_table[i].wants_int)
+                               {
+                                       intarg = parv[n++];
+                               }
+
+                               if((n - 1) > parc)
+                               {
+                                       sendto_one(source_p,
+                                                  ":%s NOTICE %s :SET %s expects (\"%s%s\") args",
+                                                  me.name, source_p->name,
+                                                  set_cmd_table[i].name,
+                                                  (set_cmd_table[i].
+                                                   wants_char ? "string, " : ""),
+                                                  (set_cmd_table[i].
+                                                   wants_char ? "int" : ""));
+                                       return 0;
+                               }
+
+                               if(parc <= 2)
+                               {
+                                       arg = NULL;
+                                       intarg = NULL;
+                               }
+
+                               if(set_cmd_table[i].wants_int && (parc > 2))
+                               {
+                                       if(intarg)
+                                       {
+                                               if(!irccmp(intarg, "yes") || !irccmp(intarg, "on"))
+                                                       newval = 1;
+                                               else if(!irccmp(intarg, "no")
+                                                       || !irccmp(intarg, "off"))
+                                                       newval = 0;
+                                               else
+                                                       newval = atoi(intarg);
+                                       }
+                                       else
+                                       {
+                                               newval = -1;
+                                       }
+
+                                       if(newval < 0)
+                                       {
+                                               sendto_one(source_p,
+                                                          ":%s NOTICE %s :Value less than 0 illegal for %s",
+                                                          me.name, source_p->name,
+                                                          set_cmd_table[i].name);
+
+                                               return 0;
+                                       }
+                               }
+                               else
+                                       newval = -1;
+
+                               if(set_cmd_table[i].wants_char)
+                               {
+                                       if(set_cmd_table[i].wants_int)
+                                               set_cmd_table[i].handler(source_p, arg, newval);
+                                       else
+                                               set_cmd_table[i].handler(source_p, arg);
+                                       return 0;
+                               }
+                               else
+                               {
+                                       if(set_cmd_table[i].wants_int)
+                                               set_cmd_table[i].handler(source_p, newval);
+                                       else
+                                               /* Just in case someone actually wants a
+                                                * set function that takes no args.. *shrug* */
+                                               set_cmd_table[i].handler(source_p);
+                                       return 0;
+                               }
+                       }
+               }
+
+               /*
+                * Code here will be executed when a /QUOTE SET command is not
+                * found within set_cmd_table.
+                */
+               sendto_one(source_p, ":%s NOTICE %s :Variable not found.", me.name, parv[0]);
+               return 0;
+       }
+
+       list_quote_commands(source_p);
+
+       return 0;
+}
diff --git a/modules/m_signon.c b/modules/m_signon.c
new file mode 100644 (file)
index 0000000..a4340be
--- /dev/null
@@ -0,0 +1,441 @@
+/* modules/m_signon.c
+ *   Copyright (C) 2006 Michael Tharp <gxti@partiallystapled.com>
+ *   Copyright (C) 2006 charybdis development team
+ *
+ * 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.The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: m_signon.c 1192 2006-04-21 16:21:02Z jilles $
+ */
+
+#include "stdinc.h"
+
+#include "tools.h"
+#include "send.h"
+#include "channel.h"
+#include "client.h"
+#include "common.h"
+#include "config.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "memory.h"
+#include "s_conf.h"
+#include "s_serv.h"
+#include "hash.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "sprintf_irc.h"
+#include "whowas.h"
+#include "monitor.h"
+#include "s_stats.h"
+#include "snomask.h"
+#include "irc_string.h"
+#include "s_user.h"
+
+static int me_svslogin(struct Client *, struct Client *, int, const char **);
+static int ms_signon(struct Client *, struct Client *, int, const char **);
+
+static void send_signon(struct Client *, struct Client *, const char *, const char *, const char *, unsigned int, const char *);
+
+struct Message svslogin_msgtab = {
+       "SVSLOGIN", 0, 0, 0, MFLG_SLOW,
+       {mg_ignore, mg_ignore, mg_ignore, mg_ignore, {me_svslogin, 6}, mg_ignore}
+};
+struct Message signon_msgtab = {
+       "SIGNON", 0, 0, 0, MFLG_SLOW,
+       {mg_ignore, mg_ignore, {ms_signon, 6}, mg_ignore, mg_ignore, mg_ignore}
+};
+
+mapi_clist_av1 signon_clist[] = { 
+       &svslogin_msgtab, &signon_msgtab, NULL
+};
+
+DECLARE_MODULE_AV1(signon, NULL, NULL, signon_clist, NULL, NULL, "$Revision: 1192 $");
+
+#define NICK_VALID     1
+#define USER_VALID     2
+#define HOST_VALID     4
+
+static int
+clean_nick(const char *nick)
+{
+       int len = 0;
+
+       if(*nick == '-')
+               return 0;
+
+       /* This is used to check logins, which are often
+        * numeric. Don't check for leading digits, if
+        * services wants to set someone's nick to something
+        * starting with a number, let it try.
+        * --gxti
+        */
+
+       for (; *nick; nick++)
+       {
+               len++;
+               if(!IsNickChar(*nick))
+                       return 0;
+       }
+
+       /* nicklen is +1 */
+       if(len >= NICKLEN)
+               return 0;
+
+       return 1;
+}
+
+static int
+clean_username(const char *username)
+{
+       int len = 0;
+
+       for (; *username; username++)
+       {
+               len++;
+
+               if(!IsUserChar(*username))
+                       return 0;
+       }
+
+       if(len > USERLEN)
+               return 0;
+
+       return 1;
+}
+
+static int
+clean_host(const char *host)
+{
+       int len = 0;
+
+       for (; *host; host++)
+       {
+               len++;
+
+               if(!IsHostChar(*host))
+                       return 0;
+       }
+
+       if(len > HOSTLEN)
+               return 0;
+
+       return 1;
+}
+
+static int
+me_svslogin(struct Client *client_p, struct Client *source_p,
+       int parc, const char *parv[])
+{
+       struct Client *target_p, *exist_p;
+       char nick[NICKLEN+1], login[NICKLEN+1];
+       char user[USERLEN+1], host[HOSTLEN+1];
+       int valid = 0;
+
+       if(!(source_p->flags & FLAGS_SERVICE))
+               return 0;
+
+       if((target_p = find_client(parv[1])) == NULL)
+               return 0;
+
+       if(!MyClient(target_p) && !IsUnknown(target_p))
+               return 0;
+
+       if(clean_nick(parv[2]))
+       {
+               strlcpy(nick, parv[2], NICKLEN + 1);
+               valid |= NICK_VALID;
+       }
+       else if(*target_p->name)
+               strlcpy(nick, target_p->name, NICKLEN + 1);
+       else
+               strcpy(nick, "*");
+
+       if(clean_username(parv[3]))
+       {
+               strlcpy(user, parv[3], USERLEN + 1);
+               valid |= USER_VALID;
+       }
+       else
+               strlcpy(user, target_p->username, USERLEN + 1);
+
+       if(clean_host(parv[4]))
+       {
+               strlcpy(host, parv[4], HOSTLEN + 1);
+               valid |= HOST_VALID;
+       }
+       else
+               strlcpy(host, target_p->host, HOSTLEN + 1);
+
+       if(*parv[5] == '*')
+       {
+               if(target_p->user)
+                       strlcpy(login, target_p->user->suser, NICKLEN + 1);
+               else
+                       login[0] = '\0';
+       }
+       else if(!strcmp(parv[5], "0"))
+               login[0] = '\0';
+       else
+               strlcpy(login, parv[5], NICKLEN + 1);
+
+       /* Login (mostly) follows nick rules. */
+       if(*login && !clean_nick(login))
+               return 0;
+
+       if((exist_p = find_person(nick)) && target_p != exist_p)
+       {
+               char buf[BUFSIZE];
+
+               if(MyClient(exist_p))
+                       sendto_one(exist_p, ":%s KILL %s :(Nickname regained by services)",
+                               me.name, exist_p->name);
+
+               exist_p->flags |= FLAGS_KILLED;
+               kill_client_serv_butone(NULL, exist_p, "%s (Nickname regained by services)",
+                                       me.name);
+
+               snprintf(buf, sizeof(buf), "Killed (%s (Nickname regained by services))",
+                       me.name);
+               exit_client(NULL, exist_p, &me, buf);
+       }else if((exist_p = find_client(nick)) && IsUnknown(exist_p) && exist_p != target_p) {
+               exit_client(NULL, exist_p, &me, "Overridden");
+       }
+
+       if(*login)
+       {
+               /* Strip leading digits, unless it's purely numeric. */
+               const char *p = login;
+               while(IsDigit(*p))
+                       p++;
+               if(!*p)
+                       p = login;
+
+               sendto_one(target_p, form_str(RPL_LOGGEDIN), me.name, EmptyString(target_p->name) ? "*" : target_p->name,
+                               nick, user, host, p, p);
+       }
+       else
+               sendto_one(target_p, form_str(RPL_LOGGEDOUT), me.name, EmptyString(target_p->name) ? "*" : target_p->name,
+                               nick, user, host);
+
+       if(IsUnknown(target_p))
+       {
+               struct User *user_p = make_user(target_p);
+
+               if(valid & NICK_VALID)
+                       strcpy(target_p->preClient->spoofnick, nick);
+
+               if(valid & USER_VALID)
+                       strcpy(target_p->preClient->spoofuser, user);
+
+               if(valid & HOST_VALID)
+                       strcpy(target_p->preClient->spoofhost, host);
+
+               strlcpy(user_p->suser, login, NICKLEN + 1);
+       }
+       else
+       {
+               send_signon(NULL, target_p, nick, user, host, CurrentTime, login);
+               comm_note(target_p->localClient->fd, "Nick: %s", target_p->name);
+       }
+
+       return 0;
+}
+
+static int
+ms_signon(struct Client *client_p, struct Client *source_p,
+       int parc, const char *parv[])
+{
+       struct Client *target_p;
+       int newts, sameuser;
+       char login[NICKLEN+1];
+
+       if(!clean_nick(parv[1]))
+       {
+               ServerStats->is_kill++;
+               sendto_realops_snomask(SNO_DEBUG, L_ALL,
+                               "Bad Nick from SIGNON: %s From: %s(via %s)",
+                               parv[1], source_p->servptr->name, client_p->name);
+               /* if source_p has an id, kill_client_serv_butone() will
+                * send a kill to client_p, otherwise do it here */
+               if (!has_id(source_p))
+                       sendto_one(client_p, ":%s KILL %s :%s (Bad nickname from SIGNON)",
+                               get_id(&me, client_p), parv[1], me.name);
+               kill_client_serv_butone(client_p, source_p, "%s (Bad nickname from SIGNON)",
+                               me.name);
+               source_p->flags |= FLAGS_KILLED;
+               exit_client(NULL, source_p, &me, "Bad nickname from SIGNON");
+               return 0;
+       }
+
+       if(!clean_username(parv[2]) || !clean_host(parv[3]))
+       {
+               ServerStats->is_kill++;
+               sendto_realops_snomask(SNO_DEBUG, L_ALL,
+                               "Bad user@host from SIGNON: %s@%s From: %s(via %s)",
+                               parv[2], parv[3], source_p->servptr->name, client_p->name);
+               /* if source_p has an id, kill_client_serv_butone() will
+                * send a kill to client_p, otherwise do it here */
+               if (!has_id(source_p))
+                       sendto_one(client_p, ":%s KILL %s :%s (Bad user@host from SIGNON)",
+                               get_id(&me, client_p), parv[1], me.name);
+               kill_client_serv_butone(client_p, source_p, "%s (Bad user@host from SIGNON)",
+                               me.name);
+               source_p->flags |= FLAGS_KILLED;
+               exit_client(NULL, source_p, &me, "Bad user@host from SIGNON");
+               return 0;
+       }
+
+       newts = atol(parv[4]);
+
+       if(!strcmp(parv[5], "0"))
+               login[0] = '\0';
+       else if(*parv[5] != '*')
+       {
+               if (clean_nick(parv[5]))
+                       strlcpy(login, parv[5], NICKLEN + 1);
+               else
+                       return 0;
+       }
+
+       target_p = find_named_client(parv[1]);
+       if(target_p != NULL && target_p != source_p)
+       {
+               /* In case of collision, follow NICK rules. */
+               /* XXX this is duplicated code and does not do SAVE */
+               if(IsUnknown(target_p))
+                       exit_client(NULL, target_p, &me, "Overridden");
+               else
+               {
+                       if(!newts || !target_p->tsinfo || (newts == target_p->tsinfo) || !source_p->user)
+                       {
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                                    "Nick change collision from SIGNON from %s to %s(%s <- %s)(both killed)",
+                                                    source_p->name, target_p->name, target_p->from->name,
+                                                    client_p->name);
+               
+                               ServerStats->is_kill++;
+                               sendto_one_numeric(target_p, ERR_NICKCOLLISION,
+                                                  form_str(ERR_NICKCOLLISION), target_p->name);
+               
+                               kill_client_serv_butone(NULL, source_p, "%s (Nick change collision)", me.name);
+               
+                               ServerStats->is_kill++;
+               
+                               kill_client_serv_butone(NULL, target_p, "%s (Nick change collision)", me.name);
+               
+                               target_p->flags |= FLAGS_KILLED;
+                               exit_client(NULL, target_p, &me, "Nick collision(new)");
+                               source_p->flags |= FLAGS_KILLED;
+                               exit_client(client_p, source_p, &me, "Nick collision(old)");
+                               return 0;
+                       }
+                       else
+                       {
+                               sameuser = !irccmp(target_p->username, source_p->username) &&
+                                       !irccmp(target_p->host, source_p->host);
+               
+                               if((sameuser && newts < target_p->tsinfo) ||
+                                  (!sameuser && newts > target_p->tsinfo))
+                               {
+                                       if(sameuser)
+                                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                                                    "Nick change collision from SIGNON from %s to %s(%s <- %s)(older killed)",
+                                                                    source_p->name, target_p->name,
+                                                                    target_p->from->name, client_p->name);
+                                       else
+                                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                                                    "Nick change collision from SIGNON from %s to %s(%s <- %s)(newer killed)",
+                                                                    source_p->name, target_p->name,
+                                                                    target_p->from->name, client_p->name);
+               
+                                       ServerStats->is_kill++;
+               
+                                       sendto_one_numeric(target_p, ERR_NICKCOLLISION,
+                                                          form_str(ERR_NICKCOLLISION), target_p->name);
+               
+                                       /* kill the client issuing the nickchange */
+                                       kill_client_serv_butone(client_p, source_p,
+                                                               "%s (Nick change collision)", me.name);
+               
+                                       source_p->flags |= FLAGS_KILLED;
+               
+                                       if(sameuser)
+                                               exit_client(client_p, source_p, &me, "Nick collision(old)");
+                                       else
+                                               exit_client(client_p, source_p, &me, "Nick collision(new)");
+                                       return 0;
+                               }
+                               else
+                               {
+                                       if(sameuser)
+                                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                                                    "Nick collision from SIGNON on %s(%s <- %s)(older killed)",
+                                                                    target_p->name, target_p->from->name,
+                                                                    client_p->name);
+                                       else
+                                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                                                    "Nick collision from SIGNON on %s(%s <- %s)(newer killed)",
+                                                                    target_p->name, target_p->from->name,
+                                                                    client_p->name);
+               
+                                       sendto_one_numeric(target_p, ERR_NICKCOLLISION,
+                                                          form_str(ERR_NICKCOLLISION), target_p->name);
+               
+                                       /* kill the client who existed before hand */
+                                       kill_client_serv_butone(client_p, target_p, 
+                                                       "%s (Nick collision)", me.name);
+               
+                                       ServerStats->is_kill++;
+               
+                                       target_p->flags |= FLAGS_KILLED;
+                                       (void) exit_client(client_p, target_p, &me, "Nick collision");
+                               }
+                       }
+               
+               }
+       }
+
+       send_signon(client_p, source_p, parv[1], parv[2], parv[3], newts, login);
+       return 0;
+}
+
+static void
+send_signon(struct Client *client_p, struct Client *target_p,
+               const char *nick, const char *user, const char *host,
+               unsigned int newts, const char *login)
+{
+       sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s SIGNON %s %s %s %ld %s",
+                       use_id(target_p), nick, user, host,
+                       (long) target_p->tsinfo, *login ? login : "0");
+       sendto_server(client_p, NULL, NOCAPS, CAP_TS6, ":%s SIGNON %s %s %s %ld %s",
+                       target_p->name, nick, user, host,
+                       (long) target_p->tsinfo, *login ? login : "0");
+
+       strcpy(target_p->user->suser, login);
+
+       change_nick_user_host(target_p, nick, user, host, newts, "Signing %s (%s)", *login ?  "in" : "out", nick);
+}
+
diff --git a/modules/m_snote.c b/modules/m_snote.c
new file mode 100644 (file)
index 0000000..881d260
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ *  charybdis: an advanced Internet Relay Chat Daemon(ircd).
+ *  m_snote.c: Server notice listener
+ *
+ *  Copyright (c) 2006 William Pitcock <nenolod -at- nenolod.net>
+ *
+ *  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.The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ *  $Id: m_snote.c 623 2006-01-29 13:47:35Z jilles $
+ */
+
+#include "stdinc.h"
+#include "class.h"
+#include "hook.h"
+#include "client.h"
+#include "hash.h"
+#include "common.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "commio.h"
+#include "s_serv.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "s_user.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+
+static int me_snote(struct Client *, struct Client *, int, const char **);
+
+struct Message snote_msgtab = {
+       "SNOTE", 0, 0, 0, MFLG_SLOW,
+       {mg_ignore, mg_not_oper, mg_ignore, mg_ignore, {me_snote, 3}, mg_ignore}
+};
+
+mapi_clist_av1 snote_clist[] = { &snote_msgtab, NULL };
+DECLARE_MODULE_AV1(snote, NULL, NULL, snote_clist, NULL, NULL, "$Revision: 623 $");
+
+/*
+ * me_snote
+ *      parv[0] = sender prefix
+ *      parv[1] = snomask letter
+ *     parv[2] = message
+ */
+static int
+me_snote(struct Client *client_p, struct Client *source_p, int parc, 
+       const char *parv[])
+{
+       /* if there's more than just two params, this is a protocol
+        * violation, but it seems stupid to drop servers over it,
+        * shit happens afterall -nenolod
+        */
+       if (parc > 3)
+               return 0;
+       if (!IsServer(source_p))
+               return 0;
+
+       sendto_realops_snomask_from(snomask_modes[(unsigned char) *parv[1]],
+               L_ALL, source_p, "%s", parv[2]);
+
+       return 0;
+}
diff --git a/modules/m_stats.c b/modules/m_stats.c
new file mode 100644 (file)
index 0000000..14c3bf7
--- /dev/null
@@ -0,0 +1,1415 @@
+/*
+ *  ircd-ratbox: an advanced Internet Relay Chat Daemon(ircd).
+ *  m_stats.c: Sends the user statistics or config information.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_stats.c 1608 2006-06-04 02:11:40Z jilles $
+ */
+
+#include "stdinc.h"
+#include "tools.h"             /* dlink_node/dlink_list */
+#include "class.h"             /* report_classes */
+#include "client.h"            /* Client */
+#include "common.h"            /* TRUE/FALSE */
+#include "irc_string.h"
+#include "ircd.h"              /* me */
+#include "listener.h"          /* show_ports */
+#include "s_gline.h"
+#include "msg.h"               /* Message */
+#include "hostmask.h"          /* report_mtrie_conf_links */
+#include "numeric.h"           /* ERR_xxx */
+#include "scache.h"            /* list_scache */
+#include "send.h"              /* sendto_one */
+#include "commio.h"            /* highest_fd */
+#include "s_conf.h"            /* ConfItem */
+#include "s_serv.h"            /* hunt_server */
+#include "s_stats.h"           /* tstats */
+#include "s_user.h"            /* show_opers */
+#include "event.h"             /* events */
+#include "blacklist.h"         /* dnsbl stuff */
+#include "linebuf.h"
+#include "parse.h"
+#include "modules.h"
+#include "hook.h"
+#include "s_newconf.h"
+#include "hash.h"
+
+static int m_stats (struct Client *, struct Client *, int, const char **);
+
+struct Message stats_msgtab = {
+       "STATS", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_stats, 2}, {m_stats, 3}, mg_ignore, mg_ignore, {m_stats, 2}}
+};
+
+int doing_stats_hook;
+int doing_stats_p_hook;
+
+mapi_clist_av1 stats_clist[] = { &stats_msgtab, NULL };
+mapi_hlist_av1 stats_hlist[] = {
+       { "doing_stats",        &doing_stats_hook },
+       { "doing_stats_p",      &doing_stats_p_hook },
+       { NULL, NULL }
+};
+
+DECLARE_MODULE_AV1(stats, NULL, NULL, stats_clist, stats_hlist, NULL, "$Revision: 1608 $");
+
+const char *Lformat = "%s %u %u %u %u %u :%u %u %s";
+
+static void stats_l_list(struct Client *s, const char *, int, int, dlink_list *, char);
+static void stats_l_client(struct Client *source_p, struct Client *target_p,
+                               char statchar);
+
+static void stats_spy(struct Client *, char, const char *);
+static void stats_p_spy(struct Client *);
+
+/* Heres our struct for the stats table */
+struct StatsStruct
+{
+       char letter;
+       void (*handler) ();
+       int need_oper;
+       int need_admin;
+};
+
+static void stats_dns_servers (struct Client *);
+static void stats_delay(struct Client *);
+static void stats_hash(struct Client *);
+static void stats_connect(struct Client *);
+static void stats_tdeny(struct Client *);
+static void stats_deny(struct Client *);
+static void stats_exempt(struct Client *);
+static void stats_events(struct Client *);
+static void stats_glines(struct Client *);
+static void stats_pending_glines(struct Client *);
+static void stats_hubleaf(struct Client *);
+static void stats_auth(struct Client *);
+static void stats_tklines(struct Client *);
+static void stats_klines(struct Client *);
+static void stats_messages(struct Client *);
+static void stats_dnsbl(struct Client *);
+static void stats_oper(struct Client *);
+static void stats_operedup(struct Client *);
+static void stats_ports(struct Client *);
+static void stats_tresv(struct Client *);
+static void stats_resv(struct Client *);
+static void stats_usage(struct Client *);
+static void stats_tstats(struct Client *);
+static void stats_uptime(struct Client *);
+static void stats_shared(struct Client *);
+static void stats_servers(struct Client *);
+static void stats_tgecos(struct Client *);
+static void stats_gecos(struct Client *);
+static void stats_class(struct Client *);
+static void stats_memory(struct Client *);
+static void stats_servlinks(struct Client *);
+static void stats_ltrace(struct Client *, int, const char **);
+static void stats_ziplinks(struct Client *);
+
+/* This table contains the possible stats items, in order:
+ * stats letter,  function to call, operonly? adminonly?
+ * case only matters in the stats letter column.. -- fl_
+ */
+static struct StatsStruct stats_cmd_table[] = {
+    /* letter     function        need_oper need_admin */
+       {'a', stats_dns_servers,        1, 1, },
+       {'A', stats_dns_servers,        1, 1, },
+       {'b', stats_delay,              1, 1, },
+       {'B', stats_hash,               1, 1, },
+       {'c', stats_connect,            0, 0, },
+       {'C', stats_connect,            0, 0, },
+       {'d', stats_tdeny,              1, 0, },
+       {'D', stats_deny,               1, 0, },
+       {'e', stats_exempt,             1, 0, },
+       {'E', stats_events,             1, 1, },
+       {'f', comm_dump,                1, 1, },
+       {'F', comm_dump,                1, 1, },
+       {'g', stats_pending_glines,     1, 0, },
+       {'G', stats_glines,             1, 0, },
+       {'h', stats_hubleaf,            0, 0, },
+       {'H', stats_hubleaf,            0, 0, },
+       {'i', stats_auth,               0, 0, },
+       {'I', stats_auth,               0, 0, },
+       {'k', stats_tklines,            0, 0, },
+       {'K', stats_klines,             0, 0, },
+       {'l', stats_ltrace,             0, 0, },
+       {'L', stats_ltrace,             0, 0, },
+       {'m', stats_messages,           0, 0, },
+       {'M', stats_messages,           0, 0, },
+       {'n', stats_dnsbl,              0, 0, },
+       {'o', stats_oper,               0, 0, },
+       {'O', stats_oper,               0, 0, },
+       {'p', stats_operedup,           0, 0, },
+       {'P', stats_ports,              0, 0, },
+       {'q', stats_tresv,              1, 0, },
+       {'Q', stats_resv,               1, 0, },
+       {'r', stats_usage,              1, 0, },
+       {'R', stats_usage,              1, 0, },
+       {'t', stats_tstats,             1, 0, },
+       {'T', stats_tstats,             1, 0, },
+       {'u', stats_uptime,             0, 0, },
+       {'U', stats_shared,             1, 0, },
+       {'v', stats_servers,            0, 0, },
+       {'V', stats_servers,            0, 0, },
+       {'x', stats_tgecos,             1, 0, },
+       {'X', stats_gecos,              1, 0, },
+       {'y', stats_class,              0, 0, },
+       {'Y', stats_class,              0, 0, },
+       {'z', stats_memory,             1, 0, },
+       {'Z', stats_ziplinks,           1, 0, },
+       {'?', stats_servlinks,          0, 0, },
+       {(char) 0, (void (*)()) 0,      0, 0, }
+};
+
+/*
+ * m_stats by fl_
+ *      parv[0] = sender prefix
+ *      parv[1] = stat letter/command
+ *      parv[2] = (if present) server/mask in stats L, or target
+ *
+ * This will search the tables for the appropriate stats letter,
+ * if found execute it.  
+ */
+static int
+m_stats(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       static time_t last_used = 0;
+       int i;
+       char statchar;
+
+       statchar = parv[1][0];
+
+       if(MyClient(source_p) && !IsOper(source_p))
+       {
+               /* Check the user is actually allowed to do /stats, and isnt flooding */
+               if((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
+               {
+                       /* safe enough to give this on a local connect only */
+                       sendto_one(source_p, form_str(RPL_LOAD2HI),
+                                  me.name, source_p->name, "STATS");
+                       sendto_one_numeric(source_p, RPL_ENDOFSTATS, 
+                                          form_str(RPL_ENDOFSTATS), statchar);
+                       return 0;
+               }
+               else
+                       last_used = CurrentTime;
+       }
+
+       if(hunt_server (client_p, source_p, ":%s STATS %s :%s", 2, parc, parv) != HUNTED_ISME)
+               return 0;
+
+       if((statchar != 'L') && (statchar != 'l'))
+               stats_spy(source_p, statchar, NULL);
+
+       for (i = 0; stats_cmd_table[i].handler; i++)
+       {
+               if(stats_cmd_table[i].letter == statchar)
+               {
+                       /* The stats table says what privs are needed, so check --fl_ */
+                       /* Called for remote clients and for local opers, so check need_admin
+                        * and need_oper
+                        */
+                       if((stats_cmd_table[i].need_admin && !IsOperAdmin (source_p)) ||
+                          (stats_cmd_table[i].need_oper && !IsOper (source_p)))
+                       {
+                               sendto_one_numeric(source_p, ERR_NOPRIVILEGES,
+                                                  form_str (ERR_NOPRIVILEGES));
+                               break;
+                       }
+
+                       /* Blah, stats L needs the parameters, none of the others do.. */
+                       if(statchar == 'L' || statchar == 'l')
+                               stats_cmd_table[i].handler (source_p, parc, parv);
+                       else
+                               stats_cmd_table[i].handler (source_p);
+               }
+       }
+
+       /* Send the end of stats notice, and the stats_spy */
+       sendto_one_numeric(source_p, RPL_ENDOFSTATS, 
+                          form_str(RPL_ENDOFSTATS), statchar);
+
+       return 0;
+}
+
+static void
+stats_dns_servers (struct Client *source_p)
+{
+       report_dns_servers (source_p);
+}
+
+static void
+stats_delay(struct Client *source_p)
+{
+       struct nd_entry *nd;
+       dlink_node *ptr;
+       int i;
+
+       HASH_WALK(i, U_MAX, ptr, ndTable)
+       {
+               nd = ptr->data;
+               sendto_one_notice(source_p, "Delaying: %s for %ld",
+                               nd->name, (long) nd->expire);
+       }
+       HASH_WALK_END
+}
+
+static void
+stats_hash(struct Client *source_p)
+{
+       hash_stats(source_p);
+}
+
+static void
+stats_connect(struct Client *source_p)
+{
+       static char buf[5];
+       struct server_conf *server_p;
+       char *s;
+       dlink_node *ptr;
+
+       if((ConfigFileEntry.stats_c_oper_only || 
+           (ConfigServerHide.flatten_links && !IsExemptShide(source_p))) &&
+           !IsOper(source_p))
+       {
+               sendto_one_numeric(source_p, ERR_NOPRIVILEGES,
+                                  form_str(ERR_NOPRIVILEGES));
+               return;
+       }
+
+       DLINK_FOREACH(ptr, server_conf_list.head)
+       {
+               server_p = ptr->data;
+
+               if(ServerConfIllegal(server_p))
+                       continue;
+
+               buf[0] = '\0';
+               s = buf;
+
+               if(IsOper(source_p))
+               {
+                       if(ServerConfAutoconn(server_p))
+                               *s++ = 'A';
+                       if(ServerConfTb(server_p))
+                               *s++ = 'T';
+                       if(ServerConfCompressed(server_p))
+                               *s++ = 'Z';
+               }
+
+               if(!buf[0])
+                       *s++ = '*';
+
+               *s = '\0';
+
+               sendto_one_numeric(source_p, RPL_STATSCLINE, 
+                               form_str(RPL_STATSCLINE),
+#ifndef HIDE_SERVERS_IPS
+                               server_p->host,
+#else
+                               "*@127.0.0.1", 
+#endif
+                               buf, server_p->name,
+                               server_p->port, server_p->class_name);
+       }
+}
+
+/* stats_tdeny()
+ *
+ * input       - client to report to
+ * output      - none
+ * side effects - client is given temp dline list.
+ */
+static void
+stats_tdeny (struct Client *source_p)
+{
+       char *host, *pass, *user, *oper_reason;
+       struct AddressRec *arec;
+       struct ConfItem *aconf;
+       int i;
+
+       for (i = 0; i < ATABLE_SIZE; i++)
+       {
+               for (arec = atable[i]; arec; arec = arec->next)
+               {
+                       if(arec->type == CONF_DLINE)
+                       {
+                               aconf = arec->aconf;
+
+                               if(!(aconf->flags & CONF_FLAGS_TEMPORARY))
+                                       continue;
+
+                               get_printable_kline(source_p, aconf, &host, &pass, &user, &oper_reason);
+
+                               sendto_one_numeric(source_p, RPL_STATSDLINE, 
+                                                  form_str (RPL_STATSDLINE),
+                                                  'd', host, pass,
+                                                  oper_reason ? "|" : "",
+                                                  oper_reason ? oper_reason : "");
+                       }
+               }
+       }
+}
+
+/* stats_deny()
+ *
+ * input       - client to report to
+ * output      - none
+ * side effects - client is given dline list.
+ */
+static void
+stats_deny (struct Client *source_p)
+{
+       char *host, *pass, *user, *oper_reason;
+       struct AddressRec *arec;
+       struct ConfItem *aconf;
+       int i;
+
+       for (i = 0; i < ATABLE_SIZE; i++)
+       {
+               for (arec = atable[i]; arec; arec = arec->next)
+               {
+                       if(arec->type == CONF_DLINE)
+                       {
+                               aconf = arec->aconf;
+
+                               if(aconf->flags & CONF_FLAGS_TEMPORARY)
+                                       continue;
+
+                               get_printable_kline(source_p, aconf, &host, &pass, &user, &oper_reason);
+
+                               sendto_one_numeric(source_p, RPL_STATSDLINE, 
+                                                  form_str (RPL_STATSDLINE),
+                                                  'D', host, pass,
+                                                  oper_reason ? "|" : "",
+                                                  oper_reason ? oper_reason : "");
+                       }
+               }
+       }
+}
+
+
+/* stats_exempt()
+ *
+ * input       - client to report to
+ * output      - none
+ * side effects - client is given list of exempt blocks
+ */
+static void
+stats_exempt(struct Client *source_p)
+{
+       char *name, *host, *pass, *user, *classname;
+       struct AddressRec *arec;
+       struct ConfItem *aconf;
+       int i, port;
+
+       if(ConfigFileEntry.stats_e_disabled)
+       {
+               sendto_one_numeric(source_p, ERR_NOPRIVILEGES,
+                                  form_str (ERR_NOPRIVILEGES));
+               return;
+       }
+
+       for (i = 0; i < ATABLE_SIZE; i++)
+       {
+               for (arec = atable[i]; arec; arec = arec->next)
+               {
+                       if(arec->type == CONF_EXEMPTDLINE)
+                       {
+                               aconf = arec->aconf;
+                               get_printable_conf (aconf, &name, &host, &pass,
+                                                   &user, &port, &classname);
+
+                               sendto_one_numeric(source_p, RPL_STATSDLINE, 
+                                                  form_str(RPL_STATSDLINE),
+                                                  'e', host, pass, "", "");
+                       }
+               }
+       }}
+
+
+static void
+stats_events (struct Client *source_p)
+{
+       show_events (source_p);
+}
+
+/* stats_pending_glines()
+ *
+ * input       - client pointer
+ * output      - none
+ * side effects - client is shown list of pending glines
+ */
+static void
+stats_pending_glines (struct Client *source_p)
+{
+       if(ConfigFileEntry.glines)
+       {
+               dlink_node *pending_node;
+               struct gline_pending *glp_ptr;
+               char timebuffer[MAX_DATE_STRING];
+               struct tm *tmptr;
+
+               DLINK_FOREACH (pending_node, pending_glines.head)
+               {
+                       glp_ptr = pending_node->data;
+
+                       tmptr = localtime (&glp_ptr->time_request1);
+                       strftime (timebuffer, MAX_DATE_STRING, "%Y/%m/%d %H:%M:%S", tmptr);
+
+                       sendto_one_notice(source_p,
+                                   ":1) %s!%s@%s on %s requested gline at %s for %s@%s [%s]",
+                                   glp_ptr->oper_nick1,
+                                   glp_ptr->oper_user1, glp_ptr->oper_host1,
+                                   glp_ptr->oper_server1, timebuffer,
+                                   glp_ptr->user, glp_ptr->host, glp_ptr->reason1);
+
+                       if(glp_ptr->oper_nick2[0])
+                       {
+                               tmptr = localtime (&glp_ptr->time_request2);
+                               strftime (timebuffer, MAX_DATE_STRING, "%Y/%m/%d %H:%M:%S", tmptr);
+                               sendto_one_notice(source_p,
+                                           ":2) %s!%s@%s on %s requested gline at %s for %s@%s [%s]",
+                                           glp_ptr->oper_nick2,
+                                           glp_ptr->oper_user2, glp_ptr->oper_host2,
+                                           glp_ptr->oper_server2, timebuffer,
+                                           glp_ptr->user, glp_ptr->host, glp_ptr->reason2);
+                       }
+               }
+
+               if(dlink_list_length (&pending_glines) > 0)
+                       sendto_one_notice(source_p, ":End of Pending G-lines");
+       }
+       else
+               sendto_one_notice(source_p, ":This server does not support G-Lines");
+
+}
+
+/* stats_glines()
+ *
+ * input       - client pointer
+ * output      - none
+ * side effects - client is shown list of glines
+ */
+static void
+stats_glines (struct Client *source_p)
+{
+       if(ConfigFileEntry.glines)
+       {
+               dlink_node *gline_node;
+               struct ConfItem *kill_ptr;
+
+               DLINK_FOREACH_PREV (gline_node, glines.tail)
+               {
+                       kill_ptr = gline_node->data;
+
+                       sendto_one_numeric(source_p, RPL_STATSKLINE, 
+                                          form_str(RPL_STATSKLINE), 'G',
+                                           kill_ptr->host ? kill_ptr->host : "*",
+                                           kill_ptr->user ? kill_ptr->user : "*",
+                                           kill_ptr->passwd ? kill_ptr->passwd : "No Reason",
+                                           kill_ptr->spasswd ? "|" : "",
+                                           kill_ptr->spasswd ? kill_ptr->spasswd : "");
+               }
+       }
+       else
+               sendto_one_notice(source_p, ":This server does not support G-Lines");
+}
+
+
+static void
+stats_hubleaf(struct Client *source_p)
+{
+       struct remote_conf *hub_p;
+       dlink_node *ptr;
+
+       if((ConfigFileEntry.stats_h_oper_only || 
+           (ConfigServerHide.flatten_links && !IsExemptShide(source_p))) &&
+           !IsOper(source_p))
+       {
+               sendto_one_numeric(source_p, ERR_NOPRIVILEGES,
+                                  form_str (ERR_NOPRIVILEGES));
+               return;
+       }
+
+       DLINK_FOREACH(ptr, hubleaf_conf_list.head)
+       {
+               hub_p = ptr->data;
+
+               if(hub_p->flags & CONF_HUB)
+                       sendto_one_numeric(source_p, RPL_STATSHLINE,
+                                       form_str(RPL_STATSHLINE),
+                                       hub_p->host, hub_p->server);
+               else
+                       sendto_one_numeric(source_p, RPL_STATSLLINE,
+                                       form_str(RPL_STATSLLINE),
+                                       hub_p->host, hub_p->server);
+       }
+}
+
+
+static void
+stats_auth (struct Client *source_p)
+{
+       /* Oper only, if unopered, return ERR_NOPRIVS */
+       if((ConfigFileEntry.stats_i_oper_only == 2) && !IsOper (source_p))
+               sendto_one_numeric(source_p, ERR_NOPRIVILEGES,
+                                  form_str (ERR_NOPRIVILEGES));
+
+       /* If unopered, Only return matching auth blocks */
+       else if((ConfigFileEntry.stats_i_oper_only == 1) && !IsOper (source_p))
+       {
+               struct ConfItem *aconf;
+               char *name, *host, *pass, *user, *classname;
+               int port;
+
+               if(MyConnect (source_p))
+                       aconf = find_conf_by_address (source_p->host, source_p->sockhost, NULL,
+                                                     (struct sockaddr *)&source_p->localClient->ip,
+                                                     CONF_CLIENT,
+                                                     source_p->localClient->ip.ss_family,
+                                                     source_p->username);
+               else
+                       aconf = find_conf_by_address (source_p->host, NULL, NULL, NULL, CONF_CLIENT,
+                                                     0, source_p->username);
+
+               if(aconf == NULL)
+                       return;
+
+               get_printable_conf (aconf, &name, &host, &pass, &user, &port, &classname);
+
+               sendto_one_numeric(source_p, RPL_STATSILINE, form_str(RPL_STATSILINE),
+                                  name, show_iline_prefix(source_p, aconf, user),
+                                  host, port, classname);
+       }
+
+       /* Theyre opered, or allowed to see all auth blocks */
+       else
+               report_auth (source_p);
+}
+
+
+static void
+stats_tklines(struct Client *source_p)
+{
+       /* Oper only, if unopered, return ERR_NOPRIVS */
+       if((ConfigFileEntry.stats_k_oper_only == 2) && !IsOper (source_p))
+               sendto_one_numeric(source_p, ERR_NOPRIVILEGES,
+                                  form_str (ERR_NOPRIVILEGES));
+
+       /* If unopered, Only return matching klines */
+       else if((ConfigFileEntry.stats_k_oper_only == 1) && !IsOper (source_p))
+       {
+               struct ConfItem *aconf;
+               char *host, *pass, *user, *oper_reason;
+
+               if(MyConnect (source_p))
+                       aconf = find_conf_by_address (source_p->host, source_p->sockhost, NULL,
+                                                     (struct sockaddr *)&source_p->localClient->ip,
+                                                     CONF_KILL,
+                                                     source_p->localClient->ip.ss_family,
+                                                     source_p->username);
+               else
+                       aconf = find_conf_by_address (source_p->host, NULL, NULL, NULL, CONF_KILL,
+                                                     0, source_p->username);
+
+               if(aconf == NULL)
+                       return;
+
+               /* dont report a permanent kline as a tkline */
+               if((aconf->flags & CONF_FLAGS_TEMPORARY) == 0)
+                       return;
+
+               get_printable_kline(source_p, aconf, &host, &pass, &user, &oper_reason);
+
+               sendto_one_numeric(source_p, RPL_STATSKLINE, 
+                                  form_str(RPL_STATSKLINE), 'k',
+                                  user, pass, oper_reason ? "|" : "",
+                                  oper_reason ? oper_reason : "");
+       }
+       /* Theyre opered, or allowed to see all klines */
+       else
+       {
+               struct ConfItem *aconf;
+               dlink_node *ptr;
+               int i;
+               char *user, *host, *pass, *oper_reason;
+
+               for(i = 0; i < LAST_TEMP_TYPE; i++)
+               {
+                       DLINK_FOREACH(ptr, temp_klines[i].head)
+                       {
+                               aconf = ptr->data;
+
+                               get_printable_kline(source_p, aconf, &host, &pass, 
+                                                       &user, &oper_reason);
+
+                               sendto_one_numeric(source_p, RPL_STATSKLINE,
+                                                  form_str(RPL_STATSKLINE),
+                                                  'k', host, user, pass,
+                                                  oper_reason ? "|" : "",
+                                                  oper_reason ? oper_reason : "");
+                       }
+               }
+       }
+}
+
+static void
+stats_klines(struct Client *source_p)
+{
+       /* Oper only, if unopered, return ERR_NOPRIVS */
+       if((ConfigFileEntry.stats_k_oper_only == 2) && !IsOper (source_p))
+               sendto_one_numeric(source_p, ERR_NOPRIVILEGES,
+                                  form_str (ERR_NOPRIVILEGES));
+
+       /* If unopered, Only return matching klines */
+       else if((ConfigFileEntry.stats_k_oper_only == 1) && !IsOper (source_p))
+       {
+               struct ConfItem *aconf;
+               char *host, *pass, *user, *oper_reason;
+
+               /* search for a kline */
+               if(MyConnect (source_p))
+                       aconf = find_conf_by_address (source_p->host, source_p->sockhost, NULL,
+                                                     (struct sockaddr *)&source_p->localClient->ip,
+                                                     CONF_KILL,
+                                                     source_p->localClient->ip.ss_family,
+                                                     source_p->username);
+               else
+                       aconf = find_conf_by_address (source_p->host, NULL, NULL, NULL, CONF_KILL,
+                                                     0, source_p->username);
+
+               if(aconf == NULL)
+                       return;
+
+               /* dont report a tkline as a kline */
+               if(aconf->flags & CONF_FLAGS_TEMPORARY)
+                       return;
+
+               get_printable_kline(source_p, aconf, &host, &pass, &user, &oper_reason);
+
+               sendto_one_numeric(source_p, RPL_STATSKLINE, form_str(RPL_STATSKLINE),
+                                  'K', host, user, pass, oper_reason ? "|" : "",
+                                  oper_reason ? oper_reason : "");
+       }
+       /* Theyre opered, or allowed to see all klines */
+       else
+               report_Klines (source_p);
+}
+
+static void
+stats_messages(struct Client *source_p)
+{
+       report_messages(source_p);
+}
+
+static void
+stats_dnsbl(struct Client *source_p)
+{
+       dlink_node *ptr;
+       struct Blacklist *blptr;
+
+       DLINK_FOREACH(ptr, blacklist_list.head)
+       {
+               blptr = ptr->data;
+
+               /* use RPL_STATSDEBUG for now -- jilles */
+               sendto_one_numeric(source_p, RPL_STATSDEBUG, "n :%d %s %s (%d)",
+                               blptr->hits,
+                               blptr->host,
+                               blptr->status & CONF_ILLEGAL ? "disabled" : "active",
+                               blptr->refcount);
+       }
+}
+
+static void
+stats_oper(struct Client *source_p)
+{
+       struct oper_conf *oper_p;
+       dlink_node *ptr;
+
+       if(!IsOper(source_p) && ConfigFileEntry.stats_o_oper_only)
+       {
+               sendto_one_numeric(source_p, ERR_NOPRIVILEGES,
+                                  form_str (ERR_NOPRIVILEGES));
+               return;
+       }
+
+       DLINK_FOREACH(ptr, oper_conf_list.head)
+       {
+               oper_p = ptr->data;
+               
+               sendto_one_numeric(source_p, RPL_STATSOLINE, 
+                               form_str(RPL_STATSOLINE),
+                               oper_p->username, oper_p->host, oper_p->name,
+                               IsOper(source_p) ? get_oper_privs(oper_p->flags) : "0", "-1");
+       }
+}
+
+
+/* stats_operedup()
+ *
+ * input       - client pointer
+ * output      - none
+ * side effects - client is shown a list of active opers
+ */
+static void
+stats_operedup (struct Client *source_p)
+{
+       struct Client *target_p;
+       dlink_node *oper_ptr;
+       unsigned int count = 0;
+
+       DLINK_FOREACH (oper_ptr, oper_list.head)
+       {
+               target_p = oper_ptr->data;
+
+               if(IsOperInvis(target_p) && !IsOper(source_p))
+                       continue;
+
+               if(target_p->user->away)
+                       continue;
+
+               count++;
+
+               sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                                  "p :%s (%s@%s)",
+                                  target_p->name, target_p->username, 
+                                  target_p->host);
+       }
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                               "p :%u staff members", count);
+
+       stats_p_spy (source_p);
+}
+
+static void
+stats_ports (struct Client *source_p)
+{
+       if(!IsOper (source_p) && ConfigFileEntry.stats_P_oper_only)
+               sendto_one_numeric(source_p, ERR_NOPRIVILEGES,
+                                  form_str (ERR_NOPRIVILEGES));
+       else
+               show_ports (source_p);
+}
+
+static void
+stats_tresv(struct Client *source_p)
+{
+       struct ConfItem *aconf;
+       dlink_node *ptr;
+       int i;
+
+       DLINK_FOREACH(ptr, resv_conf_list.head)
+       {
+               aconf = ptr->data;
+               if(aconf->hold)
+                       sendto_one_numeric(source_p, RPL_STATSQLINE, 
+                                       form_str(RPL_STATSQLINE),
+                                       'q', aconf->port, aconf->name, aconf->passwd);
+       }
+
+       HASH_WALK(i, R_MAX, ptr, resvTable)
+       {
+               aconf = ptr->data;
+               if(aconf->hold)
+                       sendto_one_numeric(source_p, RPL_STATSQLINE, 
+                                       form_str(RPL_STATSQLINE),
+                                       'q', aconf->port, aconf->name, aconf->passwd);
+       }
+       HASH_WALK_END
+}
+
+
+static void
+stats_resv(struct Client *source_p)
+{
+       struct ConfItem *aconf;
+       dlink_node *ptr;
+       int i;
+
+       DLINK_FOREACH(ptr, resv_conf_list.head)
+       {
+               aconf = ptr->data;
+               if(!aconf->hold)
+                       sendto_one_numeric(source_p, RPL_STATSQLINE, 
+                                       form_str(RPL_STATSQLINE),
+                                       'Q', aconf->port, aconf->name, aconf->passwd);
+       }
+
+       HASH_WALK(i, R_MAX, ptr, resvTable)
+       {
+               aconf = ptr->data;
+               if(!aconf->hold)
+                       sendto_one_numeric(source_p, RPL_STATSQLINE, 
+                                       form_str(RPL_STATSQLINE),
+                                       'Q', aconf->port, aconf->name, aconf->passwd);
+       }
+       HASH_WALK_END
+}
+
+static void
+stats_usage (struct Client *source_p)
+{
+       struct rusage rus;
+       time_t secs;
+       time_t rup;
+#ifdef  hz
+# define hzz hz
+#else
+# ifdef HZ
+#  define hzz HZ
+# else
+       int hzz = 1;
+# endif
+#endif
+
+       if(getrusage(RUSAGE_SELF, &rus) == -1)
+       {
+               sendto_one_notice(source_p, ":Getruseage error: %s.",
+                                 strerror(errno));
+               return;
+       }
+       secs = rus.ru_utime.tv_sec + rus.ru_stime.tv_sec;
+       if(0 == secs)
+               secs = 1;
+
+       rup = (CurrentTime - startup_time) * hzz;
+       if(0 == rup)
+               rup = 1;
+  
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "R :CPU Secs %d:%d User %d:%d System %d:%d",
+                          (int) (secs / 60), (int) (secs % 60),
+                          (int) (rus.ru_utime.tv_sec / 60),
+                          (int) (rus.ru_utime.tv_sec % 60),
+                          (int) (rus.ru_stime.tv_sec / 60), 
+                          (int) (rus.ru_stime.tv_sec % 60));
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "R :RSS %ld ShMem %ld Data %ld Stack %ld",
+                          rus.ru_maxrss, (rus.ru_ixrss / rup), 
+                          (rus.ru_idrss / rup), (rus.ru_isrss / rup));
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "R :Swaps %d Reclaims %d Faults %d",
+                          (int) rus.ru_nswap, (int) rus.ru_minflt, (int) rus.ru_majflt);
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "R :Block in %d out %d",
+                          (int) rus.ru_inblock, (int) rus.ru_oublock);
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "R :Msg Rcv %d Send %d",
+                          (int) rus.ru_msgrcv, (int) rus.ru_msgsnd);
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "R :Signals %d Context Vol. %d Invol %d",
+                          (int) rus.ru_nsignals, (int) rus.ru_nvcsw, 
+                          (int) rus.ru_nivcsw);
+}
+
+static void
+stats_tstats (struct Client *source_p)
+{
+       tstats (source_p);
+}
+
+static void
+stats_uptime (struct Client *source_p)
+{
+       time_t now;
+
+       now = CurrentTime - startup_time;
+       sendto_one_numeric(source_p, RPL_STATSUPTIME, 
+                          form_str (RPL_STATSUPTIME),
+                          now / 86400, (now / 3600) % 24, 
+                          (now / 60) % 60, now % 60);
+       sendto_one_numeric(source_p, RPL_STATSCONN,
+                          form_str (RPL_STATSCONN),
+                          MaxConnectionCount, MaxClientCount, 
+                          Count.totalrestartcount);
+}
+
+struct shared_flags
+{
+       int flag;
+       char letter;
+};
+static struct shared_flags shared_flagtable[] =
+{
+       { SHARED_PKLINE,        'K' },
+       { SHARED_TKLINE,        'k' },
+       { SHARED_UNKLINE,       'U' },
+       { SHARED_PXLINE,        'X' },
+       { SHARED_TXLINE,        'x' },
+       { SHARED_UNXLINE,       'Y' },
+       { SHARED_PRESV,         'Q' },
+       { SHARED_TRESV,         'q' },
+       { SHARED_UNRESV,        'R' },
+       { SHARED_LOCOPS,        'L' },
+       { SHARED_REHASH,        'H' },
+       { 0,                    '\0'}
+};
+
+
+static void
+stats_shared (struct Client *source_p)
+{
+       struct remote_conf *shared_p;
+       dlink_node *ptr;
+       char buf[15];
+       char *p;
+       int i;
+
+       DLINK_FOREACH(ptr, shared_conf_list.head)
+       {
+               shared_p = ptr->data;
+
+               p = buf;
+
+               *p++ = 'c';
+
+               for(i = 0; shared_flagtable[i].flag != 0; i++)
+               {
+                       if(shared_p->flags & shared_flagtable[i].flag)
+                               *p++ = shared_flagtable[i].letter;
+               }
+
+               *p = '\0';
+
+               sendto_one_numeric(source_p, RPL_STATSULINE, 
+                                       form_str(RPL_STATSULINE),
+                                       shared_p->server, shared_p->username,
+                                       shared_p->host, buf);
+       }
+
+       DLINK_FOREACH(ptr, cluster_conf_list.head)
+       {
+               shared_p = ptr->data;
+
+               p = buf;
+
+               *p++ = 'C';
+
+               for(i = 0; shared_flagtable[i].flag != 0; i++)
+               {
+                       if(shared_p->flags & shared_flagtable[i].flag)
+                               *p++ = shared_flagtable[i].letter;
+               }
+
+               *p = '\0';
+
+               sendto_one_numeric(source_p, RPL_STATSULINE, 
+                                       form_str(RPL_STATSULINE),
+                                       shared_p->server, "*", "*", buf);
+       }
+}
+
+/* stats_servers()
+ *
+ * input       - client pointer
+ * output      - none
+ * side effects - client is shown lists of who connected servers
+ */
+static void
+stats_servers (struct Client *source_p)
+{
+       struct Client *target_p;
+       dlink_node *ptr;
+       time_t seconds;
+       int days, hours, minutes;
+       int j = 0;
+
+       if(ConfigServerHide.flatten_links && !IsOper(source_p) &&
+          !IsExemptShide(source_p))
+       {
+               sendto_one_numeric(source_p, ERR_NOPRIVILEGES,
+                                  form_str (ERR_NOPRIVILEGES));
+               return;
+       }
+
+       DLINK_FOREACH (ptr, serv_list.head)
+       {
+               target_p = ptr->data;
+
+               j++;
+               seconds = CurrentTime - target_p->localClient->firsttime;
+
+               days = (int) (seconds / 86400);
+               seconds %= 86400;
+               hours = (int) (seconds / 3600);
+               seconds %= 3600;
+               minutes = (int) (seconds / 60);
+               seconds %= 60;
+
+               sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                                  "V :%s (%s!*@*) Idle: %d SendQ: %d "
+                                  "Connected: %d day%s, %d:%02d:%02d",
+                                  target_p->name,
+                                  (target_p->serv->by[0] ? target_p->serv->by : "Remote."),
+                                  (int) (CurrentTime - target_p->localClient->lasttime),
+                                  (int) linebuf_len (&target_p->localClient->buf_sendq),
+                                  days, (days == 1) ? "" : "s", hours, minutes, 
+                                  (int) seconds);
+       }
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "V :%d Server(s)", j);
+}
+
+static void
+stats_tgecos(struct Client *source_p)
+{
+       struct ConfItem *aconf;
+       dlink_node *ptr;
+
+       DLINK_FOREACH(ptr, xline_conf_list.head)
+       {
+               aconf = ptr->data;
+
+               if(aconf->hold)
+                       sendto_one_numeric(source_p, RPL_STATSXLINE,
+                                       form_str(RPL_STATSXLINE),
+                                       'x', aconf->port, aconf->name,
+                                       aconf->passwd);
+       }
+}
+
+static void
+stats_gecos(struct Client *source_p)
+{
+       struct ConfItem *aconf;
+       dlink_node *ptr;
+
+       DLINK_FOREACH(ptr, xline_conf_list.head)
+       {
+               aconf = ptr->data;
+
+               if(!aconf->hold)
+                       sendto_one_numeric(source_p, RPL_STATSXLINE,
+                                       form_str(RPL_STATSXLINE),
+                                       'X', aconf->port, aconf->name, 
+                                       aconf->passwd);
+       }
+}
+
+static void
+stats_class(struct Client *source_p)
+{
+       if(ConfigFileEntry.stats_y_oper_only && !IsOper(source_p))
+               sendto_one_numeric(source_p, ERR_NOPRIVILEGES,
+                                  form_str (ERR_NOPRIVILEGES));
+       else
+               report_classes(source_p);
+}
+
+static void
+stats_memory (struct Client *source_p)
+{
+       count_memory (source_p);
+}
+
+static void
+stats_ziplinks (struct Client *source_p)
+{
+       dlink_node *ptr;
+       struct Client *target_p;
+       int sent_data = 0;
+
+       DLINK_FOREACH (ptr, serv_list.head)
+       {
+               target_p = ptr->data;
+               if(IsCapable (target_p, CAP_ZIP))
+               {
+                       /* we use memcpy(3) and a local copy of the structure to
+                        * work around a register use bug on GCC on the SPARC.
+                        * -jmallett, 04/27/2002
+                        */
+                       struct ZipStats zipstats;
+                       memcpy (&zipstats, &target_p->localClient->zipstats,
+                               sizeof (struct ZipStats)); 
+                       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                                           "Z :ZipLinks stats for %s send[%.2f%% compression "
+                                           "(%lu kB data/%lu kB wire)] recv[%.2f%% compression "
+                                           "(%lu kB data/%lu kB wire)]",
+                                           target_p->name,
+                                           zipstats.out_ratio, zipstats.outK, zipstats.outK_wire,
+                                           zipstats.in_ratio, zipstats.inK, zipstats.inK_wire);
+                       sent_data++;
+               }
+       }
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "Z :%u ziplink(s)", sent_data);
+}
+
+static void
+stats_servlinks (struct Client *source_p)
+{
+       static char Sformat[] = ":%s %d %s %s %u %u %u %u %u :%u %u %s";
+       long uptime, sendK, receiveK;
+       struct Client *target_p;
+       dlink_node *ptr;
+       int j = 0;
+
+       if(ConfigServerHide.flatten_links && !IsOper (source_p) &&
+          !IsExemptShide(source_p))
+       {
+               sendto_one_numeric(source_p, ERR_NOPRIVILEGES,
+                                  form_str (ERR_NOPRIVILEGES));
+               return;
+       }
+
+       sendK = receiveK = 0;
+
+       DLINK_FOREACH (ptr, serv_list.head)
+       {
+               target_p = ptr->data;
+
+               j++;
+               sendK += target_p->localClient->sendK;
+               receiveK += target_p->localClient->receiveK;
+
+               sendto_one(source_p, Sformat,
+                       get_id(&me, source_p), RPL_STATSLINKINFO, get_id(source_p, source_p),
+                       get_server_name(target_p, SHOW_IP),
+                       (int) linebuf_len (&target_p->localClient->buf_sendq),
+                       (int) target_p->localClient->sendM,
+                       (int) target_p->localClient->sendK,
+                       (int) target_p->localClient->receiveM,
+                       (int) target_p->localClient->receiveK,
+                       CurrentTime - target_p->localClient->firsttime,
+                       (CurrentTime > target_p->localClient->lasttime) ? 
+                        (CurrentTime - target_p->localClient->lasttime) : 0,
+                       IsOper (source_p) ? show_capabilities (target_p) : "TS");
+       }
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "? :%u total server(s)", j);
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "? :Sent total : %7.2f %s",
+                          _GMKv (sendK), _GMKs (sendK));
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "? :Recv total : %7.2f %s",
+                          _GMKv (receiveK), _GMKs (receiveK));
+
+       uptime = (CurrentTime - startup_time);
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "? :Server send: %7.2f %s (%4.1f K/s)",
+                          _GMKv (me.localClient->sendK), 
+                          _GMKs (me.localClient->sendK),
+                          (float) ((float) me.localClient->sendK / (float) uptime));
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "? :Server recv: %7.2f %s (%4.1f K/s)",
+                          _GMKv (me.localClient->receiveK),
+                          _GMKs (me.localClient->receiveK),
+                          (float) ((float) me.localClient->receiveK / (float) uptime));
+}
+
+static void
+stats_ltrace(struct Client *source_p, int parc, const char *parv[])
+{
+       int doall = 0;
+       int wilds = 0;
+       const char *name;
+       char statchar = parv[1][0];
+
+       /* this is def targeted at us somehow.. */
+       if(parc > 2 && !EmptyString(parv[2]))
+       {
+               /* directed at us generically? */
+               if(match(parv[2], me.name) ||
+                  (!MyClient(source_p) && !irccmp(parv[2], me.id)))
+               {
+                       name = me.name;
+                       doall = 1;
+               }
+               else
+               {
+                       name = parv[2];
+                       wilds = strchr(name, '*') || strchr(name, '?');
+               }
+
+               /* must be directed at a specific person thats not us */
+               if(!doall && !wilds)
+               {
+                       struct Client *target_p;
+
+                       if(MyClient(source_p))
+                               target_p = find_named_person(name);
+                       else
+                               target_p = find_person(name);
+
+                       if(target_p != NULL)
+                       {
+                               stats_spy(source_p, statchar, target_p->name);
+                               stats_l_client(source_p, target_p, statchar);
+                       }
+                       else
+                               sendto_one_numeric(source_p, ERR_NOSUCHSERVER,
+                                               form_str(ERR_NOSUCHSERVER),
+                                               name);
+
+                       return;
+               }
+       }
+       else
+       {
+               name = me.name;
+               doall = 1;
+       }
+
+       stats_spy(source_p, statchar, name);
+
+       if(doall)
+       {
+               /* local opers get everyone */
+               if(MyOper(source_p))
+               {
+                       stats_l_list(source_p, name, doall, wilds, &unknown_list, statchar);
+                       stats_l_list(source_p, name, doall, wilds, &lclient_list, statchar);
+               }
+               else
+               {
+                       /* they still need themselves if theyre local.. */
+                       if(MyClient(source_p))
+                               stats_l_client(source_p, source_p, statchar);
+
+                       stats_l_list(source_p, name, doall, wilds, &local_oper_list, statchar);
+               }
+
+               if (!ConfigServerHide.flatten_links || IsOper(source_p) ||
+                               IsExemptShide(source_p))
+                       stats_l_list(source_p, name, doall, wilds, &serv_list, statchar);
+
+               return;
+       }
+
+       /* ok, at this point theyre looking for a specific client whos on
+        * our server.. but it contains a wildcard.  --fl
+        */
+       stats_l_list(source_p, name, doall, wilds, &lclient_list, statchar);
+
+       return;
+}
+
+
+static void
+stats_l_list(struct Client *source_p, const char *name, int doall, int wilds,
+            dlink_list * list, char statchar)
+{
+       dlink_node *ptr;
+       struct Client *target_p;
+
+       /* send information about connections which match.  note, we
+        * dont need tests for IsInvisible(), because non-opers will
+        * never get here for normal clients --fl
+        */
+       DLINK_FOREACH(ptr, list->head)
+       {
+               target_p = ptr->data;
+
+               if(!doall && wilds && !match(name, target_p->name))
+                       continue;
+
+               stats_l_client(source_p, target_p, statchar);
+       }
+}
+
+void
+stats_l_client(struct Client *source_p, struct Client *target_p,
+               char statchar)
+{
+       if(IsAnyServer(target_p))
+       {
+               sendto_one_numeric(source_p, RPL_STATSLINKINFO, Lformat,
+                               get_server_name(target_p, SHOW_IP),
+                               (int) linebuf_len(&target_p->localClient->buf_sendq),
+                               (int) target_p->localClient->sendM,
+                               (int) target_p->localClient->sendK,
+                               (int) target_p->localClient->receiveM,
+                               (int) target_p->localClient->receiveK,
+                               CurrentTime - target_p->localClient->firsttime,
+                               (CurrentTime > target_p->localClient->lasttime) ? 
+                                (CurrentTime - target_p->localClient->lasttime) : 0,
+                               IsOper(source_p) ? show_capabilities(target_p) : "-");
+       }
+
+       else
+       {
+               sendto_one_numeric(source_p, RPL_STATSLINKINFO, Lformat,
+                                  show_ip(source_p, target_p) ?
+                                   (IsUpper(statchar) ?
+                                    get_client_name(target_p, SHOW_IP) :
+                                    get_client_name(target_p, HIDE_IP)) :
+                                   get_client_name(target_p, MASK_IP),
+                                   (int) linebuf_len(&target_p->localClient->buf_sendq),
+                                   (int) target_p->localClient->sendM,
+                                   (int) target_p->localClient->sendK,
+                                   (int) target_p->localClient->receiveM,
+                                   (int) target_p->localClient->receiveK,
+                                   CurrentTime - target_p->localClient->firsttime,
+                                   (CurrentTime > target_p->localClient->lasttime) ? 
+                                    (CurrentTime - target_p->localClient->lasttime) : 0,
+                                   "-");
+       }
+}
+
+/*
+ * stats_spy
+ *
+ * inputs      - pointer to client doing the /stats
+ *             - char letter they are doing /stats on
+ * output      - none
+ * side effects -
+ * This little helper function reports to opers if configured.
+ * personally, I don't see why opers need to see stats requests
+ * at all. They are just "noise" to an oper, and users can't do
+ * any damage with stats requests now anyway. So, why show them?
+ * -Dianora
+ */
+static void
+stats_spy(struct Client *source_p, char statchar, const char *name)
+{
+       hook_data_int data;
+
+       data.client = source_p;
+       data.arg1 = name;
+       data.arg2 = (int) statchar;
+
+       call_hook(doing_stats_hook, &data);
+}
+
+/* stats_p_spy()
+ *
+ * input       - pointer to client doing stats
+ * ouput       -
+ * side effects - call hook doing_stats_p
+ */
+static void
+stats_p_spy (struct Client *source_p)
+{
+       hook_data data;
+
+       data.client = source_p;
+       data.arg1 = data.arg2 = NULL;
+
+       call_hook(doing_stats_p_hook, &data);
+}
+
diff --git a/modules/m_svinfo.c b/modules/m_svinfo.c
new file mode 100644 (file)
index 0000000..9067a64
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_svinfo.c: Sends TS information for clock & compatibility checks.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_svinfo.c 494 2006-01-15 16:08:28Z jilles $
+ */
+#include "stdinc.h"
+#include "client.h"
+#include "common.h"            /* TRUE bleah */
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "s_conf.h"
+#include "s_log.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+
+static int ms_svinfo(struct Client *, struct Client *, int, const char **);
+
+struct Message svinfo_msgtab = {
+       "SVINFO", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_ignore, mg_ignore, {ms_svinfo, 5}, mg_ignore, mg_ignore}
+};
+
+mapi_clist_av1 svinfo_clist[] = { &svinfo_msgtab, NULL };
+DECLARE_MODULE_AV1(svinfo, NULL, NULL, svinfo_clist, NULL, NULL, "$Revision: 494 $");
+
+/*
+ * ms_svinfo - SVINFO message handler
+ *      parv[0] = sender prefix
+ *      parv[1] = TS_CURRENT for the server
+ *      parv[2] = TS_MIN for the server
+ *      parv[3] = unused, send 0
+ *      parv[4] = server's idea of UTC time
+ */
+static int
+ms_svinfo(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       signed int deltat;
+       time_t theirtime;
+
+       /* SVINFO isnt remote. */
+       if(source_p != client_p)
+               return 0;
+
+       if(TS_CURRENT < atoi(parv[2]) || atoi(parv[1]) < TS_MIN)
+       {
+               /* TS version is too low on one of the sides, drop the link */
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Link %s dropped, wrong TS protocol version (%s,%s)",
+                                    get_server_name(source_p, SHOW_IP), parv[1], parv[2]);
+               exit_client(source_p, source_p, source_p, "Incompatible TS version");
+               return 0;
+       }
+
+       /*
+        * since we're here, might as well set CurrentTime while we're at it
+        */
+       set_time();
+       theirtime = atol(parv[4]);
+       deltat = abs(theirtime - CurrentTime);
+
+       if(deltat > ConfigFileEntry.ts_max_delta)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Link %s dropped, excessive TS delta"
+                                    " (my TS=%ld, their TS=%ld, delta=%d)",
+                                    get_server_name(source_p, SHOW_IP),
+                                    (long) CurrentTime, (long) theirtime, deltat);
+               ilog(L_SERVER,
+                    "Link %s dropped, excessive TS delta"
+                    " (my TS=%ld, their TS=%ld, delta=%d)",
+                    log_client_name(source_p, SHOW_IP), (long) CurrentTime, (long) theirtime, deltat);
+               exit_client(source_p, source_p, source_p, "Excessive TS delta");
+               return 0;
+       }
+
+       if(deltat > ConfigFileEntry.ts_warn_delta)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Link %s notable TS delta"
+                                    " (my TS=%ld, their TS=%ld, delta=%d)",
+                                    source_p->name, (long) CurrentTime, (long) theirtime, deltat);
+       }
+
+       return 0;
+}
+
diff --git a/modules/m_tb.c b/modules/m_tb.c
new file mode 100644 (file)
index 0000000..eac3ae3
--- /dev/null
@@ -0,0 +1,126 @@
+/* modules/m_tb.c
+ * 
+ *  Copyright (C) 2003 Lee Hardy <lee@leeh.co.uk>
+ *  Copyright (C) 2003-2005 ircd-ratbox development team
+ *
+ * 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.The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: m_tb.c 1349 2006-05-17 17:37:46Z jilles $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "send.h"
+#include "channel.h"
+#include "client.h"
+#include "common.h"
+#include "config.h"
+#include "ircd.h"
+#include "irc_string.h"
+#include "s_conf.h"
+#include "msg.h"
+#include "modules.h"
+#include "hash.h"
+#include "s_serv.h"
+
+static int ms_tb(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
+
+struct Message tb_msgtab = {
+       "TB", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_ignore, mg_ignore, {ms_tb, 4}, mg_ignore, mg_ignore}
+};
+
+mapi_clist_av1 tb_clist[] =  { &tb_msgtab, NULL };
+DECLARE_MODULE_AV1(tb, NULL, NULL, tb_clist, NULL, NULL, "$Revision: 1349 $");
+
+/* m_tb()
+ *
+ * parv[1] - channel
+ * parv[2] - topic ts
+ * parv[3] - optional topicwho/topic
+ * parv[4] - topic
+ */
+static int
+ms_tb(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Channel *chptr;
+       const char *newtopic;
+       const char *newtopicwho;
+       time_t newtopicts;
+       struct Client *fakesource_p;
+
+       chptr = find_channel(parv[1]);
+
+       if(chptr == NULL)
+               return 0;
+
+       newtopicts = atol(parv[2]);
+
+       /* Hide connecting server on netburst -- jilles */
+       if (ConfigServerHide.flatten_links && !HasSentEob(source_p))
+               fakesource_p = &me;
+       else
+               fakesource_p = source_p;
+
+       if(parc == 5)
+       {
+               newtopic = parv[4];
+               newtopicwho = parv[3];
+       }
+       else
+       {
+               newtopic = parv[3];
+               newtopicwho = fakesource_p->name;
+       }
+
+       if (EmptyString(newtopic))
+               return 0;
+
+       if(chptr->topic == NULL || chptr->topic_time > newtopicts)
+       {
+               /* its possible the topicts is a few seconds out on some
+                * servers, due to lag when propagating it, so if theyre the
+                * same topic just drop the message --fl
+                */
+               if(chptr->topic != NULL && strcmp(chptr->topic, newtopic) == 0)
+                       return 0;
+
+               set_channel_topic(chptr, newtopic, newtopicwho, newtopicts);
+               sendto_channel_local(ALL_MEMBERS, chptr, ":%s TOPIC %s :%s",
+                                    fakesource_p->name, chptr->chname, newtopic);
+               sendto_server(client_p, chptr, CAP_TB|CAP_TS6, NOCAPS,
+                             ":%s TB %s %ld %s%s:%s",
+                             use_id(source_p), chptr->chname, (long) chptr->topic_time,
+                             ConfigChannel.burst_topicwho ? chptr->topic_info : "",
+                             ConfigChannel.burst_topicwho ? " " : "", chptr->topic);
+               sendto_server(client_p, chptr, CAP_TB, CAP_TS6,
+                             ":%s TB %s %ld %s%s:%s",
+                             source_p->name, chptr->chname, (long) chptr->topic_time,
+                             ConfigChannel.burst_topicwho ? chptr->topic_info : "",
+                             ConfigChannel.burst_topicwho ? " " : "", chptr->topic);
+       }
+
+       return 0;
+}
diff --git a/modules/m_testline.c b/modules/m_testline.c
new file mode 100644 (file)
index 0000000..c57bd09
--- /dev/null
@@ -0,0 +1,215 @@
+/* modules/m_testline.c
+ * 
+ *  Copyright (C) 2004 Lee Hardy <lee@leeh.co.uk>
+ *  Copyright (C) 2004-2005 ircd-ratbox development team
+ *
+ * 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.The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: m_testline.c 2757 2006-11-10 22:58:15Z jilles $
+ */
+#include "stdinc.h"
+#include "tools.h"
+#include "send.h"
+#include "client.h"
+#include "modules.h"
+#include "msg.h"
+#include "hostmask.h"
+#include "numeric.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "sprintf_irc.h"
+
+static int mo_testline(struct Client *, struct Client *, int, const char **);
+static int mo_testgecos(struct Client *, struct Client *, int, const char **);
+
+struct Message testline_msgtab = {
+       "TESTLINE", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_ignore, mg_ignore, mg_ignore, mg_ignore, {mo_testline, 2}}
+};
+struct Message testgecos_msgtab = {
+       "TESTGECOS", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_ignore, mg_ignore, mg_ignore, mg_ignore, {mo_testgecos, 2}}
+};
+
+mapi_clist_av1 testline_clist[] = { &testline_msgtab, &testgecos_msgtab, NULL };
+DECLARE_MODULE_AV1(testline, NULL, NULL, testline_clist, NULL, NULL, "$Revision: 2757 $");
+
+static int
+mo_testline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct ConfItem *aconf;
+       struct ConfItem *resv_p;
+       struct irc_sockaddr_storage ip;
+       char user_trunc[USERLEN + 1], notildeuser_trunc[USERLEN + 1];
+       const char *name = NULL;
+       const char *username = NULL;
+       const char *host = NULL;
+       char *mask;
+       char *p;
+       int host_mask;
+       int type;
+
+       mask = LOCAL_COPY(parv[1]);
+
+       if((p = strchr(mask, '!')))
+       {
+               *p++ = '\0';
+               name = mask;
+               mask = p;
+
+               if(EmptyString(mask))
+                       return 0;
+       }
+
+       if((p = strchr(mask, '@')))
+       {
+               *p++ = '\0';
+               username = mask;
+               host = p;
+
+               if(EmptyString(host))
+                       return 0;
+       }
+       else
+               host = mask;
+
+       /* parses as an IP, check for a dline */
+       if((type = parse_netmask(host, (struct sockaddr *)&ip, &host_mask)) != HM_HOST)
+       {
+#ifdef IPV6
+               if(type == HM_IPV6)
+                       aconf = find_dline((struct sockaddr *)&ip, AF_INET6);
+               else
+#endif
+                       aconf = find_dline((struct sockaddr *)&ip, AF_INET);
+
+               if(aconf && aconf->status & CONF_DLINE)
+               {
+                       sendto_one(source_p, form_str(RPL_TESTLINE),
+                               me.name, source_p->name,
+                               (aconf->flags & CONF_FLAGS_TEMPORARY) ? 'd' : 'D',
+                               (aconf->flags & CONF_FLAGS_TEMPORARY) ? 
+                                (long) ((aconf->hold - CurrentTime) / 60) : 0L, 
+                               aconf->host, aconf->passwd);
+
+                       return 0;
+               }
+       }
+
+       if (username != NULL)
+       {
+               strlcpy(user_trunc, username, sizeof user_trunc);
+               strlcpy(notildeuser_trunc, *username == '~' ? username + 1 : username, sizeof notildeuser_trunc);
+       }
+       else
+       {
+               strlcpy(user_trunc, "dummy", sizeof user_trunc);
+               strlcpy(notildeuser_trunc, "dummy", sizeof notildeuser_trunc);
+       }
+       /* now look for a matching I/K/G */
+       if((aconf = find_address_conf(host, NULL, user_trunc, notildeuser_trunc,
+                               (type != HM_HOST) ? (struct sockaddr *)&ip : NULL,
+                               (type != HM_HOST) ? (
+#ifdef IPV6
+                                (type == HM_IPV6) ? AF_INET6 : 
+#endif
+                                 AF_INET) : 0)))
+       {
+               static char buf[HOSTLEN+USERLEN+2];
+
+               if(aconf->status & CONF_KILL)
+               {
+                       ircsnprintf(buf, sizeof(buf), "%s@%s", 
+                                       aconf->user, aconf->host);
+                       sendto_one(source_p, form_str(RPL_TESTLINE),
+                               me.name, source_p->name,
+                               (aconf->flags & CONF_FLAGS_TEMPORARY) ? 'k' : 'K',
+                               (aconf->flags & CONF_FLAGS_TEMPORARY) ? 
+                                (long) ((aconf->hold - CurrentTime) / 60) : 0L,
+                               buf, aconf->passwd);
+                       return 0;
+               }
+               else if(aconf->status & CONF_GLINE)
+               {
+                       ircsnprintf(buf, sizeof(buf), "%s@%s",
+                                       aconf->user, aconf->host);
+                       sendto_one(source_p, form_str(RPL_TESTLINE),
+                               me.name, source_p->name,
+                               'G', (long) ((aconf->hold - CurrentTime) / 60),
+                               buf, aconf->passwd);
+                       return 0;
+               }
+       }
+
+       /* they asked us to check a nick, so hunt for resvs.. */
+       if(name && (resv_p = find_nick_resv(name)))
+       {
+               sendto_one(source_p, form_str(RPL_TESTLINE),
+                               me.name, source_p->name,
+                               resv_p->hold ? 'q' : 'Q',
+                               resv_p->hold ? (long) ((resv_p->hold - CurrentTime) / 60) : 0L,
+                               resv_p->name, resv_p->passwd);
+
+               /* this is a false positive, so make sure it isn't counted in stats q
+                * --nenolod
+                */
+               resv_p->port--;
+               return 0;
+       }
+
+       /* no matching resv, we can print the I: if it exists */
+       if(aconf && aconf->status & CONF_CLIENT)
+       {
+               sendto_one_numeric(source_p, RPL_STATSILINE, form_str(RPL_STATSILINE),
+                               aconf->name, show_iline_prefix(source_p, aconf, aconf->user),
+                               aconf->host, aconf->port, aconf->className);
+               return 0;
+       }
+
+       /* nothing matches.. */
+       sendto_one(source_p, form_str(RPL_NOTESTLINE),
+                       me.name, source_p->name, parv[1]);
+       return 0;
+}
+
+static int
+mo_testgecos(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct ConfItem *aconf;
+
+       if(!(aconf = find_xline(parv[1], 0)))
+       {
+               sendto_one(source_p, form_str(RPL_NOTESTLINE),
+                               me.name, source_p->name, parv[1]);
+               return 0;
+       }
+
+       sendto_one(source_p, form_str(RPL_TESTLINE),
+                       me.name, source_p->name,
+                       aconf->hold ? 'x' : 'X',
+                       aconf->hold ? (long) ((aconf->hold - CurrentTime) / 60) : 0L,
+                       aconf->name, aconf->passwd);
+       return 0;
+}
diff --git a/modules/m_testmask.c b/modules/m_testmask.c
new file mode 100644 (file)
index 0000000..2fa4eea
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ *  m_testmask.c: Shows the number of matching local and global clients
+ *                for a user@host mask, helpful when setting GLINE's
+ *
+ *  Copyright (C) 2003 by W. Campbell
+ *  Coypright (C) 2004 ircd-ratbox development team
+ *
+ *  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.The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission. 
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ *  $Id: m_testmask.c 2775 2006-11-27 11:45:31Z jilles $
+ *
+ */
+
+/* List of ircd includes from ../include/ */
+#include "stdinc.h"
+#include "client.h"
+#include "common.h"     /* FALSE bleah */
+#include "ircd.h"
+#include "irc_string.h"
+#include "numeric.h"
+#include "s_conf.h"
+#include "s_log.h"
+#include "s_serv.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+
+static int mo_testmask(struct Client *client_p, struct Client *source_p,
+                       int parc, const char *parv[]);
+
+struct Message testmask_msgtab = {
+       "TESTMASK", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_testmask, 2}}
+};
+
+mapi_clist_av1 testmask_clist[] = { &testmask_msgtab, NULL };
+DECLARE_MODULE_AV1(testmask, NULL, NULL, testmask_clist, NULL, NULL, "$Revision: 2775 $");
+
+static const char *empty_sockhost = "255.255.255.255";
+static const char *spoofed_sockhost = "0";
+
+static int
+mo_testmask(struct Client *client_p, struct Client *source_p,
+                        int parc, const char *parv[])
+{
+       struct Client *target_p;
+       int lcount = 0;
+       int gcount = 0;
+       char *name, *username, *hostname;
+       const char *sockhost;
+       char *gecos = NULL, *mangle_gecos = NULL;
+       dlink_node *ptr;
+
+       name = LOCAL_COPY(parv[1]);
+       collapse(name);
+
+       /* username is required */
+       if((hostname = strchr(name, '@')) == NULL)
+       {
+               sendto_one(source_p, ":%s NOTICE %s :Invalid parameters",
+                               me.name, source_p->name);
+               return 0;
+       }
+
+       *hostname++ = '\0';
+
+       /* nickname is optional */
+       if((username = strchr(name, '!')) == NULL)
+       {
+               username = name;
+               name = NULL;
+       }
+       else
+               *username++ = '\0';
+
+       if(EmptyString(username) || EmptyString(hostname))
+       {
+               sendto_one(source_p, ":%s NOTICE %s :Invalid parameters",
+                               me.name, source_p->name);
+               return 0;
+       }
+
+       if(parc > 2 && !EmptyString(parv[2]))
+       {
+               gecos = LOCAL_COPY(parv[2]);
+               collapse_esc(gecos);
+               if(strstr(gecos, "\\s"))
+               {
+                       char *tmp = LOCAL_COPY(gecos);
+                       char *orig = tmp;
+                       char *new = tmp; 
+                       while(*orig)
+                       {
+                               if(*orig == '\\' && *(orig + 1) != '\0')
+                               {
+                                       if(*(orig + 1) == 's')
+                                       {
+                                               *new++ = ' ';
+                                               orig += 2;   
+                                       }
+                                       /* otherwise skip that and the escaped
+                                        * character after it, so we dont mistake
+                                        * \\s as \s --fl
+                                        */
+                                       else
+                                       {   
+                                               *new++ = *orig++;
+                                               *new++ = *orig++;
+                                       }
+                               }
+                               else
+                                       *new++ = *orig++;
+                       }
+
+                       *new = '\0';
+                       mangle_gecos = LOCAL_COPY(tmp);
+               } else
+                       mangle_gecos = gecos;
+       }
+
+       DLINK_FOREACH(ptr, global_client_list.head)
+       {
+               target_p = ptr->data;
+
+               if(!IsPerson(target_p))
+                       continue;
+
+               if(EmptyString(target_p->sockhost))
+                       sockhost = empty_sockhost;
+               else if(!show_ip(source_p, target_p))
+                       sockhost = spoofed_sockhost;
+               else
+                       sockhost = target_p->sockhost;
+
+               if(match(username, target_p->username) &&
+                  (match(hostname, target_p->host) ||
+                   match(hostname, target_p->orighost) ||
+                   match(hostname, sockhost) || match_ips(hostname, sockhost)))
+               {
+                       if(name && !match(name, target_p->name))
+                               continue;
+
+                       if(mangle_gecos && !match_esc(mangle_gecos, target_p->info))
+                               continue;
+
+                       if(MyClient(target_p))
+                               lcount++;
+                       else
+                               gcount++;
+               }
+       }
+
+       sendto_one(source_p, form_str(RPL_TESTMASKGECOS),
+                       me.name, source_p->name,
+                       lcount, gcount, name ? name : "*",
+                       username, hostname, gecos ? gecos : "*");
+       return 0;
+}
diff --git a/modules/m_time.c b/modules/m_time.c
new file mode 100644 (file)
index 0000000..26568c8
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_time.c: Sends the current time on the server.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_time.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_conf.h"
+#include "s_serv.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "packet.h"
+#include "sprintf_irc.h"
+
+static int m_time(struct Client *, struct Client *, int, const char **);
+static char *date(void);
+
+struct Message time_msgtab = {
+       "TIME", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_time, 0}, {m_time, 2}, mg_ignore, mg_ignore, {m_time, 0}}
+};
+
+mapi_clist_av1 time_clist[] = { &time_msgtab, NULL };
+DECLARE_MODULE_AV1(time, NULL, NULL, time_clist, NULL, NULL, "$Revision: 254 $");
+
+static const char *months[] = {
+       "January", "February", "March", "April",
+       "May", "June", "July", "August",
+       "September", "October", "November", "December"
+};
+
+static const char *weekdays[] = {
+       "Sunday", "Monday", "Tuesday", "Wednesday",
+       "Thursday", "Friday", "Saturday"
+};
+
+/*
+ * m_time
+ *      parv[0] = sender prefix
+ *      parv[1] = servername
+ */
+static int
+m_time(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       /* this is not rate limited, so end the grace period */
+       if(MyClient(source_p) && !IsFloodDone(source_p))
+               flood_endgrace(source_p);
+
+       if(hunt_server(client_p, source_p, ":%s TIME :%s", 1, parc, parv) == HUNTED_ISME)
+               sendto_one_numeric(source_p, RPL_TIME, form_str(RPL_TIME),
+                                  me.name, date());
+
+       return 0;
+}
+
+/* date()
+ *
+ * returns date in human readable form
+ */
+static char *
+date(void)
+{
+       static char buf[80];
+       char plus;
+       struct tm *lt;
+       struct tm *gm;
+       struct tm gmbuf;
+       time_t lclock;
+       int minswest;
+
+       lclock = CurrentTime;
+       gm = gmtime(&lclock);
+       memcpy((void *) &gmbuf, (void *) gm, sizeof(gmbuf));
+       gm = &gmbuf;
+       lt = localtime(&lclock);
+
+       if(lt->tm_yday == gm->tm_yday)
+               minswest = (gm->tm_hour - lt->tm_hour) * 60 + (gm->tm_min - lt->tm_min);
+       else if(lt->tm_yday > gm->tm_yday && lt->tm_year == gm->tm_year)
+               minswest = (gm->tm_hour - (lt->tm_hour + 24)) * 60;
+       else
+               minswest = ((gm->tm_hour + 24) - lt->tm_hour) * 60;
+
+       plus = (minswest > 0) ? '-' : '+';
+
+       if(minswest < 0)
+               minswest = -minswest;
+
+       ircsprintf(buf, "%s %s %d %d -- %02u:%02u:%02u %c%02u:%02u",
+                  weekdays[lt->tm_wday], months[lt->tm_mon], lt->tm_mday,
+                  lt->tm_year + 1900, lt->tm_hour, lt->tm_min, lt->tm_sec,
+                  plus, minswest / 60, minswest % 60);
+
+       return buf;
+}
diff --git a/modules/m_topic.c b/modules/m_topic.c
new file mode 100644 (file)
index 0000000..0541cad
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_topic.c: Sets a channel topic.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_topic.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "s_conf.h"
+#include "s_serv.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "packet.h"
+
+static int m_topic(struct Client *, struct Client *, int, const char **);
+static int ms_topic(struct Client *, struct Client *, int, const char **);
+
+struct Message topic_msgtab = {
+       "TOPIC", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_topic, 2}, {m_topic, 2}, {ms_topic, 5}, mg_ignore, {m_topic, 2}}
+};
+
+mapi_clist_av1 topic_clist[] = { &topic_msgtab, NULL };
+DECLARE_MODULE_AV1(topic, NULL, NULL, topic_clist, NULL, NULL, "$Revision: 254 $");
+
+/*
+ * m_topic
+ *      parv[0] = sender prefix
+ *      parv[1] = channel name
+ *     parv[2] = new topic, if setting topic
+ */
+static int
+m_topic(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Channel *chptr = NULL;
+       struct membership *msptr;
+       char *p = NULL;
+
+       if((p = strchr(parv[1], ',')))
+               *p = '\0';
+
+       if(MyClient(source_p) && !IsFloodDone(source_p))
+               flood_endgrace(source_p);
+
+       if(!IsChannelName(parv[1]))
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
+                                  form_str(ERR_NOSUCHCHANNEL), parv[1]);
+               return 0;
+       }
+
+       chptr = find_channel(parv[1]);
+
+       if(chptr == NULL)
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
+                               form_str(ERR_NOSUCHCHANNEL), parv[1]);
+               return 0;
+       }
+
+       /* setting topic */
+       if(parc > 2)
+       {
+               msptr = find_channel_membership(chptr, source_p);
+
+               if(msptr == NULL)
+               {
+                       sendto_one_numeric(source_p, ERR_NOTONCHANNEL,
+                                       form_str(ERR_NOTONCHANNEL), parv[1]);
+                       return 0;
+               }
+
+               if((chptr->mode.mode & MODE_TOPICLIMIT) == 0 || is_chanop(msptr))
+               {
+                       char topic_info[USERHOST_REPLYLEN];
+                       ircsprintf(topic_info, "%s!%s@%s",
+                                       source_p->name, source_p->username, source_p->host);
+                       set_channel_topic(chptr, parv[2], topic_info, CurrentTime);
+
+                       sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
+                                       ":%s TOPIC %s :%s",
+                                       use_id(source_p), chptr->chname,
+                                       chptr->topic == NULL ? "" : chptr->topic);
+                       sendto_server(client_p, chptr, NOCAPS, CAP_TS6,
+                                       ":%s TOPIC %s :%s",
+                                       source_p->name, chptr->chname,
+                                       chptr->topic == NULL ? "" : chptr->topic);
+                       sendto_channel_local(ALL_MEMBERS,
+                                       chptr, ":%s!%s@%s TOPIC %s :%s",
+                                       source_p->name, source_p->username,
+                                       source_p->host, chptr->chname,
+                                       chptr->topic == NULL ? "" : chptr->topic);
+               }
+               else
+                       sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
+                                       me.name, source_p->name, parv[1]);
+       }
+       else if(MyClient(source_p))
+       {
+               if(!IsMember(source_p, chptr) && SecretChannel(chptr))
+               {
+                       sendto_one_numeric(source_p, ERR_NOTONCHANNEL,
+                                       form_str(ERR_NOTONCHANNEL), parv[1]);
+                       return 0;
+               }
+               if(chptr->topic == NULL)
+                       sendto_one(source_p, form_str(RPL_NOTOPIC),
+                                       me.name, source_p->name, parv[1]);
+               else
+               {
+                       sendto_one(source_p, form_str(RPL_TOPIC),
+                                       me.name, source_p->name, chptr->chname, chptr->topic);
+
+                       sendto_one(source_p, form_str(RPL_TOPICWHOTIME),
+                                       me.name, source_p->name, chptr->chname,
+                                       chptr->topic_info, chptr->topic_time);
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * ms_topic
+ *      parv[0] = sender prefix
+ *      parv[1] = channel name
+ *     parv[2] = topic_info
+ *     parv[3] = topic_info time
+ *     parv[4] = new channel topic
+ *
+ * Let servers always set a topic
+ */
+static int
+ms_topic(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Channel *chptr = NULL;
+
+       if(IsChannelName(parv[1]))
+       {
+               if((chptr = find_channel(parv[1])) == NULL)
+                       return 0;
+
+               set_channel_topic(chptr, parv[4], parv[2], atoi(parv[3]));
+
+               sendto_channel_local(ALL_MEMBERS, chptr, ":%s TOPIC %s :%s",
+                                    source_p->name, parv[1], 
+                                    chptr->topic == NULL ? "" : chptr->topic);
+       }
+
+       return 0;
+}
diff --git a/modules/m_trace.c b/modules/m_trace.c
new file mode 100644 (file)
index 0000000..27ee58c
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_trace.c: Traces a path to a client/server.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_trace.c 609 2006-01-28 21:44:33Z jilles $
+ */
+
+#include "stdinc.h"
+#include "class.h"
+#include "hook.h"
+#include "client.h"
+#include "hash.h"
+#include "common.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "commio.h"
+#include "s_serv.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+
+static int m_trace(struct Client *, struct Client *, int, const char **);
+
+static void trace_spy(struct Client *, struct Client *);
+
+struct Message trace_msgtab = {
+       "TRACE", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_trace, 0}, {m_trace, 0}, mg_ignore, mg_ignore, {m_trace, 0}}
+};
+
+int doing_trace_hook;
+
+mapi_clist_av1 trace_clist[] = { &trace_msgtab, NULL };
+mapi_hlist_av1 trace_hlist[] = {
+       { "doing_trace",        &doing_trace_hook },
+       { NULL, NULL }
+};
+DECLARE_MODULE_AV1(trace, NULL, NULL, trace_clist, trace_hlist, NULL, "$Revision: 609 $");
+
+static void count_downlinks(struct Client *server_p, int *pservcount, int *pusercount);
+static int report_this_status(struct Client *source_p, struct Client *target_p, int dow);
+
+/*
+ * m_trace
+ *      parv[0] = sender prefix
+ *      parv[1] = servername
+ */
+static int
+m_trace(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p = NULL;
+       struct Class *cltmp;
+       const char *tname;
+       int doall = 0;
+       int cnt = 0, wilds, dow;
+       dlink_node *ptr;
+
+       if(parc > 1)
+       {
+               tname = parv[1];
+
+               if(parc > 2)
+               {
+                       if(hunt_server(client_p, source_p, ":%s TRACE %s :%s", 2, parc, parv) !=
+                                       HUNTED_ISME)
+                               return 0;
+               }
+       }
+       else
+               tname = me.name;
+
+       /* if we have 3 parameters, then the command is directed at us.  So
+        * we shouldnt be forwarding it anywhere.
+        */
+       if(parc < 3)
+       {
+               switch (hunt_server(client_p, source_p, ":%s TRACE :%s", 1, parc, parv))
+               {
+               case HUNTED_PASS:       /* note: gets here only if parv[1] exists */
+               {
+                       struct Client *ac2ptr;
+
+                       if(MyClient(source_p))
+                               ac2ptr = find_named_client(tname);
+                       else
+                               ac2ptr = find_client(tname);
+
+                       if(ac2ptr == NULL)
+                       {
+                               DLINK_FOREACH(ptr, global_client_list.head)
+                               {
+                                       ac2ptr = ptr->data;
+
+                                       if(match(tname, ac2ptr->name) || match(ac2ptr->name, tname))
+                                               break;
+                                       else
+                                               ac2ptr = NULL;
+                               }
+                       }
+
+                       /* giving this out with flattened links defeats the
+                        * object --fl
+                        */
+                       if(IsOper(source_p) || IsExemptShide(source_p) ||
+                          !ConfigServerHide.flatten_links)
+                               sendto_one_numeric(source_p, RPL_TRACELINK, 
+                                                  form_str(RPL_TRACELINK),
+                                                  ircd_version, 
+                                                  ac2ptr ? ac2ptr->name : tname,
+                                                  ac2ptr ? ac2ptr->from->name : "EEK!");
+
+                       return 0;
+               }
+
+               case HUNTED_ISME:
+                       break;
+
+               default:
+                       return 0;
+               }
+       }
+
+       if(match(tname, me.name))
+       {
+               doall = 1;
+       }
+       /* if theyre tracing our SID, we need to move tname to our name so
+        * we dont give the sid in ENDOFTRACE
+        */
+       else if(!MyClient(source_p) && !strcmp(tname, me.id))
+       {
+               doall = 1;
+               tname = me.name;
+       }
+
+       wilds = strchr(tname, '*') || strchr(tname, '?');
+       dow = wilds || doall;
+
+       /* specific trace */
+       if(dow == 0)
+       {
+               if(MyClient(source_p) || parc > 2)
+                       target_p = find_named_person(tname);
+               else
+                       target_p = find_person(tname);
+
+               /* tname could be pointing to an ID at this point, so reset
+                * it to target_p->name if we have a target --fl
+                */
+               if(target_p != NULL)
+               {
+                       report_this_status(source_p, target_p, 0);
+                       tname = target_p->name;
+               }
+
+               trace_spy(source_p, target_p);
+
+               sendto_one_numeric(source_p, RPL_ENDOFTRACE, 
+                                  form_str(RPL_ENDOFTRACE), tname);
+               return 0;
+       }
+
+       trace_spy(source_p, NULL);
+
+       /* give non-opers a limited trace output of themselves (if local), 
+        * opers and servers (if no shide) --fl
+        */
+       if(!IsOper(source_p))
+       {
+               if(MyClient(source_p))
+               {
+                       if(doall || (wilds && match(tname, source_p->name)))
+                               report_this_status(source_p, source_p, 0);
+               }
+
+               DLINK_FOREACH(ptr, local_oper_list.head)
+               {
+                       target_p = ptr->data;
+
+                       if(!doall && wilds && (match(tname, target_p->name) == 0))
+                               continue;
+
+                       report_this_status(source_p, target_p, 0);
+               }
+
+               if (IsExemptShide(source_p) || !ConfigServerHide.flatten_links)
+               {
+                       DLINK_FOREACH(ptr, serv_list.head)
+                       {
+                               target_p = ptr->data;
+
+                               if(!doall && wilds && !match(tname, target_p->name))
+                                       continue;
+
+                               report_this_status(source_p, target_p, 0);
+                       }
+               }
+
+               sendto_one_numeric(source_p, RPL_ENDOFTRACE, 
+                                  form_str(RPL_ENDOFTRACE), tname);
+               return 0;
+       }
+
+       /* source_p is opered */
+
+       /* report all direct connections */
+       DLINK_FOREACH(ptr, lclient_list.head)
+       {
+               target_p = ptr->data;
+
+               /* dont show invisible users to remote opers */
+               if(IsInvisible(target_p) && dow && !MyConnect(source_p) && !IsOper(target_p))
+                       continue;
+
+               if(!doall && wilds && !match(tname, target_p->name))
+                       continue;
+
+               cnt = report_this_status(source_p, target_p, dow);
+       }
+
+       DLINK_FOREACH(ptr, serv_list.head)
+       {
+               target_p = ptr->data;
+
+               if(!doall && wilds && !match(tname, target_p->name))
+                       continue;
+
+               cnt = report_this_status(source_p, target_p, dow);
+       }
+
+       if(MyConnect(source_p))
+       {
+               DLINK_FOREACH(ptr, unknown_list.head)
+               {
+                       target_p = ptr->data;
+
+                       if(!doall && wilds && !match(tname, target_p->name))
+                               continue;
+
+                       cnt = report_this_status(source_p, target_p, dow);
+               }
+       }
+
+       if(!cnt)
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHSERVER, form_str(ERR_NOSUCHSERVER),
+                                       tname);
+
+               /* let the user have some idea that its at the end of the
+                * trace
+                */
+               sendto_one_numeric(source_p, RPL_ENDOFTRACE, 
+                                  form_str(RPL_ENDOFTRACE), tname);
+               return 0;
+       }
+
+       if(doall)
+       {
+               DLINK_FOREACH(ptr, class_list.head)
+               {
+                       cltmp = ptr->data;
+
+                       if(CurrUsers(cltmp) > 0)
+                               sendto_one_numeric(source_p, RPL_TRACECLASS,
+                                                  form_str(RPL_TRACECLASS), 
+                                                  ClassName(cltmp), CurrUsers(cltmp));
+               }
+       }
+
+       sendto_one_numeric(source_p, RPL_ENDOFTRACE, form_str(RPL_ENDOFTRACE), tname);
+
+       return 0;
+}
+
+/*
+ * count_downlinks
+ *
+ * inputs      - pointer to server to count
+ *             - pointers to server and user count
+ * output      - NONE
+ * side effects - server and user counts are added to given values
+ */
+static void
+count_downlinks(struct Client *server_p, int *pservcount, int *pusercount)
+{
+       dlink_node *ptr;
+
+       (*pservcount)++;
+       *pusercount += dlink_list_length(&server_p->serv->users);
+       DLINK_FOREACH(ptr, server_p->serv->servers.head)
+       {
+               count_downlinks(ptr->data, pservcount, pusercount);
+       }
+}
+
+/*
+ * report_this_status
+ *
+ * inputs      - pointer to client to report to
+ *             - pointer to client to report about
+ * output      - counter of number of hits
+ * side effects - NONE
+ */
+static int
+report_this_status(struct Client *source_p, struct Client *target_p,
+                  int dow)
+{
+       const char *name;
+       const char *class_name;
+       char ip[HOSTIPLEN];
+       int cnt = 0;
+
+       /* sanity check - should never happen */
+       if(!MyConnect(target_p))
+               return 0;
+
+       inetntop_sock((struct sockaddr *)&target_p->localClient->ip, ip, sizeof(ip));
+       class_name = get_client_class(target_p);
+
+       if(IsAnyServer(target_p))
+               name = get_server_name(target_p, HIDE_IP);
+       else
+               name = get_client_name(target_p, HIDE_IP);
+
+       switch (target_p->status)
+       {
+       case STAT_CONNECTING:
+               sendto_one_numeric(source_p, RPL_TRACECONNECTING,
+                               form_str(RPL_TRACECONNECTING),
+                               class_name, name);
+               cnt++;
+               break;
+
+       case STAT_HANDSHAKE:
+               sendto_one_numeric(source_p, RPL_TRACEHANDSHAKE,
+                               form_str(RPL_TRACEHANDSHAKE),
+                               class_name, name);
+               cnt++;
+               break;
+
+       case STAT_ME:
+               break;
+
+       case STAT_UNKNOWN:
+               /* added time -Taner */
+               sendto_one_numeric(source_p, RPL_TRACEUNKNOWN,
+                                  form_str(RPL_TRACEUNKNOWN),
+                                  class_name, name, ip,
+                                  CurrentTime - target_p->localClient->firsttime);
+               cnt++;
+               break;
+
+       case STAT_CLIENT:
+               /* Only opers see users if there is a wildcard
+                * but anyone can see all the opers.
+                */
+               if((IsOper(source_p) &&
+                   (MyClient(source_p) || !(dow && IsInvisible(target_p))))
+                  || !dow || IsOper(target_p) || (source_p == target_p))
+               {
+                       if(IsOper(target_p))
+                               sendto_one_numeric(source_p, RPL_TRACEOPERATOR,
+                                                  form_str(RPL_TRACEOPERATOR),
+                                                  class_name, name,
+                                                  show_ip(source_p, target_p) ? ip : "255.255.255.255",
+                                                  CurrentTime - target_p->localClient->lasttime,
+                                                  CurrentTime - target_p->localClient->last);
+
+                       else
+                               sendto_one_numeric(source_p, RPL_TRACEUSER, 
+                                                  form_str(RPL_TRACEUSER),
+                                                  class_name, name,
+                                                  show_ip(source_p, target_p) ? ip : "255.255.255.255",
+                                                  CurrentTime - target_p->localClient->lasttime,
+                                                  CurrentTime - target_p->localClient->last);
+                       cnt++;
+               }
+               break;
+
+       case STAT_SERVER:
+               {
+                       int usercount = 0;
+                       int servcount = 0;
+
+                       count_downlinks(target_p, &servcount, &usercount);
+
+                       sendto_one_numeric(source_p, RPL_TRACESERVER, form_str(RPL_TRACESERVER),
+                                  class_name, servcount, usercount, name,
+                                  *(target_p->serv->by) ? target_p->serv->by : "*", "*",
+                                  me.name, CurrentTime - target_p->localClient->lasttime);
+                       cnt++;
+
+               }
+               break;
+
+       default:                /* ...we actually shouldn't come here... --msa */
+               sendto_one_numeric(source_p, RPL_TRACENEWTYPE, 
+                                  form_str(RPL_TRACENEWTYPE), 
+                                  me.name, source_p->name, name);
+               cnt++;
+               break;
+       }
+
+       return (cnt);
+}
+
+/* trace_spy()
+ *
+ * input        - pointer to client
+ * output       - none
+ * side effects - hook event doing_trace is called
+ */
+static void
+trace_spy(struct Client *source_p, struct Client *target_p)
+{
+       hook_data_client hdata;
+
+       hdata.client = source_p;
+       hdata.target = target_p;
+
+       call_hook(doing_trace_hook, &hdata);
+}
diff --git a/modules/m_unreject.c b/modules/m_unreject.c
new file mode 100644 (file)
index 0000000..7b333e8
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_unreject.c: Removes an ip from the reject cache
+ *
+ *  Copyright (C) 2004 Aaron Sethman <androsyn@ratbox.org>
+ *  Copyright (C) 2004-2005 ircd-ratbox development 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: m_unreject.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "s_conf.h"
+#include "hostmask.h"
+#include "reject.h"
+#include "msg.h"
+#include "modules.h"
+#include "send.h"
+
+static int mo_unreject(struct Client *, struct Client *, int, const char **);
+
+struct Message unreject_msgtab = {
+       "UNREJECT", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_unreject, 2}}
+};
+
+mapi_clist_av1 unreject_clist[] = { &unreject_msgtab, NULL };
+DECLARE_MODULE_AV1(unreject, NULL, NULL, unreject_clist, NULL, NULL, "$Revision: 254 $");
+
+/*
+ * mo_unreject
+ *
+ */
+static int
+mo_unreject(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_ban_time == 0 ||
+          ConfigFileEntry.reject_duration == 0)
+       {
+               sendto_one(source_p, ":%s NOTICE %s :Reject cache is disabled",
+                          me.name, source_p->name);
+               return 0;                       
+       }
+
+       if(!parse_netmask(parv[1], NULL, NULL))
+       {
+               sendto_one(source_p, ":%s NOTICE %s :Unable to parse netmask %s", 
+                          me.name, source_p->name, parv[1]);
+               return 0;
+       }       
+       
+       if(remove_reject(parv[1]))
+               sendto_one(source_p, ":%s NOTICE %s :Removed reject for %s", 
+                          me.name, source_p->name, parv[1]);
+       else
+               sendto_one(source_p, ":%s NOTICE %s :Unable to remove reject for %s",
+                          me.name, source_p->name, parv[1]);
+       return 0;
+}
diff --git a/modules/m_user.c b/modules/m_user.c
new file mode 100644 (file)
index 0000000..c8d710c
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_user.c: Sends username information.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_user.c 1459 2006-05-26 20:50:41Z jilles $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_user.h"
+#include "send.h"
+#include "s_conf.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "sprintf_irc.h"
+#include "blacklist.h"
+
+#define UFLAGS  (FLAGS_INVISIBLE|FLAGS_WALLOP|FLAGS_SERVNOTICE)
+
+static int mr_user(struct Client *, struct Client *, int, const char **);
+
+struct Message user_msgtab = {
+       "USER", 0, 0, 0, MFLG_SLOW,
+       {{mr_user, 5}, mg_reg, mg_ignore, mg_ignore, mg_ignore, mg_reg}
+};
+
+mapi_clist_av1 user_clist[] = { &user_msgtab, NULL };
+DECLARE_MODULE_AV1(user, NULL, NULL, user_clist, NULL, NULL, "$Revision: 1459 $");
+
+static int do_local_user(struct Client *client_p, struct Client *source_p,
+                        const char *username, const char *realname);
+
+/* mr_user()
+ *      parv[1] = username (login name, account)
+ *      parv[2] = client host name (ignored)
+ *      parv[3] = server host name (ignored)
+ *      parv[4] = users gecos
+ */
+static int
+mr_user(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       static char buf[BUFSIZE];
+       char *p;
+
+       if (strlen(client_p->id) == 3)
+       {
+               exit_client(client_p, client_p, client_p, "Mixing client and server protocol");
+               return 0;
+       }
+
+       if((p = strchr(parv[1], '@')))
+               *p = '\0';
+
+       ircsnprintf(buf, sizeof(buf), "%s %s", parv[2], parv[3]);
+       MyFree(source_p->localClient->fullcaps);
+       DupString(source_p->localClient->fullcaps, buf);
+
+       do_local_user(client_p, source_p, parv[1], parv[4]);
+       return 0;
+}
+
+static int
+do_local_user(struct Client *client_p, struct Client *source_p,
+             const char *username, const char *realname)
+{
+       struct User *user;
+
+       s_assert(NULL != source_p);
+       s_assert(source_p->username != username);
+
+       user = make_user(source_p);
+       user->server = me.name;
+
+       if (!(source_p->flags & FLAGS_SENTUSER))
+       {
+               lookup_blacklists(source_p);
+               source_p->flags |= FLAGS_SENTUSER;
+       }
+
+       strlcpy(source_p->info, realname, sizeof(source_p->info));
+
+       if(!IsGotId(source_p))
+       {
+               /* This is in this location for a reason..If there is no identd
+                * and ping cookies are enabled..we need to have a copy of this
+                */
+               strlcpy(source_p->username, username, sizeof(source_p->username));
+       }
+
+       if(source_p->name[0])
+       {
+               /* NICK already received, now I have USER... */
+               return register_local_user(client_p, source_p, username);
+       }
+
+       return 0;
+}
diff --git a/modules/m_userhost.c b/modules/m_userhost.c
new file mode 100644 (file)
index 0000000..c13d2ec
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_userhost.c: Shows a user's host.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_userhost.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_serv.h"
+#include "send.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_conf.h"
+
+static char buf[BUFSIZE];
+
+static int m_userhost(struct Client *, struct Client *, int, const char **);
+
+struct Message userhost_msgtab = {
+       "USERHOST", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_userhost, 2}, mg_ignore, mg_ignore, mg_ignore, {m_userhost, 2}}
+};
+
+mapi_clist_av1 userhost_clist[] = { &userhost_msgtab, NULL };
+DECLARE_MODULE_AV1(userhost, NULL, NULL, userhost_clist, NULL, NULL, "$Revision: 254 $");
+
+/*
+ * m_userhost added by Darren Reed 13/8/91 to aid clients and reduce
+ * the need for complicated requests like WHOIS. It returns user/host
+ * information only (no spurious AWAY labels or channels).
+ */
+static int
+m_userhost(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+       char response[NICKLEN * 2 + USERLEN + HOSTLEN + 30];
+       char *t;
+       int i;                  /* loop counter */
+       int cur_len;
+       int rl;
+
+       cur_len = ircsprintf(buf, form_str(RPL_USERHOST), me.name, parv[0], "");
+       t = buf + cur_len;
+
+       for (i = 1; i <= 5; i++)
+       {
+               if(parc < i + 1)
+                       break;
+
+               if((target_p = find_person(parv[i])) != NULL)
+               {
+                       /*
+                        * Show real IP for USERHOST on yourself.
+                        * This is needed for things like mIRC, which do a server-based
+                        * lookup (USERHOST) to figure out what the clients' local IP
+                        * is.  Useful for things like NAT, and dynamic dial-up users.
+                        */
+                       if(MyClient(target_p) && (target_p == source_p))
+                       {
+                               rl = ircsprintf(response, "%s%s=%c%s@%s ",
+                                               target_p->name,
+                                               IsOper(target_p) ? "*" : "",
+                                               (target_p->user->away) ? '-' : '+',
+                                               target_p->username,
+                                               target_p->sockhost);
+                       }
+                       else
+                       {
+                               rl = ircsprintf(response, "%s%s=%c%s@%s ",
+                                               target_p->name,
+                                               IsOper(target_p) ? "*" : "",
+                                               (target_p->user->away) ? '-' : '+',
+                                               target_p->username, target_p->host);
+                       }
+
+                       if((rl + cur_len) < (BUFSIZE - 10))
+                       {
+                               ircsprintf(t, "%s", response);
+                               t += rl;
+                               cur_len += rl;
+                       }
+                       else
+                               break;
+               }
+       }
+
+       sendto_one(source_p, "%s", buf);
+
+       return 0;
+}
diff --git a/modules/m_users.c b/modules/m_users.c
new file mode 100644 (file)
index 0000000..5c3d9d7
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_users.c: Gives some basic user statistics.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_users.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_serv.h"
+#include "s_conf.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+
+static int m_users(struct Client *, struct Client *, int, const char **);
+
+struct Message users_msgtab = {
+       "USERS", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_users, 0}, {m_users, 0}, mg_ignore, mg_ignore, {m_users, 0}}
+};
+
+mapi_clist_av1 users_clist[] = { &users_msgtab, NULL };
+DECLARE_MODULE_AV1(users, NULL, NULL, users_clist, NULL, NULL, "$Revision: 254 $");
+
+/*
+ * m_users
+ *      parv[0] = sender prefix
+ *      parv[1] = servername
+ */
+static int
+m_users(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       if(hunt_server(client_p, source_p, ":%s USERS :%s", 1, parc, parv) == HUNTED_ISME)
+       {
+               sendto_one_numeric(source_p, RPL_LOCALUSERS,
+                                  form_str(RPL_LOCALUSERS),
+                                  dlink_list_length(&lclient_list), 
+                                  Count.max_loc,
+                                  dlink_list_length(&lclient_list), 
+                                  Count.max_loc);
+
+               sendto_one_numeric(source_p, RPL_GLOBALUSERS, 
+                                  form_str(RPL_GLOBALUSERS),
+                                  Count.total, Count.max_tot,
+                                  Count.total, Count.max_tot);
+       }
+
+       return 0;
+}
diff --git a/modules/m_version.c b/modules/m_version.c
new file mode 100644 (file)
index 0000000..08b918a
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_version.c: Shows ircd version information.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_version.c 1887 2006-08-29 13:42:56Z jilles $
+ */
+
+#include <stdinc.h>
+#include "client.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_conf.h"
+#include "s_serv.h"
+#include "supported.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+
+static char *confopts(struct Client *source_p);
+
+static int m_version(struct Client *, struct Client *, int, const char **);
+static int mo_version(struct Client *, struct Client *, int, const char **);
+
+struct Message version_msgtab = {
+       "VERSION", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_version, 0}, {mo_version, 0}, {mo_version, 0}, mg_ignore, {mo_version, 0}}
+};
+
+mapi_clist_av1 version_clist[] = { &version_msgtab, NULL };
+DECLARE_MODULE_AV1(version, NULL, NULL, version_clist, NULL, NULL, "$Revision: 1887 $");
+
+/*
+ * m_version - VERSION command handler
+ *      parv[0] = sender prefix
+ *      parv[1] = remote server
+ */
+static int
+m_version(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       static time_t last_used = 0L;
+
+       if(parc > 1)
+       {
+               if((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
+               {
+                       /* safe enough to give this on a local connect only */
+                       sendto_one(source_p, form_str(RPL_LOAD2HI),
+                                  me.name, source_p->name, "VERSION");
+                       return 0;
+               }
+               else
+                       last_used = CurrentTime;
+
+               if(hunt_server(client_p, source_p, ":%s VERSION :%s", 1, parc, parv) != HUNTED_ISME)
+                       return 0;
+       }
+
+       sendto_one_numeric(source_p, RPL_VERSION, form_str(RPL_VERSION),
+                          ircd_version, serno,
+                          me.name, confopts(source_p), TS_CURRENT,
+                          ServerInfo.sid);
+
+       show_isupport(source_p);
+
+       return 0;
+}
+
+/*
+ * mo_version - VERSION command handler
+ *      parv[0] = sender prefix
+ *      parv[1] = remote server
+ */
+static int
+mo_version(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       if(hunt_server(client_p, source_p, ":%s VERSION :%s", 1, parc, parv) == HUNTED_ISME)
+       {
+               sendto_one_numeric(source_p, RPL_VERSION, form_str(RPL_VERSION),
+                                  ircd_version, serno, 
+                                  me.name, confopts(source_p), TS_CURRENT,
+                                  ServerInfo.sid);
+               show_isupport(source_p);
+       }
+
+       return 0;
+}
+
+/* confopts()
+ * input  - client pointer
+ * output - ircd.conf option string
+ * side effects - none
+ */
+static char *
+confopts(struct Client *source_p)
+{
+       static char result[15];
+       char *p;
+
+       result[0] = '\0';
+       p = result;
+
+       if(ConfigChannel.use_except)
+               *p++ = 'e';
+
+       if(ConfigFileEntry.glines)
+               *p++ = 'g';
+       *p++ = 'G';
+
+       /* might wanna hide this :P */
+       if(ServerInfo.hub)
+               *p++ = 'H';
+
+       if(ConfigChannel.use_invex)
+               *p++ = 'I';
+
+       if(ConfigChannel.use_knock)
+               *p++ = 'K';
+
+       *p++ = 'M';
+       *p++ = 'p';
+
+       if(opers_see_all_users || ConfigFileEntry.operspy_dont_care_user_info)
+               *p++ = 'S';
+#ifdef IGNORE_BOGUS_TS
+       *p++ = 'T';
+#endif
+
+#ifdef HAVE_LIBZ
+       *p++ = 'Z';
+#endif
+
+#ifdef IPV6
+       *p++ = '6';
+#endif
+
+       *p = '\0';
+
+       return result;
+}
diff --git a/modules/m_wallops.c b/modules/m_wallops.c
new file mode 100644 (file)
index 0000000..3301d25
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_wallops.c: Sends a message to all operators.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_wallops.c 1377 2006-05-20 13:48:37Z jilles $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "ircd.h"
+#include "irc_string.h"
+#include "numeric.h"
+#include "send.h"
+#include "s_user.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_serv.h"
+
+static int mo_operwall(struct Client *, struct Client *, int, const char **);
+static int ms_operwall(struct Client *, struct Client *, int, const char **);
+static int ms_wallops(struct Client *, struct Client *, int, const char **);
+
+struct Message wallops_msgtab = {
+       "WALLOPS", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, {ms_wallops, 2}, {ms_wallops, 2}, mg_ignore, {ms_wallops, 2}}
+};
+struct Message operwall_msgtab = {
+       "OPERWALL", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, {ms_operwall, 2}, mg_ignore, mg_ignore, {mo_operwall, 2}}
+};
+
+mapi_clist_av1 wallops_clist[] = { &wallops_msgtab, &operwall_msgtab, NULL };
+DECLARE_MODULE_AV1(wallops, NULL, NULL, wallops_clist, NULL, NULL, "$Revision: 1377 $");
+
+/*
+ * mo_operwall (write to *all* opers currently online)
+ *      parv[1] = message text
+ */
+static int
+mo_operwall(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       if(!IsOperOperwall(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS),
+                          me.name, source_p->name, "operwall");
+               return 0;
+       }
+
+       sendto_wallops_flags(UMODE_OPERWALL, source_p, "OPERWALL - %s", parv[1]);
+       sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s OPERWALL :%s", 
+                     use_id(source_p), parv[1]);
+       sendto_server(client_p, NULL, NOCAPS, CAP_TS6, ":%s OPERWALL :%s", 
+                     source_p->name, parv[1]);
+
+       return 0;
+}
+
+/*
+ * ms_operwall - OPERWALL message handler
+ *  (write to *all* local opers currently online)
+ *      parv[0] = sender prefix
+ *      parv[1] = message text
+ */
+static int
+ms_operwall(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s OPERWALL :%s",
+                     use_id(source_p), parv[1]);
+       sendto_server(client_p, NULL, NOCAPS, CAP_TS6, ":%s OPERWALL :%s",
+                     source_p->name, parv[1]);
+       sendto_wallops_flags(UMODE_OPERWALL, source_p, "OPERWALL - %s", parv[1]);
+
+       return 0;
+}
+
+/*
+ * ms_wallops (write to *all* opers currently online)
+ *      parv[1] = message text
+ */
+static int
+ms_wallops(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       const char *prefix = "";
+
+       if (IsPerson(source_p))
+       {
+               if (!strncmp(parv[1], "OPERWALL - ", 11) ||
+                               !strncmp(parv[1], "LOCOPS - ", 9) ||
+                               !strncmp(parv[1], "SLOCOPS - ", 10))
+                       prefix = "WALLOPS - ";
+       }
+
+       sendto_wallops_flags(UMODE_WALLOP, source_p, "%s%s", prefix, parv[1]);
+
+       sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s WALLOPS :%s", 
+                     use_id(source_p), parv[1]);
+       sendto_server(client_p, NULL, NOCAPS, CAP_TS6, ":%s WALLOPS :%s", 
+                     source_p->name, parv[1]);
+
+       return 0;
+}
+
diff --git a/modules/m_who.c b/modules/m_who.c
new file mode 100644 (file)
index 0000000..b62d301
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_who.c: Shows who is on a channel.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_who.c 1853 2006-08-24 18:30:52Z jilles $
+ */
+#include "stdinc.h"
+#include "tools.h"
+#include "common.h"
+#include "client.h"
+#include "channel.h"
+#include "hash.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_serv.h"
+#include "send.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "s_conf.h"
+#include "s_log.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "packet.h"
+#include "s_newconf.h"
+
+static int m_who(struct Client *, struct Client *, int, const char **);
+
+struct Message who_msgtab = {
+       "WHO", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_who, 2}, mg_ignore, mg_ignore, mg_ignore, {m_who, 2}}
+};
+
+mapi_clist_av1 who_clist[] = { &who_msgtab, NULL };
+DECLARE_MODULE_AV1(who, NULL, NULL, who_clist, NULL, NULL, "$Revision: 1853 $");
+
+static void do_who_on_channel(struct Client *source_p, struct Channel *chptr,
+                             int server_oper, int member);
+
+static void who_global(struct Client *source_p, const char *mask, int server_oper, int operspy);
+
+static void do_who(struct Client *source_p,
+                  struct Client *target_p, const char *chname, const char *op_flags);
+
+
+/*
+** m_who
+**      parv[0] = sender prefix
+**      parv[1] = nickname mask list
+**      parv[2] = additional selection flag, only 'o' for now.
+*/
+static int
+m_who(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       static time_t last_used = 0;
+       struct Client *target_p;
+       struct membership *msptr;
+       char *mask;
+       dlink_node *lp;
+       struct Channel *chptr = NULL;
+       int server_oper = parc > 2 ? (*parv[2] == 'o') : 0;     /* Show OPERS only */
+       int member;
+       int operspy = 0;
+
+       mask = LOCAL_COPY(parv[1]);
+
+       collapse(mask);
+
+       /* '/who *' */
+       if((*(mask + 1) == '\0') && (*mask == '*'))
+       {
+               if(source_p->user == NULL)
+                       return 0;
+
+               if((lp = source_p->user->channel.head) != NULL)
+               {
+                       msptr = lp->data;
+                       do_who_on_channel(source_p, msptr->chptr, server_oper, YES);
+               }
+
+               sendto_one(source_p, form_str(RPL_ENDOFWHO),
+                          me.name, source_p->name, "*");
+               return 0;
+       }
+
+       if(IsOperSpy(source_p) && *mask == '!')
+       {
+               mask++;
+               operspy = 1;
+
+               if(EmptyString(mask))
+               {
+                       sendto_one(source_p, form_str(RPL_ENDOFWHO),
+                                       me.name, source_p->name, parv[1]);
+                       return 0;
+               }
+       }
+
+       /* '/who #some_channel' */
+       if(IsChannelName(mask))
+       {
+               /* List all users on a given channel */
+               chptr = find_channel(mask);
+               if(chptr != NULL)
+               {
+                       if(operspy)
+                               report_operspy(source_p, "WHO", chptr->chname);
+
+                       if(IsMember(source_p, chptr) || operspy)
+                               do_who_on_channel(source_p, chptr, server_oper, YES);
+                       else if(!SecretChannel(chptr))
+                               do_who_on_channel(source_p, chptr, server_oper, NO);
+               }
+               sendto_one(source_p, form_str(RPL_ENDOFWHO),
+                          me.name, source_p->name, mask);
+               return 0;
+       }
+
+       /* '/who nick' */
+
+       if(((target_p = find_named_person(mask)) != NULL) &&
+          (!server_oper || IsOper(target_p)))
+       {
+               int isinvis = 0;
+
+               isinvis = IsInvisible(target_p);
+               DLINK_FOREACH(lp, target_p->user->channel.head)
+               {
+                       msptr = lp->data;
+                       chptr = msptr->chptr;
+
+                       member = IsMember(source_p, chptr);
+
+                       if(isinvis && !member)
+                               continue;
+
+                       if(member || (!isinvis && PubChannel(chptr)))
+                               break;
+               }
+
+               /* if we stopped midlist, lp->data is the membership for
+                * target_p of chptr
+                */
+               if(lp != NULL)
+                       do_who(source_p, target_p, chptr->chname,
+                              find_channel_status(lp->data, IsCapable(source_p, CLICAP_MULTI_PREFIX)));
+               else
+                       do_who(source_p, target_p, NULL, "");
+
+               sendto_one(source_p, form_str(RPL_ENDOFWHO), 
+                          me.name, source_p->name, mask);
+               return 0;
+       }
+
+       if(!IsFloodDone(source_p))
+               flood_endgrace(source_p);
+
+       /* it has to be a global who at this point, limit it */
+       if(!IsOper(source_p))
+       {
+               if((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
+               {
+                       sendto_one(source_p, form_str(RPL_LOAD2HI),
+                                       me.name, source_p->name, "WHO");
+                       sendto_one(source_p, form_str(RPL_ENDOFWHO),
+                                  me.name, source_p->name, "*");
+                       return 0;
+               }
+               else
+                       last_used = CurrentTime;
+       }
+
+       /* Note: operspy_dont_care_user_info does not apply to
+        * who on channels */
+       if(IsOperSpy(source_p) && ConfigFileEntry.operspy_dont_care_user_info)
+               operspy = 1;
+
+       /* '/who 0' for a global list.  this forces clients to actually
+        * request a full list.  I presume its because of too many typos
+        * with "/who" ;) --fl
+        */
+       if((*(mask + 1) == '\0') && (*mask == '0'))
+               who_global(source_p, NULL, server_oper, 0);
+       else
+               who_global(source_p, mask, server_oper, operspy);
+
+       sendto_one(source_p, form_str(RPL_ENDOFWHO),
+                  me.name, source_p->name, mask);
+
+       return 0;
+}
+
+/* who_common_channel
+ * inputs      - pointer to client requesting who
+ *             - pointer to channel member chain.
+ *             - char * mask to match
+ *             - int if oper on a server or not
+ *             - pointer to int maxmatches
+ * output      - NONE
+ * side effects - lists matching invisible clients on specified channel,
+ *               marks matched clients.
+ */
+static void
+who_common_channel(struct Client *source_p, struct Channel *chptr,
+                  const char *mask, int server_oper, int *maxmatches)
+{
+       struct membership *msptr;
+       struct Client *target_p;
+       dlink_node *ptr;
+
+       DLINK_FOREACH(ptr, chptr->members.head)
+       {
+               msptr = ptr->data;
+               target_p = msptr->client_p;
+
+               if(!IsInvisible(target_p) || IsMarked(target_p))
+                       continue;
+
+               if(server_oper && !IsOper(target_p))
+                       continue;
+
+               SetMark(target_p);
+
+               if(*maxmatches > 0)
+               {
+                       if((mask == NULL) ||
+                                       match(mask, target_p->name) || match(mask, target_p->username) ||
+                                       match(mask, target_p->host) || match(mask, target_p->user->server) ||
+                                       (IsOper(source_p) && match(mask, target_p->orighost)) ||
+                                       match(mask, target_p->info))
+                       {
+                               do_who(source_p, target_p, NULL, "");
+                               --(*maxmatches);
+                       }
+               }
+       }
+}
+
+/*
+ * who_global
+ *
+ * inputs      - pointer to client requesting who
+ *             - char * mask to match
+ *             - int if oper on a server or not
+ * output      - NONE
+ * side effects - do a global scan of all clients looking for match
+ *               this is slightly expensive on EFnet ...
+ *               marks assumed cleared for all clients initially
+ *               and will be left cleared on return
+ */
+static void
+who_global(struct Client *source_p, const char *mask, int server_oper, int operspy)
+{
+       struct membership *msptr;
+       struct Client *target_p;
+       dlink_node *lp, *ptr;
+       int maxmatches = 500;
+
+       /* first, list all matching INvisible clients on common channels
+        * if this is not an operspy who
+        */
+       if(!operspy)
+       {
+               DLINK_FOREACH(lp, source_p->user->channel.head)
+               {
+                       msptr = lp->data;
+                       who_common_channel(source_p, msptr->chptr, mask, server_oper, &maxmatches);
+               }
+       }
+       else if (!ConfigFileEntry.operspy_dont_care_user_info)
+               report_operspy(source_p, "WHO", mask);
+
+       /* second, list all matching visible clients and clear all marks
+        * on invisible clients
+        * if this is an operspy who, list all matching clients, no need
+        * to clear marks
+        */
+       DLINK_FOREACH(ptr, global_client_list.head)
+       {
+               target_p = ptr->data;
+               if(!IsPerson(target_p))
+                       continue;
+
+               if(IsInvisible(target_p) && !operspy)
+               {
+                       ClearMark(target_p);
+                       continue;
+               }
+
+               if(server_oper && !IsOper(target_p))
+                       continue;
+
+               if(maxmatches > 0)
+               {
+                       if(!mask ||
+                                       match(mask, target_p->name) || match(mask, target_p->username) ||
+                                       match(mask, target_p->host) || match(mask, target_p->user->server) ||
+                                       (IsOper(source_p) && match(mask, target_p->orighost)) ||
+                                       match(mask, target_p->info))
+                       {
+                               do_who(source_p, target_p, NULL, "");
+                               --maxmatches;
+                       }
+               }
+       }
+
+       if (maxmatches <= 0)
+               sendto_one(source_p,
+                       form_str(ERR_TOOMANYMATCHES),
+                       me.name, source_p->name, "WHO");
+}
+
+/*
+ * do_who_on_channel
+ *
+ * inputs      - pointer to client requesting who
+ *             - pointer to channel to do who on
+ *             - The "real name" of this channel
+ *             - int if source_p is a server oper or not
+ *             - int if client is member or not
+ * output      - NONE
+ * side effects - do a who on given channel
+ */
+static void
+do_who_on_channel(struct Client *source_p, struct Channel *chptr,
+                 int server_oper, int member)
+{
+       struct Client *target_p;
+       struct membership *msptr;
+       dlink_node *ptr;
+       int combine = IsCapable(source_p, CLICAP_MULTI_PREFIX);
+
+       DLINK_FOREACH(ptr, chptr->members.head)
+       {
+               msptr = ptr->data;
+               target_p = msptr->client_p;
+
+               if(server_oper && !IsOper(target_p))
+                       continue;
+
+               if(member || !IsInvisible(target_p))
+                       do_who(source_p, target_p, chptr->chname,
+                              find_channel_status(msptr, combine));
+       }
+}
+
+/*
+ * do_who
+ *
+ * inputs      - pointer to client requesting who
+ *             - pointer to client to do who on
+ *             - The reported name
+ *             - channel flags
+ * output      - NONE
+ * side effects - do a who on given person
+ */
+
+static void
+do_who(struct Client *source_p, struct Client *target_p, const char *chname, const char *op_flags)
+{
+       char status[5];
+
+       ircsprintf(status, "%c%s%s",
+                  target_p->user->away ? 'G' : 'H', IsOper(target_p) ? "*" : "", op_flags);
+
+       sendto_one(source_p, form_str(RPL_WHOREPLY), me.name, source_p->name,
+                  (chname) ? (chname) : "*",
+                  target_p->username,
+                  target_p->host, target_p->user->server, target_p->name,
+                  status, 
+                  ConfigServerHide.flatten_links ? 0 : target_p->hopcount, 
+                  target_p->info);
+}
diff --git a/modules/m_whois.c b/modules/m_whois.c
new file mode 100644 (file)
index 0000000..ef60a55
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_whois.c: Shows who a user is.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_whois.c 1879 2006-08-27 21:18:43Z jilles $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "common.h"
+#include "client.h"
+#include "hash.h"
+#include "channel.h"
+#include "hash.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_conf.h"
+#include "s_serv.h"
+#include "send.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "s_conf.h"
+#include "s_log.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "hook.h"
+#include "s_newconf.h"
+
+static void do_whois(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
+static void single_whois(struct Client *source_p, struct Client *target_p, int operspy);
+
+static int m_whois(struct Client *, struct Client *, int, const char **);
+static int ms_whois(struct Client *, struct Client *, int, const char **);
+
+struct Message whois_msgtab = {
+       "WHOIS", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_whois, 2}, {ms_whois, 2}, mg_ignore, mg_ignore, {m_whois, 2}}
+};
+
+int doing_whois_hook;
+int doing_whois_global_hook;
+
+mapi_clist_av1 whois_clist[] = { &whois_msgtab, NULL };
+mapi_hlist_av1 whois_hlist[] = {
+       { "doing_whois",        &doing_whois_hook },
+       { "doing_whois_global", &doing_whois_global_hook },
+       { NULL, NULL }
+};
+
+DECLARE_MODULE_AV1(whois, NULL, NULL, whois_clist, whois_hlist, NULL, "$Revision: 1879 $");
+
+/*
+ * m_whois
+ *      parv[0] = sender prefix
+ *      parv[1] = nickname masklist
+ */
+static int
+m_whois(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       static time_t last_used = 0;
+
+       if(parc > 2)
+       {
+               if(EmptyString(parv[2]))
+               {
+                       sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN),
+                                       me.name, source_p->name);
+                       return 0;
+               }
+
+               if(!IsOper(source_p))
+               {
+                       /* seeing as this is going across servers, we should limit it */
+                       if((last_used + ConfigFileEntry.pace_wait_simple) > CurrentTime)
+                       {
+                               sendto_one(source_p, form_str(RPL_LOAD2HI),
+                                          me.name, source_p->name, "WHOIS");
+                               sendto_one_numeric(source_p, RPL_ENDOFWHOIS, 
+                                                  form_str(RPL_ENDOFWHOIS), parv[1]);
+                               return 0;
+                       }
+                       else
+                               last_used = CurrentTime;
+               }
+
+               if(hunt_server(client_p, source_p, ":%s WHOIS %s :%s", 1, parc, parv) !=
+                  HUNTED_ISME)
+                       return 0;
+
+               parv[1] = parv[2];
+
+       }
+       do_whois(client_p, source_p, parc, parv);
+
+       return 0;
+}
+
+/*
+ * ms_whois
+ *      parv[0] = sender prefix
+ *      parv[1] = server to reply
+ *      parv[2] = nickname to whois
+ */
+static int
+ms_whois(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+
+       /* note: early versions of ratbox allowed users to issue a remote
+        * whois with a blank parv[2], so we cannot treat it as a protocol
+        * violation. --anfl
+        */
+       if(parc < 3 || EmptyString(parv[2]))
+       {
+               sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN),
+                               me.name, source_p->name);
+               return 0;
+       }
+
+       /* check if parv[1] exists */
+       if((target_p = find_client(parv[1])) == NULL)
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHSERVER,
+                                  form_str(ERR_NOSUCHSERVER), 
+                                  IsDigit(parv[1][0]) ? "*" : parv[1]);
+               return 0;
+       }
+
+       /* if parv[1] isnt my client, or me, someone else is supposed
+        * to be handling the request.. so send it to them 
+        */
+       if(!MyClient(target_p) && !IsMe(target_p))
+       {
+               sendto_one(target_p, ":%s WHOIS %s :%s", 
+                          get_id(source_p, target_p), 
+                          get_id(target_p, target_p), parv[2]);
+               return 0;
+       }
+
+       /* ok, the target is either us, or a client on our server, so perform the whois
+        * but first, parv[1] == server to perform the whois on, parv[2] == person
+        * to whois, so make parv[1] = parv[2] so do_whois is ok -- fl_
+        */
+       parv[1] = parv[2];
+       do_whois(client_p, source_p, parc, parv);
+
+       return 0;
+}
+
+/* do_whois
+ *
+ * inputs      - pointer to 
+ * output      - 
+ * side effects -
+ */
+static void
+do_whois(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+       char *nick;
+       char *p = NULL;
+       int operspy = 0;
+
+       nick = LOCAL_COPY(parv[1]);
+       if((p = strchr(nick, ',')))
+               *p = '\0';
+
+       if(IsOperSpy(source_p) && *nick == '!')
+       {
+               operspy = 1;
+               nick++;
+       }
+
+       target_p = find_named_person(nick);
+
+       if(target_p != NULL)
+       {
+               if(operspy)
+               {
+                       char buffer[BUFSIZE];
+
+                       snprintf(buffer, sizeof(buffer), "%s!%s@%s %s",
+                               target_p->name, target_p->username,
+                               target_p->host, target_p->user->server);
+                       report_operspy(source_p, "WHOIS", buffer);
+               }
+
+               single_whois(source_p, target_p, operspy);
+       }
+       else
+               sendto_one_numeric(source_p, ERR_NOSUCHNICK,
+                                  form_str(ERR_NOSUCHNICK), 
+                                  IsDigit(*nick) ? "*" : nick);
+
+       sendto_one_numeric(source_p, RPL_ENDOFWHOIS, 
+                          form_str(RPL_ENDOFWHOIS), parv[1]);
+       return;
+}
+
+/*
+ * single_whois()
+ *
+ * Inputs      - source_p client to report to
+ *             - target_p client to report on
+ * Output      - if found return 1
+ * Side Effects        - do a single whois on given client
+ *               writing results to source_p
+ */
+static void
+single_whois(struct Client *source_p, struct Client *target_p, int operspy)
+{
+       char buf[BUFSIZE];
+       dlink_node *ptr;
+       struct Client *a2client_p;
+       struct membership *msptr;
+       struct Channel *chptr;
+       int cur_len = 0;
+       int mlen;
+       char *t;
+       int tlen;
+       hook_data_client hdata;
+       char *name;
+       char quest[] = "?";
+       int visible;
+       int extra_space = 0;
+
+       if(target_p->name[0] == '\0')
+               name = quest;
+       else
+               name = target_p->name;
+
+       if(target_p->user == NULL)
+       {
+               s_assert(0);
+               return;
+       }
+
+       a2client_p = target_p->servptr;
+
+       sendto_one_numeric(source_p, RPL_WHOISUSER, form_str(RPL_WHOISUSER),
+                          target_p->name, target_p->username, 
+                          target_p->host, target_p->info);
+
+       cur_len = mlen = ircsprintf(buf, form_str(RPL_WHOISCHANNELS), 
+                                   get_id(&me, source_p), get_id(source_p, source_p), 
+                                   target_p->name);
+
+       /* Make sure it won't overflow when sending it to the client
+        * in full names; note that serverhiding may require more space
+        * for a different server name (not done here) -- jilles
+        */
+       if (!MyConnect(source_p))
+       {
+               extra_space = strlen(source_p->name) - 9;
+               if (extra_space < 0)
+                       extra_space = 0;
+               extra_space += strlen(me.name) - 2; /* make sure >= 0 */
+               cur_len += extra_space;
+       }
+
+       t = buf + mlen;
+
+       DLINK_FOREACH(ptr, target_p->user->channel.head)
+       {
+               msptr = ptr->data;
+               chptr = msptr->chptr;
+
+               visible = IsService(target_p) ? IsMember(source_p, chptr) : ShowChannel(source_p, chptr);
+
+               if(visible || operspy)
+               {
+                       if((cur_len + strlen(chptr->chname) + 3) > (BUFSIZE - 5))
+                       {
+                               sendto_one(source_p, "%s", buf);
+                               cur_len = mlen + extra_space;
+                               t = buf + mlen;
+                       }
+
+                       tlen = ircsprintf(t, "%s%s%s ",
+                                       visible ? "" : "!",
+                                       find_channel_status(msptr, 1),
+                                       chptr->chname);
+                       t += tlen;
+                       cur_len += tlen;
+               }
+       }
+
+       if(cur_len > mlen + extra_space)
+               sendto_one(source_p, "%s", buf);
+
+       sendto_one_numeric(source_p, RPL_WHOISSERVER, form_str(RPL_WHOISSERVER),
+                          target_p->name, target_p->user->server,
+                          a2client_p ? a2client_p->info : "*Not On This Net*");
+
+       if(target_p->user->away)
+               sendto_one_numeric(source_p, RPL_AWAY, form_str(RPL_AWAY),
+                                  target_p->name, target_p->user->away);
+
+       if(IsOper(target_p))
+       {
+               sendto_one_numeric(source_p, RPL_WHOISOPERATOR, form_str(RPL_WHOISOPERATOR),
+                                  target_p->name,
+                                  IsService(target_p) ? ConfigFileEntry.servicestring :
+                                  (IsAdmin(target_p) ? GlobalSetOptions.adminstring :
+                                   GlobalSetOptions.operstring));
+       }
+
+       if(MyClient(target_p))
+       {
+               if (IsDynSpoof(target_p) && (IsOper(source_p) || source_p == target_p))
+               {
+                       /* trick here: show a nonoper their own IP if
+                        * dynamic spoofed but not if auth{} spoofed
+                        * -- jilles */
+                       ClearDynSpoof(target_p);
+                       sendto_one_numeric(source_p, RPL_WHOISHOST,
+                                          form_str(RPL_WHOISHOST),
+                                          target_p->name, target_p->orighost,
+                                          show_ip(source_p, target_p) ? target_p->sockhost : "255.255.255.255");
+                       SetDynSpoof(target_p);
+               }
+               else if(ConfigFileEntry.use_whois_actually && show_ip(source_p, target_p))
+                       sendto_one_numeric(source_p, RPL_WHOISACTUALLY,
+                                          form_str(RPL_WHOISACTUALLY),
+                                          target_p->name, target_p->sockhost);
+
+               sendto_one_numeric(source_p, RPL_WHOISIDLE, form_str(RPL_WHOISIDLE),
+                                  target_p->name, 
+                                  CurrentTime - target_p->localClient->last, 
+                                  target_p->localClient->firsttime);
+       }
+       else
+       {
+               if (IsDynSpoof(target_p) && (IsOper(source_p) || source_p == target_p))
+               {
+                       ClearDynSpoof(target_p);
+                       sendto_one_numeric(source_p, RPL_WHOISHOST,
+                                          form_str(RPL_WHOISHOST),
+                                          target_p->name, target_p->orighost,
+                                          show_ip(source_p, target_p) && !EmptyString(target_p->sockhost) && strcmp(target_p->sockhost, "0")? target_p->sockhost : "255.255.255.255");
+                       SetDynSpoof(target_p);
+               }
+               else if(ConfigFileEntry.use_whois_actually && show_ip(source_p, target_p) &&
+                  !EmptyString(target_p->sockhost) && strcmp(target_p->sockhost, "0"))
+               {
+                       sendto_one_numeric(source_p, RPL_WHOISACTUALLY,
+                                          form_str(RPL_WHOISACTUALLY),
+                                          target_p->name, target_p->sockhost);
+                       
+               }
+       
+       }
+
+       hdata.client = source_p;
+       hdata.target = target_p;
+
+       /* doing_whois_hook must only be called for local clients,
+        * doing_whois_global_hook must only be called for local targets
+        */
+       /* it is important that these are called *before* RPL_ENDOFWHOIS is
+        * sent, services compatibility code depends on it. --anfl
+        */
+       if(MyClient(source_p))
+               call_hook(doing_whois_hook, &hdata);
+       else
+               call_hook(doing_whois_global_hook, &hdata);
+
+       return;
+}
+
diff --git a/modules/m_whowas.c b/modules/m_whowas.c
new file mode 100644 (file)
index 0000000..ecb4770
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  m_whois.c: Shows who a user was.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: m_whowas.c 1717 2006-07-04 14:41:11Z jilles $
+ */
+
+#include "stdinc.h"
+#include "whowas.h"
+#include "client.h"
+#include "common.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "ircd_defs.h"
+#include "numeric.h"
+#include "s_serv.h"
+#include "s_user.h"
+#include "send.h"
+#include "s_conf.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+
+static int m_whowas(struct Client *, struct Client *, int, const char **);
+
+struct Message whowas_msgtab = {
+       "WHOWAS", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, {m_whowas, 2}, mg_ignore, mg_ignore, mg_ignore, {m_whowas, 2}}
+};
+
+mapi_clist_av1 whowas_clist[] = { &whowas_msgtab, NULL };
+DECLARE_MODULE_AV1(whowas, NULL, NULL, whowas_clist, NULL, NULL, "$Revision: 1717 $");
+
+/*
+** m_whowas
+**      parv[0] = sender prefix
+**      parv[1] = nickname queried
+*/
+static int
+m_whowas(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{      
+       struct Whowas *temp;
+       int cur = 0;
+       int max = -1, found = 0;
+       char *p;
+       const char *nick;
+
+       static time_t last_used = 0L;
+
+       if(!IsOper(source_p))
+       {
+               if((last_used + ConfigFileEntry.pace_wait_simple) > CurrentTime)
+               {
+                       sendto_one(source_p, form_str(RPL_LOAD2HI),
+                                  me.name, source_p->name, "WHOWAS");
+                       sendto_one(source_p, form_str(RPL_ENDOFWHOWAS),
+                                  me.name, source_p->name, parv[1]);
+                       return 0;
+               }
+               else
+                       last_used = CurrentTime;
+       }
+
+
+       if(parc > 2)
+               max = atoi(parv[2]);
+
+#if 0
+       if(parc > 3)
+               if(hunt_server(client_p, source_p, ":%s WHOWAS %s %s :%s", 3, parc, parv))
+                       return 0;
+#endif
+
+       if((p = strchr(parv[1], ',')))
+               *p = '\0';
+
+       nick = parv[1];
+
+       temp = WHOWASHASH[hash_whowas_name(nick)];
+       found = 0;
+       for (; temp; temp = temp->next)
+       {
+               if(!irccmp(nick, temp->name))
+               {
+                       sendto_one(source_p, form_str(RPL_WHOWASUSER),
+                                  me.name, source_p->name, temp->name,
+                                  temp->username, temp->hostname, temp->realname);
+                       if (MyOper(source_p) && !EmptyString(temp->sockhost))
+#if 0
+                               sendto_one(source_p, form_str(RPL_WHOWASREAL),
+                                          me.name, source_p->name, temp->name,
+                                          "<untracked>", temp->sockhost);
+#else
+                               sendto_one_numeric(source_p, RPL_WHOISACTUALLY,
+                                                  form_str(RPL_WHOISACTUALLY),
+                                                  temp->name, temp->sockhost);
+#endif
+                       sendto_one_numeric(source_p, RPL_WHOISSERVER,
+                                          form_str(RPL_WHOISSERVER),
+                                          temp->name, temp->servername,
+                                          myctime(temp->logoff));
+                       cur++;
+                       found++;
+               }
+               if(max > 0 && cur >= max)
+                       break;
+       }
+
+       if(!found)
+               sendto_one(source_p, form_str(ERR_WASNOSUCHNICK), 
+                          me.name, source_p->name, nick);
+
+       sendto_one(source_p, form_str(RPL_ENDOFWHOWAS), 
+                  me.name, source_p->name, parv[1]);
+       return 0;
+}
diff --git a/modules/m_xline.c b/modules/m_xline.c
new file mode 100644 (file)
index 0000000..248bf7a
--- /dev/null
@@ -0,0 +1,681 @@
+/* modules/m_xline.c
+ * 
+ *  Copyright (C) 2002-2003 Lee Hardy <lee@leeh.co.uk>
+ *  Copyright (C) 2002-2005 ircd-ratbox development team
+ *
+ * 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.The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: m_xline.c 3059 2006-12-27 00:36:54Z jilles $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "send.h"
+#include "channel.h"
+#include "client.h"
+#include "common.h"
+#include "config.h"
+#include "class.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "memory.h"
+#include "s_log.h"
+#include "s_serv.h"
+#include "whowas.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "hash.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+
+static int mo_xline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
+static int ms_xline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
+static int me_xline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
+static int mo_unxline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
+static int ms_unxline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
+static int me_unxline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
+
+struct Message xline_msgtab = {
+       "XLINE", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, {ms_xline, 5}, {ms_xline, 5}, {me_xline, 5}, {mo_xline, 3}}
+};
+struct Message unxline_msgtab = {
+       "UNXLINE", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, {ms_unxline, 3}, {ms_unxline, 3}, {me_unxline, 2}, {mo_unxline, 2}}
+};
+
+mapi_clist_av1 xline_clist[] =  { &xline_msgtab, &unxline_msgtab, NULL };
+DECLARE_MODULE_AV1(xline, NULL, NULL, xline_clist, NULL, NULL, "$Revision: 3059 $");
+
+static int valid_xline(struct Client *, const char *, const char *);
+static void apply_xline(struct Client *client_p, const char *name, 
+                       const char *reason, int temp_time);
+static void write_xline(struct Client *source_p, struct ConfItem *aconf);
+static void propagate_xline(struct Client *source_p, const char *target,
+                       int temp_time, const char *name, 
+                       const char *type, const char *reason);
+static void cluster_xline(struct Client *source_p, int temp_time,
+                       const char *name, const char *reason);
+
+static void handle_remote_xline(struct Client *source_p, int temp_time,
+                               const char *name, const char *reason);
+static void handle_remote_unxline(struct Client *source_p, const char *name);
+
+static int remove_temp_xline(struct Client *source_p, const char *name);
+static void remove_xline(struct Client *source_p, const char *gecos);
+
+
+/* m_xline()
+ *
+ * parv[1] - thing to xline
+ * parv[2] - optional type/reason
+ * parv[3] - reason
+ */
+static int
+mo_xline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct ConfItem *aconf;
+       const char *name;
+       const char *reason;
+       const char *target_server = NULL;
+       int temp_time;
+       int loc = 1;
+
+       if(!IsOperXline(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS),
+                          me.name, source_p->name, "xline");
+               return 0;
+       }
+
+       if((temp_time = valid_temp_time(parv[loc])) >= 0)
+               loc++;
+       /* we just set temp_time to -1! */
+       else
+               temp_time = 0;
+
+       name = parv[loc];
+       loc++;
+
+       /* XLINE <gecos> ON <server> :<reason> */
+       if(parc >= loc+2 && !irccmp(parv[loc], "ON"))
+       {
+               if(!IsOperRemoteBan(source_p))
+               {
+                       sendto_one(source_p, form_str(ERR_NOPRIVS),
+                               me.name, source_p->name, "remoteban");
+                       return 0;
+               }
+
+               target_server = parv[loc+1];
+               loc += 2;
+       }
+
+       if(parc <= loc || EmptyString(parv[loc]))
+       {
+               sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+                               me.name, source_p->name, "XLINE");
+               return 0;
+       }
+
+       reason = parv[loc];
+
+       if(target_server != NULL)
+       {
+               propagate_xline(source_p, target_server, temp_time,
+                               name, "2", reason);
+
+               if(!match(target_server, me.name))
+                       return 0;
+       }
+       else if(dlink_list_length(&cluster_conf_list) > 0)
+               cluster_xline(source_p, temp_time, name, reason);
+
+       if((aconf = find_xline(name, 0)) != NULL)
+       {
+               sendto_one(source_p, ":%s NOTICE %s :[%s] already X-Lined by [%s] - %s",
+                          me.name, source_p->name, parv[1], aconf->name, aconf->passwd);
+               return 0;
+       }
+
+       if(!valid_xline(source_p, name, reason))
+               return 0;
+
+       apply_xline(source_p, name, reason, temp_time);
+
+       return 0;
+}
+
+/* ms_xline()
+ *
+ * handles a remote xline
+ */
+static int
+ms_xline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       /* parv[0]  parv[1]      parv[2]  parv[3]  parv[4]
+        * oper     target serv  xline    type     reason
+        */
+       propagate_xline(source_p, parv[1], 0, parv[2], parv[3], parv[4]);
+
+       if(!IsPerson(source_p))
+               return 0;
+
+       /* destined for me? */
+       if(!match(parv[1], me.name))
+               return 0;
+
+       handle_remote_xline(source_p, 0, parv[2], parv[4]);
+       return 0;
+}
+
+static int
+me_xline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       /* time name type :reason */
+       if(!IsPerson(source_p))
+               return 0;
+
+       handle_remote_xline(source_p, atoi(parv[1]), parv[2], parv[4]);
+       return 0;
+}
+
+static void
+handle_remote_xline(struct Client *source_p, int temp_time,
+                       const char *name, const char *reason)
+{
+       struct ConfItem *aconf;
+
+       if(!find_shared_conf(source_p->username, source_p->host,
+                               source_p->user->server,
+                               (temp_time > 0) ? SHARED_TXLINE : SHARED_PXLINE))
+               return;
+
+       if(!valid_xline(source_p, name, reason))
+               return;
+
+       /* already xlined */
+       if((aconf = find_xline(name, 0)) != NULL)
+       {
+               sendto_one(source_p, ":%s NOTICE %s :[%s] already X-Lined by [%s] - %s",
+                               me.name, source_p->name, name, 
+                               aconf->name, aconf->passwd);
+               return;
+       }
+
+       apply_xline(source_p, name, reason, temp_time);
+}
+
+/* valid_xline()
+ *
+ * inputs      - client xlining, gecos, reason and whether to warn
+ * outputs     -
+ * side effects - checks the xline for validity, erroring if needed
+ */
+static int
+valid_xline(struct Client *source_p, const char *gecos,
+           const char *reason)
+{
+       if(EmptyString(reason))
+       {
+               sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+                          get_id(&me, source_p), 
+                          get_id(source_p, source_p), "XLINE");
+               return 0;
+       }
+
+       if(strchr(reason, ':') != NULL)
+       {
+               sendto_one_notice(source_p,
+                                 ":Invalid character ':' in comment");
+               return 0;
+       }
+
+       if(strchr(reason, '"'))
+       {
+               sendto_one_notice(source_p,
+                               ":Invalid character '\"' in comment");
+               return 0;
+       }
+
+       if(!valid_wild_card_simple(gecos))
+       {
+               sendto_one_notice(source_p,
+                                 ":Please include at least %d non-wildcard "
+                                 "characters with the xline",
+                                 ConfigFileEntry.min_nonwildcard_simple);
+               return 0;
+       }
+
+       return 1;
+}
+
+void
+apply_xline(struct Client *source_p, const char *name, const char *reason,
+               int temp_time)
+{
+       struct ConfItem *aconf;
+
+       aconf = make_conf();
+       aconf->status = CONF_XLINE;
+
+       if(strstr(name, "\\s"))
+       {
+               char *tmp = LOCAL_COPY(name);
+               char *orig = tmp;
+               char *new = tmp;
+
+               while(*orig)
+               {
+                       if(*orig == '\\' && *(orig + 1) != '\0')
+                       {
+                               if(*(orig + 1) == 's')
+                               {
+                                       *new++ = ' ';
+                                       orig += 2;
+                               }
+                               /* otherwise skip that and the escaped
+                                * character after it, so we dont mistake
+                                * \\s as \s --fl
+                                */
+                               else
+                               {
+                                       *new++ = *orig++;
+                                       *new++ = *orig++;
+                               }
+                       }
+                       else
+                               *new++ = *orig++;
+               }
+
+               *new = '\0';
+               DupString(aconf->name, tmp);
+       }
+       else
+               DupString(aconf->name, name);
+
+       DupString(aconf->passwd, reason);
+       collapse(aconf->name);
+
+       if(temp_time > 0)
+       {
+               aconf->hold = CurrentTime + temp_time;
+
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                            "%s added temporary %d min. X-Line for [%s] [%s]",
+                            get_oper_name(source_p), temp_time / 60,
+                            aconf->name, reason);
+               ilog(L_KLINE, "X %s %d %s %s",
+                       get_oper_name(source_p), temp_time / 60,
+                       name, reason);
+               sendto_one_notice(source_p, ":Added temporary %d min. X-Line [%s]",
+                               temp_time / 60, aconf->name);
+       }
+       else
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s added X-Line for [%s] [%s]",
+                               get_oper_name(source_p), 
+                               aconf->name, aconf->passwd);
+               sendto_one_notice(source_p, ":Added X-Line for [%s] [%s]",
+                                       aconf->name, aconf->passwd);
+               write_xline(source_p, aconf);
+               ilog(L_KLINE, "X %s 0 %s %s",
+                       get_oper_name(source_p), name, reason);
+       }
+
+       dlinkAddAlloc(aconf, &xline_conf_list);
+       check_xlines();
+}
+
+/* write_xline()
+ *
+ * inputs      - gecos, reason, xline type
+ * outputs     - writes an xline to the config
+ * side effects - 
+ */
+static void
+write_xline(struct Client *source_p, struct ConfItem *aconf)
+{
+       char buffer[BUFSIZE * 2];
+       FILE *out;
+       const char *filename;
+
+       filename = ConfigFileEntry.xlinefile;
+
+       if((out = fopen(filename, "a")) == NULL)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "*** Problem opening %s ", filename);
+               sendto_one_notice(source_p, ":*** Problem opening file, xline added temporarily only");
+               return;
+       }
+
+       ircsprintf(buffer, "\"%s\",\"0\",\"%s\",\"%s\",%ld\n",
+                  aconf->name, aconf->passwd,
+                  get_oper_name(source_p), CurrentTime);
+
+       if(fputs(buffer, out) == -1)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "*** Problem writing to %s", filename);
+               sendto_one_notice(source_p, ":*** Problem writing to file, xline added temporarily only");
+               fclose(out);
+               return;
+       }
+
+       if(fclose(out))
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "*** Problem writing to %s", filename);
+               sendto_one_notice(source_p, ":*** Problem writing to file, xline added temporarily only");
+               return;
+       }
+}
+
+static void 
+propagate_xline(struct Client *source_p, const char *target,
+               int temp_time, const char *name, const char *type,
+               const char *reason)
+{
+       if(!temp_time)
+       {
+               sendto_match_servs(source_p, target, CAP_CLUSTER, NOCAPS,
+                                       "XLINE %s %s %s :%s",
+                                       target, name, type, reason);
+               sendto_match_servs(source_p, target, CAP_ENCAP, CAP_CLUSTER,
+                               "ENCAP %s XLINE %d %s 2 :%s",
+                               target, temp_time, name, reason);
+       }
+       else
+               sendto_match_servs(source_p, target, CAP_ENCAP, NOCAPS,
+                               "ENCAP %s XLINE %d %s %s :%s",
+                               target, temp_time, name, type, reason);
+}
+                       
+static void
+cluster_xline(struct Client *source_p, int temp_time, const char *name,
+               const char *reason)
+{
+       struct remote_conf *shared_p;
+       dlink_node *ptr;
+
+       DLINK_FOREACH(ptr, cluster_conf_list.head)
+       {
+               shared_p = ptr->data;
+
+               /* old protocol cant handle temps, and we dont really want
+                * to convert them to perm.. --fl
+                */
+               if(!temp_time)
+               {
+                       if(!(shared_p->flags & SHARED_PXLINE))
+                               continue;
+
+                       sendto_match_servs(source_p, shared_p->server, CAP_CLUSTER, NOCAPS,
+                                       "XLINE %s %s 2 :%s",
+                                       shared_p->server, name, reason);
+                       sendto_match_servs(source_p, shared_p->server, CAP_ENCAP, CAP_CLUSTER,
+                                       "ENCAP %s XLINE 0 %s 2 :%s",
+                                       shared_p->server, name, reason);
+               }
+               else if(shared_p->flags & SHARED_TXLINE)
+                       sendto_match_servs(source_p, shared_p->server, CAP_ENCAP, NOCAPS,
+                                       "ENCAP %s XLINE %d %s 2 :%s",
+                                       shared_p->server, temp_time, name, reason);
+       }
+}
+
+/* mo_unxline()
+ *
+ * parv[1] - thing to unxline
+ */
+static int
+mo_unxline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       if(!IsOperXline(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS),
+                          me.name, source_p->name, "xline");
+               return 0;
+       }
+
+       if(parc == 4 && !(irccmp(parv[2], "ON")))
+       {
+               if(!IsOperRemoteBan(source_p))
+               {
+                       sendto_one(source_p, form_str(ERR_NOPRIVS),
+                               me.name, source_p->name, "remoteban");
+                       return 0;
+               }
+
+               propagate_generic(source_p, "UNXLINE", parv[3], CAP_CLUSTER,
+                               "%s", parv[1]);
+
+               if(match(parv[3], me.name) == 0)
+                       return 0;
+       }
+       else if(dlink_list_length(&cluster_conf_list))
+               cluster_generic(source_p, "UNXLINE", SHARED_UNXLINE, CAP_CLUSTER,
+                               "%s", parv[1]);
+
+       if(remove_temp_xline(source_p, parv[1]))
+               return 0;
+
+       remove_xline(source_p, parv[1]);
+
+       return 0;
+}
+
+/* ms_unxline()
+ *
+ * handles a remote unxline
+ */
+static int
+ms_unxline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       /* parv[0]  parv[1]        parv[2]
+        * oper     target server  gecos
+        */
+       propagate_generic(source_p, "UNXLINE", parv[1], CAP_CLUSTER,
+                       "%s", parv[2]);
+
+       if(!match(parv[1], me.name))
+               return 0;
+
+       if(!IsPerson(source_p))
+               return 0;
+
+       handle_remote_unxline(source_p, parv[2]);
+       return 0;
+}
+
+static int
+me_unxline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       /* name */
+       if(!IsPerson(source_p))
+               return 0;
+
+       handle_remote_unxline(source_p, parv[1]);
+       return 0;
+}
+
+static void
+handle_remote_unxline(struct Client *source_p, const char *name)
+{
+       if(!find_shared_conf(source_p->username, source_p->host,
+                               source_p->user->server, SHARED_UNXLINE))
+               return;
+
+       if(remove_temp_xline(source_p, name))
+               return;
+
+       remove_xline(source_p, name);
+
+       return;
+}
+
+static int
+remove_temp_xline(struct Client *source_p, const char *name)
+{
+       struct ConfItem *aconf;
+       dlink_node *ptr;
+
+       DLINK_FOREACH(ptr, xline_conf_list.head)
+       {
+               aconf = ptr->data;
+
+               /* only want to check temp ones! */
+               if(!aconf->hold)
+                       continue;
+
+               if(!irccmp(aconf->name, name))
+               {
+                       sendto_one_notice(source_p, 
+                                       ":X-Line for [%s] is removed",
+                                       name);
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                        "%s has removed the temporary X-Line for: [%s]",
+                                        get_oper_name(source_p), name);
+                       ilog(L_KLINE, "UX %s %s", 
+                               get_oper_name(source_p), name);
+                       
+                       free_conf(aconf);
+                       dlinkDestroy(ptr, &xline_conf_list);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+/* remove_xline()
+ *
+ * inputs      - gecos to remove
+ * outputs     - 
+ * side effects - removes xline from conf, if exists
+ */
+static void
+remove_xline(struct Client *source_p, const char *huntgecos)
+{
+       FILE *in, *out;
+       char buf[BUFSIZE];
+       char buff[BUFSIZE];
+       char temppath[BUFSIZE];
+       const char *filename;
+       const char *gecos;
+       mode_t oldumask;
+       char *p;
+       int error_on_write = 0;
+       int found_xline = 0;
+
+       filename = ConfigFileEntry.xlinefile;
+       ircsnprintf(temppath, sizeof(temppath),
+                "%s.tmp", ConfigFileEntry.xlinefile);
+
+       if((in = fopen(filename, "r")) == NULL)
+       {
+               sendto_one_notice(source_p, ":Cannot open %s", filename);
+               return;
+       }
+
+       oldumask = umask(0);
+
+       if((out = fopen(temppath, "w")) == NULL)
+       {
+               sendto_one_notice(source_p, ":Cannot open %s", temppath);
+               fclose(in);
+               umask(oldumask);
+               return;
+       }
+
+       umask(oldumask);
+
+       while (fgets(buf, sizeof(buf), in))
+       {
+               if(error_on_write)
+               {
+                       if(temppath != NULL)
+                               (void) unlink(temppath);
+
+                       break;
+               }
+
+               strlcpy(buff, buf, sizeof(buff));
+
+               if((p = strchr(buff, '\n')) != NULL)
+                       *p = '\0';
+
+               if((*buff == '\0') || (*buff == '#'))
+               {
+                       error_on_write = (fputs(buf, out) < 0) ? YES : NO;
+                       continue;
+               }
+
+               if((gecos = getfield(buff)) == NULL)
+               {
+                       error_on_write = (fputs(buf, out) < 0) ? YES : NO;
+                       continue;
+               }
+
+               /* matching.. */
+               if(irccmp(gecos, huntgecos) == 0)
+                       found_xline++;
+               else
+                       error_on_write = (fputs(buf, out) < 0) ? YES : NO;
+       }
+
+       fclose(in);
+       if (fclose(out))
+               error_on_write = YES;
+
+       if(error_on_write)
+       {
+               sendto_one_notice(source_p,
+                                 ":Couldn't write temp xline file, aborted");
+               return;
+       }
+       else if(found_xline == 0)
+       {
+               sendto_one_notice(source_p, ":No X-Line for %s", huntgecos);
+
+               if(temppath != NULL)
+                       (void) unlink(temppath);
+               return;
+       }
+
+       if (rename(temppath, filename))
+       {
+               sendto_one_notice(source_p, ":Couldn't rename temp file, aborted");
+               return;
+       }
+       rehash_bans(0);
+
+       sendto_one_notice(source_p, ":X-Line for [%s] is removed", huntgecos);
+       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                            "%s has removed the X-Line for: [%s]",
+                            get_oper_name(source_p), huntgecos);
+       ilog(L_KLINE, "UX %s %s", get_oper_name(source_p), huntgecos);
+}
diff --git a/modules/sno_routing.c b/modules/sno_routing.c
new file mode 100644 (file)
index 0000000..cb1df17
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ *  charybdis: an advanced Internet Relay Chat Daemon(ircd).
+ *  sno_routing.c: Shows notices about netjoins and netsplits
+ *
+ *  Copyright (c) 2005-2006 Jilles Tjoelker <jilles-at-stack.nl>
+ *
+ *  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.The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ *  $Id: sno_routing.c 1172 2006-04-18 13:49:18Z jilles $
+ */
+
+#include "stdinc.h"
+#include "modules.h"
+#include "client.h"
+#include "hook.h"
+#include "ircd.h"
+#include "send.h"
+
+static void h_nn_server_eob(struct Client *);
+static void h_nn_client_exit(hook_data_client_exit *);
+
+mapi_hfn_list_av1 nn_hfnlist[] = {
+       { "server_eob", (hookfn) h_nn_server_eob },
+       { "client_exit", (hookfn) h_nn_client_exit },
+       { NULL, NULL }
+};
+
+DECLARE_MODULE_AV1(networknotice, NULL, NULL, NULL, NULL, nn_hfnlist, "$Revision: 1172 $");
+
+/*
+ * count_mark_downlinks
+ *
+ * inputs      - pointer to server to count
+ *             - pointers to server and user count
+ * output      - NONE
+ * side effects - servers are marked
+ *             - server and user counts are added to given values
+ */
+static void
+count_mark_downlinks(struct Client *server_p, int *pservcount, int *pusercount)
+{
+       dlink_node *ptr;
+
+       SetFloodDone(server_p);
+       (*pservcount)++;
+       *pusercount += dlink_list_length(&server_p->serv->users);
+       DLINK_FOREACH(ptr, server_p->serv->servers.head)
+       {
+               count_mark_downlinks(ptr->data, pservcount, pusercount);
+       }
+}
+
+static void
+h_nn_server_eob(struct Client *source_p)
+{
+       int s = 0, u = 0;
+
+       if (IsFloodDone(source_p))
+               return;
+       count_mark_downlinks(source_p, &s, &u);
+       sendto_realops_snomask(SNO_GENERAL, L_ALL, "Netjoin %s <-> %s (%dS %dC)",
+                       source_p->servptr ? source_p->servptr->name : "?",
+                       source_p->name, s, u);
+}
+
+static void
+h_nn_client_exit(hook_data_client_exit *hdata)
+{
+       struct Client *source_p;
+       int s = 0, u = 0;
+       char *fromnick;
+
+       source_p = hdata->target;
+       fromnick = IsClient(hdata->from) ? hdata->from->name : NULL;
+
+       if (!IsServer(source_p))
+               return;
+       if (HasSentEob(source_p))
+       {
+               count_mark_downlinks(source_p, &s, &u);
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "Netsplit %s <-> %s (%dS %dC) (%s%s%s%s)",
+                               source_p->servptr ? source_p->servptr->name : "?",
+                               source_p->name, s, u,
+                               fromnick ? "by " : "",
+                               fromnick ? fromnick : "",
+                               fromnick ? ": " : "",
+                               hdata->comment);
+       }
+       else
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "Netsplit %s <-> %s (during burst) (%s%s%s%s)",
+                               source_p->servptr ? source_p->servptr->name : "?",
+                               source_p->name,
+                               fromnick ? "by " : "",
+                               fromnick ? fromnick : "",
+                               fromnick ? ": " : "",
+                               hdata->comment);
+}
diff --git a/modules/static_modules.c.SH b/modules/static_modules.c.SH
new file mode 100644 (file)
index 0000000..ab4fe2b
--- /dev/null
@@ -0,0 +1,106 @@
+#!/bin/sh
+# static_modules.c.SH: Generates our static module list
+# $Id: static_modules.c.SH 6 2005-09-10 01:02:21Z nenolod $
+#
+SYMS=`for x in $*; do basename $x .o|sed -es/^m_//; done`
+cat > static_modules.c <<EOF
+/*
+ *  This file is automatically generated: do not modify
+ *  ircd-ratbox: A slightly useful ircd
+ *
+ *  Copyright (C) 2003 Aaron Sethman <androsyn@ratbox.org>
+ *  Copyright (C) 2003-2005 ircd-ratbox development 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
+ *  
+ */
+#include "stdinc.h"
+#include "modules.h"
+#include "hash.h"
+#include "s_log.h"
+
+EOF
+
+for x in $SYMS; do 
+       echo extern struct mapi_header_av1 "$x"_mheader\;
+done >> static_modules.c
+
+
+echo static const struct mapi_header_av1 *mapi_headers[] = { >> static_modules.c 
+for x in $SYMS; do 
+       echo \&"$x"_mheader,
+done >> static_modules.c
+
+echo NULL }\; >> static_modules.c
+
+cat >> static_modules.c <<EOF
+void load_static_modules(void)
+{
+       int x;
+       int *mapi_version;
+       for(x = 0; mapi_headers[x] != NULL; x++)
+       {
+               mapi_version = (int *)mapi_headers[x];
+               if(MAPI_MAGIC(*mapi_version) != MAPI_MAGIC_HDR)
+               {
+                       ilog(L_MAIN, "Error: linked in module without a MAPI header..giving up");
+                       exit(70);
+               }       
+               switch(MAPI_VERSION(*mapi_version))
+               {
+                       case 1:
+                       {
+                               struct mapi_mheader_av1 *mheader = (struct mapi_mheader_av1*)mapi_version;
+                               if (mheader->mapi_register && (mheader->mapi_register() == -1))
+                               {
+                                       ilog(L_MAIN, "Error: linked in module failed loading..giving up");
+                                       exit(70);
+                               }
+                               
+                               if(mheader->mapi_command_list)
+                               {
+                                       struct Message **m;
+                                       for(m = mheader->mapi_command_list; *m; ++m)
+                                               mod_add_cmd(*m);
+                               }
+                               
+                               if(mheader->mapi_hook_list)
+                               {
+                                       mapi_hlist_av1 *m;
+                                       for(m = mheader->mapi_hook_list; m->hapi_name; ++m)
+                                               *m->hapi_id = register_hook(m->hapi_name);
+                               }       
+                               
+                               if(mheader->mapi_hfn_list)
+                               {
+                                       mapi_hfn_list_av1 *m;
+                                       for(m = mheader->mapi_hfn_list; m->hapi_name; ++m)
+                                               add_hook(m->hapi_name, m->fn);
+                                               
+                               }
+                               
+                               break;
+                       
+                       }       
+                       default:
+                       {
+                               ilog(L_MAIN, "Error: Unknown MAPI version in linked in module..giving up");
+                               exit(70);
+                       }                               
+               }
+       }
+}
+EOF
diff --git a/servlink/.cvsignore b/servlink/.cvsignore
new file mode 100644 (file)
index 0000000..224f7c6
--- /dev/null
@@ -0,0 +1,3 @@
+Makefile
+setup.h
+servlink
diff --git a/servlink/.indent.pro b/servlink/.indent.pro
new file mode 100644 (file)
index 0000000..a498166
--- /dev/null
@@ -0,0 +1 @@
+-i8 -bli0 -ut -nsai -l100 -npcs
\ No newline at end of file
diff --git a/servlink/Makefile.in b/servlink/Makefile.in
new file mode 100644 (file)
index 0000000..a047012
--- /dev/null
@@ -0,0 +1,82 @@
+#
+# Makefile.in for servlink/src
+#
+# $Id: Makefile.in 1285 2006-05-05 15:03:53Z nenolod $
+#
+
+CC              = @CC@
+INSTALL         = @INSTALL@
+INSTALL_BIN     = @INSTALL_PROGRAM@
+INSTALL_DATA    = @INSTALL_DATA@
+INSTALL_SUID    = @INSTALL_PROGRAM@ -o root -m 4755
+RM              = @RM@
+LEX             = @LEX@
+LEXLIB          = @LEXLIB@
+CFLAGS          = @IRC_CFLAGS@ -DIRCD_PREFIX=\"@prefix@\"
+LDFLAGS         = @LDFLAGS@
+MKDEP           = @MKDEP@ -DIRCD_PREFIX=\"@prefix@\"
+MV              = @MV@
+RM              = @RM@
+prefix          = @prefix@
+exec_prefix     = @exec_prefix@
+bindir          = @bindir@
+libexecdir      = @libexecdir@
+confdir         = @confdir@
+localstatedir   = @localstatedir@
+
+ZIP_LIB                = @ZLIB_LD@
+
+IRCDLIBS        = @LIBS@ $(ZIP_LIB)
+
+INCLUDES        = -I. -I../include $(SSL_INCLUDES)
+CPPFLAGS        = ${INCLUDES} @CPPFLAGS@
+
+PROGS          = servlink
+
+SOURCES =     \
+  servlink.c  \
+  io.c        \
+  control.c
+  
+
+OBJECTS = ${SOURCES:.c=.o}
+
+all: servlink
+
+build: all
+
+servlink: ${OBJECTS}
+       ${CC} ${CFLAGS} ${LDFLAGS} -o $@ ${OBJECTS} ${IRCDLIBS}
+
+install: build
+       @echo "ircd: installing servlink ($(PROGS))"
+       @for i in $(PROGS); do \
+                if test -f $(DESTDIR)$(bindir)/$$i; then \
+                        $(MV) $(DESTDIR)$(bindir)/$$i $(DESTDIR)$(bindir)/$$i.old; \
+                fi; \
+                $(INSTALL_BIN) $$i $(DESTDIR)$(bindir); \
+        done
+
+.c.o:
+       ${CC} ${CPPFLAGS} ${CFLAGS} -c $<
+
+.PHONY: depend clean distclean
+depend:
+       @${MKDEP} ${CPPFLAGS} ${SOURCES} > .depend.tmp
+       @sed -e '/^# DO NOT DELETE THIS LINE/,$$d' <Makefile >Makefile.depend
+       @echo '# DO NOT DELETE THIS LINE!!!' >>Makefile.depend
+       @echo '# make depend needs it.' >>Makefile.depend
+       @cat .depend.tmp >>Makefile.depend
+       @mv Makefile.depend Makefile
+       @rm -f .depend.tmp
+
+clean:
+       ${RM} -f *.o *~ *.core core servlink
+
+lint:
+       lint -aacgprxhH $(CPPFLAGS) -DIRCD_PREFIX=\"@prefix@\" $(SOURCES) >>../lint.out
+
+distclean: clean
+       ${RM} -f Makefile
+
+# End of Makefile
diff --git a/servlink/README b/servlink/README
new file mode 100644 (file)
index 0000000..2ccfcd6
--- /dev/null
@@ -0,0 +1,71 @@
+Servlink protocol documentation.
+$Id: README 1285 2006-05-05 15:03:53Z nenolod $
+--------------
+
+After negotiating an incoming/outgoing server connection, the ircd will
+fork, then execve servlink, with fd 0 as one end of a control pipe and
+fd 1 as one end of a data pipe. fd 2 will be the socket connected to
+the remote server.
+
+The data pipe is used by the ircd to send/receive normal, decrypted,
+uncompressed IRC commands to/from the remote server.  The socket is used to
+send the (processed) data to the remote server, and receive the data from
+the remote server.
+
+The control pipe is used to activate encryption/compression and to set the
+encryption key/algorithm to be used.
+
+Format of control messages:
+
+<u8 command><optional data>
+
+data format:
+<u16 len><data>
+
+Commands:
+
+001 - SET_ZIP_OUT_LEVEL
+       data: yes
+       description:
+               set compression level (0 [use default, 6], or 1-9)
+
+002 - START_ZIP_OUT
+       data: no
+       description:
+               all data written to the data pipe will be compressed
+               prior to being sent to the remote server.
+
+003 - START_ZIP_IN
+       data: no
+       description:
+               all data not yet read from the slink program will be
+               decompressed before reading
+
+004 - INJECT_RECVQ
+       data: recvq
+
+       Used before INIT to inject any data read from the server fd which
+       should be pre-processed by servlink before being sent back
+       to the LOCAL_FD through the data fd.
+
+005 - INJECT_SENDQ
+       data: sendq
+
+       As above, but sent to remote server without processing.
+
+006 - INIT
+
+007 - ZIPSTATS
+       request to send ziplinks statistics reply.
+
+replies
+
+001 - ERROR
+       data: u32 len/char error[len]
+
+       fatal error message.
+
+002 - ZIPSTATS
+        data: u32 in/u32 in_wire/u32 out/u32 out_wire                           
+
+       ziplinks commpression statistics
diff --git a/servlink/TODO b/servlink/TODO
new file mode 100644 (file)
index 0000000..6fcefa1
--- /dev/null
@@ -0,0 +1,7 @@
+Servlink todo list
+$Id: TODO 6 2005-09-10 01:02:21Z nenolod $
+------------------
+
+Fix any bugs that come up
+
+Think of improvements :)
diff --git a/servlink/control.c b/servlink/control.c
new file mode 100644 (file)
index 0000000..1f341a7
--- /dev/null
@@ -0,0 +1,129 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, servlink/servlink.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.
+ *
+ *   $Id: control.c 1285 2006-05-05 15:03:53Z nenolod $
+ */
+
+#include "setup.h"
+
+#include <sys/types.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#ifdef HAVE_LIBZ
+#include <zlib.h>
+#endif
+
+#include "servlink.h"
+#include "io.h"
+#include "control.h"
+
+static cmd_handler cmd_set_zip_out_level;
+static cmd_handler cmd_start_zip_out;
+static cmd_handler cmd_start_zip_in;
+static cmd_handler cmd_init;
+
+struct command_def command_table[] = {
+       {CMD_SET_ZIP_OUT_LEVEL, cmd_set_zip_out_level, COMMAND_FLAG_DATA},
+       {CMD_START_ZIP_OUT, cmd_start_zip_out, 0},
+       {CMD_START_ZIP_IN, cmd_start_zip_in, 0},
+       {CMD_INJECT_RECVQ, process_recvq, COMMAND_FLAG_DATA},
+       {CMD_INJECT_SENDQ, process_sendq, COMMAND_FLAG_DATA},
+       {CMD_INIT, cmd_init, 0},
+       {CMD_ZIPSTATS, send_zipstats, 0},
+       {0, 0, 0}
+};
+
+void
+cmd_set_zip_out_level(struct ctrl_command *cmd)
+{
+#ifdef HAVE_LIBZ
+       out_state.zip_state.level = *cmd->data;
+       if((out_state.zip_state.level < -1) || (out_state.zip_state.level > 9))
+               send_error("invalid compression level %d", out_state.zip_state.level);
+#else
+       send_error("can't set compression level - no libz support!");
+#endif
+}
+
+void
+cmd_start_zip_out(struct ctrl_command *cmd)
+{
+#ifdef HAVE_LIBZ
+       int ret;
+
+       if(out_state.zip)
+               send_error("can't start compression - already started!");
+
+       out_state.zip_state.z_stream.total_in = 0;
+       out_state.zip_state.z_stream.total_out = 0;
+       out_state.zip_state.z_stream.zalloc = (alloc_func) 0;
+       out_state.zip_state.z_stream.zfree = (free_func) 0;
+       out_state.zip_state.z_stream.data_type = Z_ASCII;
+
+       if(out_state.zip_state.level <= 0)
+               out_state.zip_state.level = Z_DEFAULT_COMPRESSION;
+
+       if((ret = deflateInit(&out_state.zip_state.z_stream, out_state.zip_state.level)) != Z_OK)
+               send_error("deflateInit failed: %s", zError(ret));
+
+       out_state.zip = 1;
+#else
+       send_error("can't start compression - no libz support!");
+#endif
+}
+
+void
+cmd_start_zip_in(struct ctrl_command *cmd)
+{
+#ifdef HAVE_LIBZ
+       int ret;
+
+       if(in_state.zip)
+               send_error("can't start decompression - already started!");
+
+       in_state.zip_state.z_stream.total_in = 0;
+       in_state.zip_state.z_stream.total_out = 0;
+       in_state.zip_state.z_stream.zalloc = (alloc_func) 0;
+       in_state.zip_state.z_stream.zfree = (free_func) 0;
+       in_state.zip_state.z_stream.data_type = Z_ASCII;
+       if((ret = inflateInit(&in_state.zip_state.z_stream)) != Z_OK)
+               send_error("inflateInit failed: %s", zError(ret));
+       in_state.zip = 1;
+#else
+       send_error("can't start decompression - no libz support!");
+#endif
+}
+
+
+void
+cmd_init(struct ctrl_command *cmd)
+{
+       if(in_state.active || out_state.active)
+               send_error("CMD_INIT sent twice!");
+
+       in_state.active = 1;
+       out_state.active = 1;
+       CONTROL.read_cb = read_ctrl;
+       CONTROL.write_cb = NULL;
+       LOCAL.read_cb = read_data;
+       LOCAL.write_cb = NULL;
+       REMOTE.read_cb = read_net;
+       REMOTE.write_cb = NULL;
+}
diff --git a/servlink/control.h b/servlink/control.h
new file mode 100644 (file)
index 0000000..294eeb9
--- /dev/null
@@ -0,0 +1,57 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, servlink/control.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: control.h 1285 2006-05-05 15:03:53Z nenolod $
+ */
+
+#ifndef INCLUDED_servlink_control_h
+#define INCLUDED_servlink_control_h
+
+#define CMD_SET_ZIP_OUT_LEVEL           1  /* data */
+#define CMD_START_ZIP_OUT               2
+#define CMD_START_ZIP_IN                3
+#define CMD_INJECT_RECVQ                4  /* data */
+#define CMD_INJECT_SENDQ                5  /* data */ 
+#define CMD_INIT                        6
+#define CMD_ZIPSTATS                    7
+
+#define RPL_ERROR                       1      /* data */
+#define RPL_ZIPSTATS                    2      /* data */
+
+/* flags */
+#define COMMAND_FLAG_DATA               0x0001 /* command has data
+                                                  following */
+struct ctrl_command
+{
+       int command;
+       int datalen;
+       int gotdatalen;
+       int readdata;
+       unsigned char *data;
+};
+
+typedef void cmd_handler(struct ctrl_command *);
+
+struct command_def
+{
+       unsigned int commandid;
+       cmd_handler *handler;
+       unsigned int flags;
+};
+
+extern struct command_def command_table[];
+#endif /* INCLUDED_servlink_control_h */
diff --git a/servlink/io.c b/servlink/io.c
new file mode 100644 (file)
index 0000000..754fcd7
--- /dev/null
@@ -0,0 +1,657 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, servlink/io.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.
+ *
+ *   $Id: io.c 1285 2006-05-05 15:03:53Z nenolod $
+ */
+
+#include "setup.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#ifdef HAVE_LIBZ
+#include <zlib.h>
+#endif
+
+#include "servlink.h"
+#include "io.h"
+#include "control.h"
+
+static int check_error(int, int, int);
+
+static const char *
+fd_name(int fd)
+{
+       if(fd == CONTROL.fd)
+               return "control";
+       if(fd == LOCAL.fd)
+               return "data";
+       if(fd == REMOTE.fd)
+               return "network";
+
+       /* uh oh... */
+       return "unknown";
+}
+
+#if defined( HAVE_LIBZ )
+static unsigned char tmp_buf[BUFLEN];
+static unsigned char tmp2_buf[BUFLEN];
+#endif
+
+static unsigned char ctrl_buf[256] = "";
+static unsigned int ctrl_len = 0;
+static unsigned int ctrl_ofs = 0;
+
+void
+io_loop(int nfds)
+{
+       fd_set rfds;
+       fd_set wfds;
+       int i, ret;
+
+       /* loop forever */
+       for (;;)
+       {
+               FD_ZERO(&rfds);
+               FD_ZERO(&wfds);
+
+               for (i = 0; i < 3; i++)
+               {
+                       if(fds[i].read_cb)
+                               FD_SET(fds[i].fd, &rfds);
+                       if(fds[i].write_cb)
+                               FD_SET(fds[i].fd, &wfds);
+               }
+
+               /* we have <3 fds ever, so I don't think select is too painful */
+               ret = select(nfds, &rfds, &wfds, NULL, NULL);
+
+               if(ret < 0)
+               {
+                       check_error(ret, IO_SELECT, -1);        /* exit on fatal errors */
+               }
+               else if(ret > 0)
+               {
+                       /* call any callbacks */
+                       for (i = 0; i < 3; i++)
+                       {
+                               if(FD_ISSET(fds[i].fd, &rfds) && fds[i].read_cb)
+                                       (*fds[i].read_cb) ();
+                               if(FD_ISSET(fds[i].fd, &wfds) && fds[i].write_cb)
+                                       (*fds[i].write_cb) ();
+                       }
+               }
+       }
+}
+
+void
+send_data_blocking(int fd, unsigned char *data, int datalen)
+{
+       int ret;
+       fd_set wfds;
+
+       while (1)
+       {
+               ret = write(fd, data, datalen);
+
+               if(ret == datalen)
+                       return;
+               else if(ret > 0)
+               {
+                       data += ret;
+                       datalen -= ret;
+               }
+
+               ret = check_error(ret, IO_WRITE, fd);
+
+               FD_ZERO(&wfds);
+               FD_SET(fd, &wfds);
+
+               /* sleep until we can write to the fd */
+               while (1)
+               {
+                       ret = select(fd + 1, NULL, &wfds, NULL, NULL);
+
+                       if(ret > 0)     /* break out so we can write */
+                               break;
+
+                       if(ret < 0)     /* error ? */
+                               check_error(ret, IO_SELECT, fd);        /* exit on fatal errors */
+
+                       /* loop on non-fatal errors */
+               }
+       }
+}
+
+/*
+ * process_sendq:
+ * 
+ * used before CMD_INIT to pass contents of SendQ from ircd
+ * to servlink.  This data must _not_ be encrypted/compressed.
+ */
+void
+process_sendq(struct ctrl_command *cmd)
+{
+       send_data_blocking(REMOTE.fd, cmd->data, cmd->datalen);
+}
+
+/*
+ * process_recvq:
+ *
+ * used before CMD_INIT to pass contents of RecvQ from ircd
+ * to servlink.  This data must be decrypted/decopmressed before
+ * sending back to the ircd.
+ */
+void
+process_recvq(struct ctrl_command *cmd)
+{
+       int ret;
+       unsigned char *buf;
+       int blen;
+       unsigned char *data = cmd->data;
+       unsigned int datalen = cmd->datalen;
+
+       buf = data;
+       blen = datalen;
+       ret = -1;
+       if(datalen > READLEN)
+               send_error("Error processing INJECT_RECVQ - buffer too long (%d > %d)",
+                          datalen, READLEN);
+
+#ifdef HAVE_LIBZ
+       if(in_state.zip)
+       {
+               /* decompress data */
+               in_state.zip_state.z_stream.next_in = buf;
+               in_state.zip_state.z_stream.avail_in = blen;
+               in_state.zip_state.z_stream.next_out = tmp2_buf;
+               in_state.zip_state.z_stream.avail_out = BUFLEN;
+
+               buf = tmp2_buf;
+               while (in_state.zip_state.z_stream.avail_in)
+               {
+                       if((ret = inflate(&in_state.zip_state.z_stream, Z_NO_FLUSH)) != Z_OK)
+                       {
+                               if(!strncmp("ERROR ", (char *)in_state.zip_state.z_stream.next_in, 6))
+                                       send_error("Received uncompressed ERROR");
+                               else
+                                       send_error("Inflate failed: %s", zError(ret));
+                       }
+                       blen = BUFLEN - in_state.zip_state.z_stream.avail_out;
+
+                       if(in_state.zip_state.z_stream.avail_in)
+                       {
+                               send_data_blocking(LOCAL.fd, buf, blen);
+                               blen = 0;
+                               in_state.zip_state.z_stream.next_out = buf;
+                               in_state.zip_state.z_stream.avail_out = BUFLEN;
+                       }
+               }
+
+               if(!blen)
+                       return;
+       }
+#endif
+
+       send_data_blocking(LOCAL.fd, buf, blen);
+}
+
+void
+send_zipstats(struct ctrl_command *unused)
+{
+#ifdef HAVE_LIBZ
+       int i = 0;
+       int ret;
+       u_int32_t len;
+       if(!in_state.active || !out_state.active)
+               send_error("Error processing CMD_ZIPSTATS - link is not active!");
+       if(!in_state.zip || !out_state.zip)
+               send_error("Error processing CMD_ZIPSTATS - link is not compressed!");
+
+       ctrl_buf[i++] = RPL_ZIPSTATS;
+       ctrl_buf[i++] = 0;
+       ctrl_buf[i++] = 16;
+
+       len = (u_int32_t) in_state.zip_state.z_stream.total_out;
+       ctrl_buf[i++] = ((len >> 24) & 0xFF);
+       ctrl_buf[i++] = ((len >> 16) & 0xFF);
+       ctrl_buf[i++] = ((len >> 8) & 0xFF);
+       ctrl_buf[i++] = ((len) & 0xFF);
+
+       len = (u_int32_t) in_state.zip_state.z_stream.total_in;
+       ctrl_buf[i++] = ((len >> 24) & 0xFF);
+       ctrl_buf[i++] = ((len >> 16) & 0xFF);
+       ctrl_buf[i++] = ((len >> 8) & 0xFF);
+       ctrl_buf[i++] = ((len) & 0xFF);
+
+       len = (u_int32_t) out_state.zip_state.z_stream.total_in;
+       ctrl_buf[i++] = ((len >> 24) & 0xFF);
+       ctrl_buf[i++] = ((len >> 16) & 0xFF);
+       ctrl_buf[i++] = ((len >> 8) & 0xFF);
+       ctrl_buf[i++] = ((len) & 0xFF);
+
+       len = (u_int32_t) out_state.zip_state.z_stream.total_out;
+       ctrl_buf[i++] = ((len >> 24) & 0xFF);
+       ctrl_buf[i++] = ((len >> 16) & 0xFF);
+       ctrl_buf[i++] = ((len >> 8) & 0xFF);
+       ctrl_buf[i++] = ((len) & 0xFF);
+
+       in_state.zip_state.z_stream.total_in = 0;
+       in_state.zip_state.z_stream.total_out = 0;
+       out_state.zip_state.z_stream.total_in = 0;
+       out_state.zip_state.z_stream.total_out = 0;
+
+       ret = check_error(write(CONTROL.fd, ctrl_buf, i), IO_WRITE, CONTROL.fd);
+       if(ret < i)
+       {
+               /* write incomplete, register write cb */
+               CONTROL.write_cb = write_ctrl;
+               /*  deregister read_cb */
+               CONTROL.read_cb = NULL;
+               ctrl_ofs = ret;
+               ctrl_len = i - ret;
+               return;
+       }
+#else
+       send_error("can't send_zipstats -- no zlib support!");
+#endif
+}
+
+/* send_error
+ *   - we ran into some problem, make a last ditch effort to 
+ *     flush the control fd sendq, then (blocking) send an
+ *     error message over the control fd.
+ */
+void
+send_error(const char *message, ...)
+{
+       va_list args;
+       static int sending_error = 0;
+       struct linger linger_opt = { 1, 30 };   /* wait 30 seconds */
+       int len;
+
+       if(sending_error)
+               exit(1);        /* we did _try_ */
+
+       sending_error = 1;
+
+       if(ctrl_len)            /* attempt to flush any data we have... */
+       {
+               send_data_blocking(CONTROL.fd, (ctrl_buf + ctrl_ofs), ctrl_len);
+       }
+
+       /* prepare the message, in in_buf, since we won't be using it again.. */
+       in_state.buf[0] = RPL_ERROR;
+       in_state.buf[1] = 0;
+       in_state.buf[2] = 0;
+
+       va_start(args, message);
+       len = vsprintf((char *) in_state.buf + 3, message, args);
+       va_end(args);
+
+       in_state.buf[3 + len++] = '\0';
+       in_state.buf[1] = len >> 8;
+       in_state.buf[2] = len & 0xFF;
+       len += 3;
+
+       send_data_blocking(CONTROL.fd, in_state.buf, len);
+
+       /* XXX - is this portable?
+        *       this obviously will fail on a non socket.. */
+       setsockopt(CONTROL.fd, SOL_SOCKET, SO_LINGER, &linger_opt, sizeof(struct linger));
+
+       /* well, we've tried... */
+       exit(1);                /* now abort */
+}
+
+/* read_ctrl
+ *      called when a command is waiting on the control pipe
+ */
+void
+read_ctrl(void)
+{
+       int ret;
+       unsigned char tmp[2];
+       unsigned char *len;
+       struct command_def *cdef;
+       static struct ctrl_command cmd = { 0, 0, 0, 0, NULL };
+
+       if(cmd.command == 0)    /* we don't have a command yet */
+       {
+               cmd.gotdatalen = 0;
+               cmd.datalen = 0;
+               cmd.readdata = 0;
+               cmd.data = NULL;
+
+               /* read the command */
+               if(!(ret = check_error(read(CONTROL.fd, tmp, 1), IO_READ, CONTROL.fd)))
+                       return;
+
+               cmd.command = tmp[0];
+       }
+
+       for (cdef = command_table; cdef->commandid; cdef++)
+       {
+               if((int)cdef->commandid == cmd.command)
+                       break;
+       }
+
+       if(!cdef->commandid)
+       {
+               send_error("Unsupported command (servlink/ircd out of sync?): %d", cmd.command);
+               /* NOTREACHED */
+       }
+
+       /* read datalen for commands including data */
+       if(cdef->flags & COMMAND_FLAG_DATA)
+       {
+               if(cmd.gotdatalen < 2)
+               {
+                       len = tmp;
+                       if(!(ret = check_error(read(CONTROL.fd, len,
+                                                   (2 - cmd.gotdatalen)), IO_READ, CONTROL.fd)))
+                               return;
+
+                       if(cmd.gotdatalen == 0)
+                       {
+                               cmd.datalen = len[0] << 8;
+                               cmd.gotdatalen++;
+                               ret--;
+                               len++;
+                       }
+                       if(ret && (cmd.gotdatalen == 1))
+                       {
+                               cmd.datalen |= len[0];
+                               cmd.gotdatalen++;
+                               if(cmd.datalen > 0)
+                                       cmd.data = calloc(cmd.datalen, 1);
+                       }
+               }
+       }
+
+       if(cmd.readdata < cmd.datalen)  /* try to get any remaining data */
+       {
+               if(!(ret = check_error(read(CONTROL.fd,
+                                           (cmd.data + cmd.readdata),
+                                           cmd.datalen - cmd.readdata), IO_READ, CONTROL.fd)))
+                       return;
+
+               cmd.readdata += ret;
+               if(cmd.readdata < cmd.datalen)
+                       return;
+       }
+
+       /* we now have the command and any data */
+       (*cdef->handler) (&cmd);
+
+       if(cmd.datalen > 0)
+               free(cmd.data);
+       cmd.command = 0;
+}
+
+void
+write_ctrl(void)
+{
+       int ret;
+
+       assert(ctrl_len);
+
+       if(!(ret = check_error(write(CONTROL.fd, (ctrl_buf + ctrl_ofs),
+                                    ctrl_len), IO_WRITE, CONTROL.fd)))
+               return;         /* no data waiting */
+
+       ctrl_len -= ret;
+
+       if(!ctrl_len)
+       {
+               /* write completed, de-register write cb */
+               CONTROL.write_cb = NULL;
+               /* reregister read_cb */
+               CONTROL.read_cb = read_ctrl;
+               ctrl_ofs = 0;
+       }
+       else
+               ctrl_ofs += ret;
+}
+
+void
+read_data(void)
+{
+       int ret, ret2;
+       unsigned char *buf = out_state.buf;
+       int blen;
+       ret2 = -1;
+       assert(!out_state.len);
+
+#if defined(HAVE_LIBZ) 
+       if(out_state.zip || out_state.crypt)
+               buf = tmp_buf;
+#endif
+
+       while ((ret = check_error(read(LOCAL.fd, buf, READLEN), IO_READ, LOCAL.fd)))
+       {
+               blen = ret;
+#ifdef HAVE_LIBZ
+               if(out_state.zip)
+               {
+                       out_state.zip_state.z_stream.next_in = buf;
+                       out_state.zip_state.z_stream.avail_in = ret;
+
+                       buf = out_state.buf;
+                       out_state.zip_state.z_stream.next_out = buf;
+                       out_state.zip_state.z_stream.avail_out = BUFLEN;
+                       if(!(ret2 = deflate(&out_state.zip_state.z_stream,
+                                           Z_PARTIAL_FLUSH)) == Z_OK)
+                               send_error("error compressing outgoing data - deflate returned: %s",
+                                          zError(ret2));
+
+                       if(!out_state.zip_state.z_stream.avail_out)
+                               send_error("error compressing outgoing data - avail_out == 0");
+                       if(out_state.zip_state.z_stream.avail_in)
+                               send_error("error compressing outgoing data - avail_in != 0");
+
+                       blen = BUFLEN - out_state.zip_state.z_stream.avail_out;
+               }
+#endif
+
+
+               ret = check_error(write(REMOTE.fd, out_state.buf, blen), IO_WRITE, REMOTE.fd);
+               if(ret < blen)
+               {
+                       /* write incomplete, register write cb */
+                       REMOTE.write_cb = write_net;
+                       /*  deregister read_cb */
+                       LOCAL.read_cb = NULL;
+                       out_state.ofs = ret;
+                       out_state.len = blen - ret;
+                       return;
+               }
+#if defined(HAVE_LIBZ) 
+               if(out_state.zip)
+                       buf = tmp_buf;
+#endif
+       }
+
+}
+
+void
+write_net(void)
+{
+       int ret;
+
+       assert(out_state.len);
+
+       if(!(ret = check_error(write(REMOTE.fd,
+                                    (out_state.buf + out_state.ofs),
+                                    out_state.len), IO_WRITE, REMOTE.fd)))
+               return;         /* no data waiting */
+
+       out_state.len -= ret;
+
+       if(!out_state.len)
+       {
+               /* write completed, de-register write cb */
+               REMOTE.write_cb = NULL;
+               /* reregister read_cb */
+               LOCAL.read_cb = read_data;
+               out_state.ofs = 0;
+       }
+       else
+               out_state.ofs += ret;
+}
+
+void
+read_net(void)
+{
+       int ret;
+       int ret2;
+       unsigned char *buf = in_state.buf;
+       int blen;
+       ret2 = -1;
+       assert(!in_state.len);
+
+#if defined(HAVE_LIBZ)
+       if(in_state.zip)
+               buf = tmp_buf;
+#endif
+
+       while ((ret = check_error(read(REMOTE.fd, buf, READLEN), IO_READ, REMOTE.fd)))
+       {
+               blen = ret;
+#ifdef HAVE_LIBZ
+               if(in_state.zip)
+               {
+                       /* decompress data */
+                       in_state.zip_state.z_stream.next_in = buf;
+                       in_state.zip_state.z_stream.avail_in = ret;
+                       in_state.zip_state.z_stream.next_out = in_state.buf;
+                       in_state.zip_state.z_stream.avail_out = BUFLEN;
+
+                       while (in_state.zip_state.z_stream.avail_in)
+                       {
+                               if((ret2 = inflate(&in_state.zip_state.z_stream,
+                                                  Z_NO_FLUSH)) != Z_OK)
+                               {
+                                       if(!strncmp("ERROR ", (char *)buf, 6))
+                                               send_error("Received uncompressed ERROR");
+                                       send_error("Inflate failed: %s", zError(ret2));
+                               }
+                               blen = BUFLEN - in_state.zip_state.z_stream.avail_out;
+
+                               if(in_state.zip_state.z_stream.avail_in)
+                               {
+                                       if(blen)
+                                       {
+                                               send_data_blocking(LOCAL.fd, in_state.buf, blen);
+                                               blen = 0;
+                                       }
+
+                                       in_state.zip_state.z_stream.next_out = in_state.buf;
+                                       in_state.zip_state.z_stream.avail_out = BUFLEN;
+                               }
+                       }
+
+                       if(!blen)
+                               return; /* that didn't generate any decompressed input.. */
+               }
+#endif
+
+               ret = check_error(write(LOCAL.fd, in_state.buf, blen), IO_WRITE, LOCAL.fd);
+
+               if(ret < blen)
+               {
+                       in_state.ofs = ret;
+                       in_state.len = blen - ret;
+                       /* write incomplete, register write cb */
+                       LOCAL.write_cb = write_data;
+                       /* deregister read_cb */
+                       REMOTE.read_cb = NULL;
+                       return;
+               }
+#if defined(HAVE_LIBZ)
+               if(in_state.zip)
+                       buf = tmp_buf;
+#endif
+       }
+}
+
+void
+write_data(void)
+{
+       int ret;
+
+       assert(in_state.len);
+
+       if(!(ret = check_error(write(LOCAL.fd,
+                                    (in_state.buf + in_state.ofs),
+                                    in_state.len), IO_WRITE, LOCAL.fd)))
+               return;
+
+       in_state.len -= ret;
+
+       if(!in_state.len)
+       {
+               /* write completed, de-register write cb */
+               LOCAL.write_cb = NULL;
+               /* reregister read_cb */
+               REMOTE.read_cb = read_net;
+               in_state.ofs = 0;
+       }
+       else
+               in_state.ofs += ret;
+}
+
+int
+check_error(int ret, int io, int fd)
+{
+       if(ret > 0)             /* no error */
+               return ret;
+       if(ret == 0)            /* EOF */
+       {
+               send_error("%s failed on %s: EOF", IO_TYPE(io), FD_NAME(fd));
+               exit(1);        /* NOTREACHED */
+       }
+
+       /* ret == -1.. */
+       switch (errno)
+       {
+       case EINPROGRESS:
+       case EWOULDBLOCK:
+#if EAGAIN != EWOULDBLOCK
+       case EAGAIN:
+#endif
+       case EALREADY:
+       case EINTR:
+#ifdef ERESTART
+       case ERESTART:
+#endif
+               /* non-fatal error, 0 bytes read */
+               return 0;
+       }
+
+       /* fatal error */
+       send_error("%s failed on %s: %s", IO_TYPE(io), FD_NAME(fd), strerror(errno));
+       exit(1);                /* NOTREACHED */
+}
diff --git a/servlink/io.h b/servlink/io.h
new file mode 100644 (file)
index 0000000..da2126a
--- /dev/null
@@ -0,0 +1,48 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, servlink/io.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: io.h 6 2005-09-10 01:02:21Z nenolod $
+ */
+
+#ifndef INCLUDED_servlink_io_h
+#define INCLUDED_servlink_io_h
+
+#include "control.h"
+
+#define IO_READ                 0
+#define IO_WRITE                1
+#define IO_SELECT               2
+
+#define IO_TYPE(io)     ((io==IO_SELECT)?"select": \
+                         ((io==IO_WRITE)?"write":"read"))
+
+#define FD_NAME(fd)     (fd_name(fd))
+
+extern void io_loop(int nfds);
+extern void write_data(void);
+extern void read_data(void);
+extern void write_ctrl(void);
+extern void read_ctrl(void);
+extern void write_net(void);
+extern void read_net(void);
+extern void send_error(const char *, ...);
+extern void send_data_blocking(int fd, unsigned char *data, int datalen);
+extern cmd_handler process_recvq;
+extern cmd_handler process_sendq;
+extern cmd_handler send_zipstats;
+
+#endif /* INCLUDED_servlink_io_h */
diff --git a/servlink/servlink.c b/servlink/servlink.c
new file mode 100644 (file)
index 0000000..1276200
--- /dev/null
@@ -0,0 +1,121 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, servlink/servlink.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.
+ *
+ *   $Id: servlink.c 6 2005-09-10 01:02:21Z nenolod $
+ */
+
+#include "setup.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifdef HAVE_LIBZ
+#include <zlib.h>
+#endif
+
+#include "servlink.h"
+#include "io.h"
+#include "control.h"
+
+static void usage(void);
+
+struct slink_state in_state;
+struct slink_state out_state;
+
+struct fd_table fds[3] = {
+       {0, read_ctrl, NULL},   /* ctrl */
+       {0, NULL, NULL},        /* data */
+       {0, NULL, NULL},        /* net */
+};
+
+/* usage();
+ *
+ * Display usage message
+ */
+static void
+usage(void)
+{
+       fprintf(stderr, "ircd-ratbox server link v1.2\n");
+       fprintf(stderr, "2004-03-02\n");
+       fprintf(stderr, "\n");
+       fprintf(stderr, "This program is called by the ircd-ratbox ircd.\n");
+       fprintf(stderr, "It cannot be used on its own.\n");
+       exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+       int max_fd = 0;
+       int i, x;
+#ifdef SERVLINK_DEBUG
+       int GDBAttached = 0;
+
+       while (!GDBAttached)
+               sleep(1);
+#endif
+
+       /* Make sure we are running under ircd.. */
+       
+       if(argc != 4 || strcmp(argv[0], "-slink"))
+               usage();        /* exits */
+
+
+       for (i = 0; i < 3; i++)
+       {
+               fds[i].fd = atoi(argv[i + 1]);
+               if(fds[i].fd < 0)
+                       exit(1);
+       }
+
+       for (i = 0; i < 3; i++)
+       {               
+               /* XXX: Hack alert...we need to do dup2() here for some dumb
+                * platforms (Solaris) that don't like select using fds > 255
+                */
+
+               if(fds[i].fd >= 255)
+               {
+                       for(x = 0; x < 255; x++)
+                       {
+                               if(x != fds[0].fd && x != fds[1].fd && x != fds[2].fd)
+                               {
+                                       if(dup2(fds[i].fd, x) < 0)
+                                               exit(1);
+                                       close(fds[i].fd);
+                                       fds[i].fd = x;
+                                       break;
+                               }
+                       }
+               }               
+               fcntl(fds[i].fd, F_SETFL, O_NONBLOCK);
+               if(fds[i].fd > max_fd)
+                       max_fd = fds[i].fd;
+       }
+       
+       /* enter io loop */
+       io_loop(max_fd + 1);
+
+       /* NOTREACHED */
+       return (0);
+}                              /* main() */
diff --git a/servlink/servlink.h b/servlink/servlink.h
new file mode 100644 (file)
index 0000000..a0f37de
--- /dev/null
@@ -0,0 +1,83 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, servlink/servlink.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: servlink.h 1285 2006-05-05 15:03:53Z nenolod $
+ */
+
+#ifndef INCLUDED_servlink_servlink_h
+#define INCLUDED_servlink_servlink_h
+
+#include "setup.h"
+
+#ifdef HAVE_LIBZ
+#include <zlib.h>
+#endif
+
+/* do not use stdin/out/err, as it seems to break on solaris */
+#define CONTROL               fds[0]
+#define LOCAL                 fds[1]
+#define REMOTE                 fds[2]
+
+#undef  SERVLINK_DEBUG
+
+#define READLEN                  16384
+
+#ifdef HAVE_LIBZ
+#define BUFLEN                   READLEN * 6   /* allow for decompression */
+#else
+#define BUFLEN                   READLEN
+#endif
+
+
+#ifdef HAVE_LIBZ
+struct zip_state
+{
+       z_stream z_stream;
+       int level;              /* compression level */
+};
+#endif
+
+struct slink_state
+{
+       unsigned int crypt:1;
+       unsigned int zip:1;
+       unsigned int active:1;
+
+       unsigned char buf[BUFLEN * 2];
+       unsigned int ofs;
+       unsigned int len;
+
+#ifdef HAVE_LIBZ
+       struct zip_state zip_state;
+#endif
+};
+
+
+typedef void (io_callback) (void);
+
+struct fd_table
+{
+       int fd;
+       io_callback *read_cb;
+       io_callback *write_cb;
+};
+
+extern struct slink_state in_state;
+extern struct slink_state out_state;
+extern struct fd_table fds[3];
+
+#endif /* INCLUDED_servlink_servlink_h */
diff --git a/src/.cvsignore b/src/.cvsignore
new file mode 100644 (file)
index 0000000..2eb5775
--- /dev/null
@@ -0,0 +1,6 @@
+Makefile
+y.tab.*
+lex.yy.c
+ircd
+version.c.last
+version.c
diff --git a/src/.depend b/src/.depend
new file mode 100644 (file)
index 0000000..3cc89ee
--- /dev/null
@@ -0,0 +1,587 @@
+cache.o: cache.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/ircd_defs.h \
+  ../include/s_log.h ../include/ircd_defs.h ../include/send.h \
+  ../include/common.h ../include/s_conf.h ../include/class.h \
+  ../libcharybdis/tools.h ../include/client.h ../libcharybdis/linebuf.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/res.h \
+  ../include/common.h ../libcharybdis/commio.h ../include/setup.h \
+  ../include/config.h ../include/ircd_defs.h ../include/reslib.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/ircd.h \
+  ../libcharybdis/memory.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/snomask.h ../include/patricia.h \
+  ../include/numeric.h ../libcharybdis/tools.h ../include/client.h \
+  ../libcharybdis/memory.h ../libcharybdis/balloc.h \
+  ../libcharybdis/event.h ../include/hash.h ../include/cache.h \
+  ../include/sprintf_irc.h
+channel.o: channel.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../include/client.h ../libcharybdis/linebuf.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/res.h \
+  ../include/common.h ../libcharybdis/commio.h ../include/setup.h \
+  ../include/config.h ../include/ircd_defs.h ../include/reslib.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/ircd.h \
+  ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/snomask.h \
+  ../include/client.h ../include/common.h ../include/hash.h \
+  ../include/hook.h ../include/irc_string.h ../include/sprintf_irc.h \
+  ../include/ircd.h ../include/numeric.h ../include/s_serv.h \
+  ../include/s_user.h ../include/send.h ../include/whowas.h \
+  ../include/s_conf.h ../include/class.h ../include/patricia.h \
+  ../include/numeric.h ../include/s_newconf.h ../libcharybdis/event.h \
+  ../libcharybdis/memory.h ../libcharybdis/balloc.h ../include/s_log.h
+chmode.o: chmode.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../include/client.h ../libcharybdis/linebuf.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/res.h \
+  ../include/common.h ../libcharybdis/commio.h ../include/setup.h \
+  ../include/config.h ../include/ircd_defs.h ../include/reslib.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/ircd.h \
+  ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/snomask.h \
+  ../include/client.h ../include/common.h ../include/hash.h \
+  ../include/hook.h ../include/irc_string.h ../include/sprintf_irc.h \
+  ../include/ircd.h ../include/numeric.h ../include/s_serv.h \
+  ../include/s_user.h ../include/send.h ../include/whowas.h \
+  ../include/s_conf.h ../include/class.h ../include/patricia.h \
+  ../include/numeric.h ../include/s_newconf.h ../libcharybdis/event.h \
+  ../libcharybdis/memory.h ../libcharybdis/balloc.h ../include/s_log.h
+class.o: class.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/config.h \
+  ../libcharybdis/tools.h ../include/class.h ../libcharybdis/tools.h \
+  ../include/client.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../libcharybdis/linebuf.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/res.h ../include/common.h \
+  ../libcharybdis/commio.h ../include/setup.h ../include/config.h \
+  ../include/ircd_defs.h ../include/reslib.h ../include/irc_string.h \
+  ../include/sprintf_irc.h ../include/ircd.h ../libcharybdis/memory.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/snomask.h \
+  ../include/client.h ../include/common.h ../include/ircd.h \
+  ../include/numeric.h ../include/s_conf.h ../include/class.h \
+  ../include/patricia.h ../include/numeric.h ../include/s_newconf.h \
+  ../include/send.h ../include/irc_string.h ../libcharybdis/memory.h \
+  ../include/patricia.h
+client.o: client.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/config.h \
+  ../libcharybdis/tools.h ../include/client.h ../include/ircd_defs.h \
+  ../include/s_log.h ../include/send.h ../libcharybdis/linebuf.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/res.h \
+  ../include/common.h ../libcharybdis/commio.h ../include/setup.h \
+  ../include/config.h ../include/ircd_defs.h ../include/reslib.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/ircd.h \
+  ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/snomask.h \
+  ../include/client.h ../include/class.h ../include/common.h \
+  ../libcharybdis/event.h ../include/hash.h ../include/irc_string.h \
+  ../include/sprintf_irc.h ../include/ircd.h ../include/s_gline.h \
+  ../include/numeric.h ../include/packet.h ../include/s_auth.h \
+  ../libcharybdis/commio.h ../include/s_conf.h ../include/class.h \
+  ../include/patricia.h ../include/numeric.h ../include/s_newconf.h \
+  ../include/s_log.h ../include/s_serv.h ../include/s_stats.h \
+  ../include/send.h ../include/whowas.h ../include/s_user.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/memory.h \
+  ../include/hostmask.h ../libcharybdis/balloc.h ../include/listener.h \
+  ../include/hook.h ../include/msg.h ../include/monitor.h
+getopt.o: getopt.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/ircd_getopt.h
+hash.o: hash.c ../include/stdinc.h ../include/config.h ../include/setup.h \
+  ../include/defaults.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/ircd_defs.h ../include/send.h ../libcharybdis/tools.h \
+  ../include/s_conf.h ../include/class.h ../libcharybdis/tools.h \
+  ../include/client.h ../libcharybdis/linebuf.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/res.h ../include/common.h \
+  ../libcharybdis/commio.h ../include/setup.h ../include/config.h \
+  ../include/ircd_defs.h ../include/reslib.h ../include/irc_string.h \
+  ../include/sprintf_irc.h ../include/ircd.h ../libcharybdis/memory.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/snomask.h \
+  ../include/patricia.h ../include/numeric.h ../include/channel.h \
+  ../include/client.h ../include/common.h ../include/hash.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../include/send.h ../libcharybdis/memory.h ../include/msg.h \
+  ../include/cache.h ../include/s_newconf.h
+hook.o: hook.c ../include/stdinc.h ../include/config.h ../include/setup.h \
+  ../include/defaults.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/s_log.h ../include/ircd_defs.h ../include/send.h \
+  ../include/setup.h ../libcharybdis/balloc.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../libcharybdis/tools.h ../include/hook.h \
+  ../include/irc_string.h
+hostmask.o: hostmask.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/ircd_defs.h \
+  ../include/send.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/tools.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/s_conf.h ../include/class.h ../libcharybdis/tools.h \
+  ../include/client.h ../libcharybdis/linebuf.h ../include/channel.h \
+  ../include/res.h ../include/common.h ../libcharybdis/commio.h \
+  ../include/config.h ../include/reslib.h ../include/irc_string.h \
+  ../include/sprintf_irc.h ../include/ircd.h ../libcharybdis/memory.h \
+  ../include/snomask.h ../include/patricia.h ../include/numeric.h \
+  ../include/hostmask.h ../include/numeric.h ../include/send.h \
+  ../include/irc_string.h
+irc_string.o: irc_string.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/sprintf_irc.h \
+  ../libcharybdis/tools.h ../include/irc_string.h ../include/ircd_defs.h \
+  ../include/s_log.h ../include/send.h ../include/client.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/common.h ../libcharybdis/commio.h \
+  ../include/setup.h ../include/config.h ../include/ircd_defs.h \
+  ../include/reslib.h ../include/irc_string.h ../include/sprintf_irc.h \
+  ../include/ircd.h ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/snomask.h \
+  ../include/client.h ../libcharybdis/memory.h ../include/setup.h
+ircd.o: ircd.c ../include/stdinc.h ../include/config.h ../include/setup.h \
+  ../include/defaults.h ../include/setup.h ../include/config.h \
+  ../libcharybdis/tools.h ../include/ircd.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/ircd_defs.h ../include/send.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../include/channel.h ../include/class.h \
+  ../include/client.h ../libcharybdis/linebuf.h ../include/channel.h \
+  ../include/res.h ../include/common.h ../libcharybdis/commio.h \
+  ../include/config.h ../include/reslib.h ../include/irc_string.h \
+  ../include/sprintf_irc.h ../include/ircd.h ../include/snomask.h \
+  ../include/client.h ../include/common.h ../libcharybdis/event.h \
+  ../include/hash.h ../include/irc_string.h ../include/ircd_signal.h \
+  ../include/sprintf_irc.h ../include/s_gline.h ../include/msg.h \
+  ../include/hostmask.h ../include/numeric.h ../include/parse.h \
+  ../include/res.h ../include/restart.h ../include/s_auth.h \
+  ../libcharybdis/commio.h ../include/s_conf.h ../include/class.h \
+  ../include/patricia.h ../include/numeric.h ../include/s_log.h \
+  ../include/s_serv.h ../include/s_user.h ../include/s_stats.h \
+  ../include/scache.h ../include/send.h ../include/whowas.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../include/hook.h ../libcharybdis/memory.h ../include/hook.h \
+  ../include/ircd_getopt.h ../libcharybdis/balloc.h ../include/newconf.h \
+  ../include/patricia.h ../include/reject.h ../include/s_newconf.h \
+  ../include/cache.h ../include/monitor.h ../libcharybdis/libcharybdis.h \
+  ../include/stdinc.h ../include/res.h ../include/numeric.h \
+  ../libcharybdis/linebuf.h ../include/sprintf_irc.h \
+  ../libcharybdis/commio.h ../libcharybdis/event.h \
+  ../include/patchlevel.h ../include/serno.h
+ircd_signal.o: ircd_signal.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/ircd_signal.h \
+  ../include/ircd.h ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/ircd_defs.h \
+  ../include/send.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/tools.h ../libcharybdis/memory.h ../include/restart.h \
+  ../include/s_log.h ../libcharybdis/memory.h ../libcharybdis/commio.h \
+  ../include/config.h ../include/s_conf.h ../include/class.h \
+  ../include/client.h ../libcharybdis/linebuf.h ../include/channel.h \
+  ../include/res.h ../include/common.h ../libcharybdis/commio.h \
+  ../include/reslib.h ../include/irc_string.h ../include/sprintf_irc.h \
+  ../include/ircd.h ../include/snomask.h ../include/patricia.h \
+  ../include/numeric.h ../include/client.h ../include/send.h
+ircd_state.o: ircd_state.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/setup.h \
+  ../include/config.h ../include/client.h ../include/ircd_defs.h \
+  ../include/s_log.h ../include/send.h ../libcharybdis/linebuf.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/res.h \
+  ../include/common.h ../libcharybdis/commio.h ../include/setup.h \
+  ../include/config.h ../include/ircd_defs.h ../include/reslib.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/ircd.h \
+  ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/snomask.h \
+  ../include/client.h ../libcharybdis/tools.h ../include/ircd.h \
+  ../include/channel.h ../include/class.h ../include/common.h \
+  ../libcharybdis/event.h ../include/hash.h ../include/irc_string.h \
+  ../include/ircd_signal.h ../include/sprintf_irc.h ../include/s_gline.h \
+  ../include/msg.h ../include/hostmask.h ../include/numeric.h \
+  ../include/parse.h ../include/res.h ../include/restart.h \
+  ../include/s_auth.h ../libcharybdis/commio.h ../include/s_conf.h \
+  ../include/class.h ../include/patricia.h ../include/numeric.h \
+  ../include/s_log.h ../include/s_serv.h ../include/s_user.h \
+  ../include/s_stats.h ../include/scache.h ../include/send.h \
+  ../include/whowas.h ../include/modules.h ../include/parse.h \
+  ../include/msg.h ../include/hook.h ../libcharybdis/memory.h \
+  ../include/hook.h ../include/ircd_getopt.h ../libcharybdis/balloc.h \
+  ../include/newconf.h ../include/patricia.h ../include/reject.h \
+  ../include/s_newconf.h ../include/cache.h ../include/monitor.h \
+  ../libcharybdis/libcharybdis.h ../include/stdinc.h ../include/res.h \
+  ../include/numeric.h ../libcharybdis/linebuf.h ../include/sprintf_irc.h \
+  ../libcharybdis/commio.h ../libcharybdis/event.h \
+  ../include/patchlevel.h ../include/serno.h
+kdparse.o: kdparse.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/s_log.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../include/s_conf.h ../include/class.h \
+  ../libcharybdis/tools.h ../include/client.h ../libcharybdis/linebuf.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/res.h \
+  ../include/common.h ../libcharybdis/commio.h ../include/setup.h \
+  ../include/config.h ../include/ircd_defs.h ../include/reslib.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/ircd.h \
+  ../libcharybdis/memory.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/snomask.h ../include/patricia.h \
+  ../include/numeric.h ../include/s_newconf.h ../include/hostmask.h \
+  ../include/client.h ../include/irc_string.h ../libcharybdis/memory.h \
+  ../include/hash.h
+listener.o: listener.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/setup.h \
+  ../include/listener.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../include/client.h ../libcharybdis/linebuf.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/res.h \
+  ../include/common.h ../libcharybdis/commio.h ../include/setup.h \
+  ../include/config.h ../include/ircd_defs.h ../include/reslib.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/ircd.h \
+  ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/snomask.h \
+  ../include/client.h ../include/irc_string.h ../include/sprintf_irc.h \
+  ../include/ircd.h ../include/ircd_defs.h ../include/numeric.h \
+  ../libcharybdis/commio.h ../include/s_conf.h ../include/class.h \
+  ../include/patricia.h ../include/numeric.h ../include/s_newconf.h \
+  ../include/s_stats.h ../include/send.h ../libcharybdis/memory.h \
+  ../include/s_auth.h ../include/reject.h
+match.o: match.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/config.h \
+  ../include/client.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../libcharybdis/linebuf.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/res.h ../include/common.h \
+  ../libcharybdis/commio.h ../include/setup.h ../include/config.h \
+  ../include/ircd_defs.h ../include/reslib.h ../include/irc_string.h \
+  ../include/sprintf_irc.h ../include/ircd.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/snomask.h ../include/client.h \
+  ../include/ircd.h ../include/irc_string.h
+modules.o: modules.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/modules.h \
+  ../include/parse.h ../libcharybdis/tools.h ../include/msg.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/ircd_defs.h ../include/send.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../include/hook.h ../include/s_log.h \
+  ../include/ircd.h ../include/client.h ../libcharybdis/linebuf.h \
+  ../include/channel.h ../include/res.h ../include/common.h \
+  ../libcharybdis/commio.h ../include/config.h ../include/reslib.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/ircd.h \
+  ../include/snomask.h ../include/client.h ../include/send.h \
+  ../include/s_conf.h ../include/class.h ../include/patricia.h \
+  ../include/numeric.h ../include/s_newconf.h ../include/numeric.h \
+  ../include/parse.h ../include/ircd_defs.h ../include/irc_string.h \
+  ../libcharybdis/memory.h ../libcharybdis/tools.h \
+  ../include/sprintf_irc.h
+monitor.o: monitor.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/client.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../libcharybdis/linebuf.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/res.h ../include/common.h \
+  ../libcharybdis/commio.h ../include/setup.h ../include/config.h \
+  ../include/ircd_defs.h ../include/reslib.h ../include/irc_string.h \
+  ../include/sprintf_irc.h ../include/ircd.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/snomask.h ../include/client.h \
+  ../libcharybdis/memory.h ../libcharybdis/balloc.h ../include/monitor.h \
+  ../include/hash.h ../libcharybdis/event.h ../include/numeric.h
+newconf.o: newconf.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/ircd_defs.h \
+  ../include/send.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/tools.h ../libcharybdis/memory.h ../include/newconf.h \
+  ../libcharybdis/tools.h ../include/client.h ../libcharybdis/linebuf.h \
+  ../include/channel.h ../include/res.h ../include/common.h \
+  ../libcharybdis/commio.h ../include/config.h ../include/reslib.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/ircd.h \
+  ../libcharybdis/memory.h ../include/snomask.h ../libcharybdis/tools.h \
+  ../include/ircd_defs.h ../include/sprintf_irc.h ../include/common.h \
+  ../include/s_log.h ../include/s_conf.h ../include/class.h \
+  ../include/patricia.h ../include/numeric.h ../include/s_user.h \
+  ../include/s_newconf.h ../include/send.h ../include/setup.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../include/hook.h ../include/listener.h ../include/hostmask.h \
+  ../include/s_serv.h ../libcharybdis/event.h ../include/hash.h \
+  ../include/cache.h ../include/ircd.h ../include/snomask.h
+numeric.o: numeric.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/setup.h \
+  ../include/config.h ../include/s_conf.h ../include/ircd_defs.h \
+  ../include/s_log.h ../include/send.h ../include/class.h \
+  ../libcharybdis/tools.h ../include/client.h ../libcharybdis/linebuf.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/res.h \
+  ../include/common.h ../libcharybdis/commio.h ../include/setup.h \
+  ../include/config.h ../include/ircd_defs.h ../include/reslib.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/ircd.h \
+  ../libcharybdis/memory.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/snomask.h ../include/patricia.h \
+  ../include/numeric.h ../include/numeric.h ../include/irc_string.h \
+  ../include/common.h ../libcharybdis/memory.h messages.tab
+packet.o: packet.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../libcharybdis/commio.h ../include/setup.h ../include/config.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/ircd_defs.h \
+  ../include/send.h ../include/s_conf.h ../include/class.h \
+  ../libcharybdis/tools.h ../include/client.h ../libcharybdis/linebuf.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/res.h \
+  ../include/common.h ../libcharybdis/commio.h ../include/reslib.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/ircd.h \
+  ../libcharybdis/memory.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/snomask.h ../include/patricia.h \
+  ../include/numeric.h ../include/s_serv.h ../include/client.h \
+  ../include/common.h ../include/ircd.h ../include/parse.h \
+  ../include/packet.h ../include/irc_string.h ../libcharybdis/memory.h \
+  ../include/hook.h ../include/send.h
+parse.o: parse.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/parse.h \
+  ../libcharybdis/tools.h ../include/client.h ../include/ircd_defs.h \
+  ../include/s_log.h ../include/send.h ../libcharybdis/linebuf.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/res.h \
+  ../include/common.h ../libcharybdis/commio.h ../include/setup.h \
+  ../include/config.h ../include/ircd_defs.h ../include/reslib.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/ircd.h \
+  ../libcharybdis/memory.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/snomask.h ../include/client.h \
+  ../include/channel.h ../include/common.h ../include/hash.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/ircd.h \
+  ../include/numeric.h ../include/s_log.h ../include/s_stats.h \
+  ../include/send.h ../include/msg.h ../include/s_conf.h \
+  ../include/class.h ../include/patricia.h ../include/numeric.h \
+  ../libcharybdis/memory.h ../include/s_serv.h
+patricia.o: patricia.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/config.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/ircd_defs.h \
+  ../include/send.h ../include/patricia.h ../include/class.h \
+  ../libcharybdis/tools.h ../include/client.h ../libcharybdis/linebuf.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/res.h \
+  ../include/common.h ../libcharybdis/commio.h ../include/setup.h \
+  ../include/config.h ../include/ircd_defs.h ../include/reslib.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/ircd.h \
+  ../libcharybdis/memory.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/snomask.h ../include/numeric.h \
+  ../libcharybdis/balloc.h
+res.o: res.c ../include/stdinc.h ../include/config.h ../include/setup.h \
+  ../include/defaults.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/ircd_defs.h ../include/send.h ../include/common.h \
+  ../include/ircd.h ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../include/ircd_defs.h ../include/setup.h ../libcharybdis/balloc.h \
+  ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../libcharybdis/commio.h ../include/config.h ../include/res.h \
+  ../include/common.h ../libcharybdis/commio.h ../include/reslib.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/ircd.h \
+  ../include/reslib.h ../libcharybdis/tools.h ../libcharybdis/event.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/numeric.h
+reslib.o: reslib.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/ircd_defs.h \
+  ../include/s_log.h ../include/ircd_defs.h ../include/send.h \
+  ../include/common.h ../include/ircd.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../include/ircd_defs.h ../include/setup.h \
+  ../libcharybdis/balloc.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../libcharybdis/commio.h ../include/config.h \
+  ../include/res.h ../include/common.h ../libcharybdis/commio.h \
+  ../include/reslib.h ../include/irc_string.h ../include/sprintf_irc.h \
+  ../include/ircd.h ../include/reslib.h ../libcharybdis/tools.h \
+  ../libcharybdis/event.h ../include/irc_string.h \
+  ../include/sprintf_irc.h
+reject.o: reject.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/config.h \
+  ../include/patricia.h ../include/class.h ../libcharybdis/tools.h \
+  ../include/client.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../libcharybdis/linebuf.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/res.h ../include/common.h \
+  ../libcharybdis/commio.h ../include/setup.h ../include/config.h \
+  ../include/ircd_defs.h ../include/reslib.h ../include/irc_string.h \
+  ../include/sprintf_irc.h ../include/ircd.h ../libcharybdis/memory.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/snomask.h \
+  ../include/numeric.h ../include/client.h ../include/s_conf.h \
+  ../include/patricia.h ../libcharybdis/event.h ../libcharybdis/tools.h \
+  ../include/reject.h ../include/s_stats.h ../include/msg.h
+restart.o: restart.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/restart.h ../include/common.h ../include/ircd.h \
+  ../libcharybdis/tools.h ../libcharybdis/memory.h ../include/ircd_defs.h \
+  ../include/s_log.h ../include/ircd_defs.h ../include/send.h \
+  ../include/setup.h ../libcharybdis/balloc.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../include/send.h ../include/s_log.h \
+  ../include/client.h ../libcharybdis/linebuf.h ../include/channel.h \
+  ../include/res.h ../include/common.h ../libcharybdis/commio.h \
+  ../include/config.h ../include/reslib.h ../include/irc_string.h \
+  ../include/sprintf_irc.h ../include/ircd.h ../include/snomask.h \
+  ../include/client.h ../libcharybdis/memory.h
+s_auth.o: s_auth.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/config.h \
+  ../libcharybdis/tools.h ../include/s_auth.h ../include/res.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../include/common.h ../libcharybdis/commio.h ../include/setup.h \
+  ../include/config.h ../include/ircd_defs.h ../include/reslib.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/ircd.h \
+  ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../libcharybdis/balloc.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../include/s_conf.h ../include/class.h \
+  ../include/client.h ../libcharybdis/linebuf.h ../include/channel.h \
+  ../include/snomask.h ../include/patricia.h ../include/numeric.h \
+  ../include/client.h ../include/common.h ../libcharybdis/event.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/ircd.h \
+  ../include/numeric.h ../include/packet.h ../include/res.h \
+  ../libcharybdis/commio.h ../include/s_log.h ../include/s_stats.h \
+  ../include/send.h ../libcharybdis/memory.h ../include/hook.h
+s_conf.o: s_conf.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/ircd_defs.h \
+  ../include/s_log.h ../include/ircd_defs.h ../include/send.h \
+  ../libcharybdis/tools.h ../include/s_conf.h ../include/class.h \
+  ../libcharybdis/tools.h ../include/client.h ../libcharybdis/linebuf.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/res.h \
+  ../include/common.h ../libcharybdis/commio.h ../include/setup.h \
+  ../include/config.h ../include/ircd_defs.h ../include/reslib.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/ircd.h \
+  ../libcharybdis/memory.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/snomask.h ../include/patricia.h \
+  ../include/numeric.h ../include/s_newconf.h ../include/s_serv.h \
+  ../include/s_stats.h ../include/channel.h ../include/class.h \
+  ../include/client.h ../include/common.h ../libcharybdis/event.h \
+  ../include/hash.h ../include/irc_string.h ../include/sprintf_irc.h \
+  ../include/ircd.h ../include/listener.h ../include/hostmask.h \
+  ../include/modules.h ../include/parse.h ../include/msg.h \
+  ../include/hook.h ../include/numeric.h ../libcharybdis/commio.h \
+  ../include/s_log.h ../include/send.h ../include/s_gline.h \
+  ../libcharybdis/memory.h ../libcharybdis/balloc.h ../include/patricia.h \
+  ../include/reject.h ../include/cache.h
+s_newconf.o: s_newconf.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/ircd_defs.h \
+  ../include/s_log.h ../include/ircd_defs.h ../include/send.h \
+  ../include/common.h ../include/s_conf.h ../include/class.h \
+  ../libcharybdis/tools.h ../include/client.h ../libcharybdis/linebuf.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/res.h \
+  ../include/common.h ../libcharybdis/commio.h ../include/setup.h \
+  ../include/config.h ../include/ircd_defs.h ../include/reslib.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/ircd.h \
+  ../libcharybdis/memory.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/snomask.h ../include/patricia.h \
+  ../include/numeric.h ../include/s_newconf.h ../libcharybdis/tools.h \
+  ../include/client.h ../libcharybdis/memory.h ../include/s_serv.h \
+  ../include/send.h ../include/hostmask.h ../include/newconf.h \
+  ../include/hash.h ../libcharybdis/balloc.h ../libcharybdis/event.h \
+  ../include/sprintf_irc.h
+s_gline.o: s_gline.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../include/client.h ../libcharybdis/linebuf.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/res.h \
+  ../include/common.h ../libcharybdis/commio.h ../include/setup.h \
+  ../include/config.h ../include/ircd_defs.h ../include/reslib.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/ircd.h \
+  ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/snomask.h \
+  ../include/client.h ../include/common.h ../include/config.h \
+  ../include/irc_string.h ../include/ircd.h ../include/hostmask.h \
+  ../include/numeric.h ../libcharybdis/commio.h ../include/s_conf.h \
+  ../include/class.h ../include/patricia.h ../include/numeric.h \
+  ../include/scache.h ../include/send.h ../include/msg.h \
+  ../include/s_serv.h ../include/s_gline.h ../include/hash.h \
+  ../libcharybdis/event.h ../libcharybdis/memory.h
+s_log.o: s_log.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/ircd_defs.h \
+  ../include/s_log.h ../include/ircd_defs.h ../include/send.h \
+  ../include/s_log.h ../include/s_conf.h ../include/class.h \
+  ../libcharybdis/tools.h ../include/client.h ../libcharybdis/linebuf.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/res.h \
+  ../include/common.h ../libcharybdis/commio.h ../include/setup.h \
+  ../include/config.h ../include/ircd_defs.h ../include/reslib.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/ircd.h \
+  ../libcharybdis/memory.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/snomask.h ../include/patricia.h \
+  ../include/numeric.h ../include/sprintf_irc.h ../include/send.h \
+  ../include/client.h ../include/s_serv.h
+s_serv.o: s_serv.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/s_serv.h ../include/class.h ../libcharybdis/tools.h \
+  ../include/client.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../libcharybdis/linebuf.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/res.h ../include/common.h \
+  ../libcharybdis/commio.h ../include/setup.h ../include/config.h \
+  ../include/ircd_defs.h ../include/reslib.h ../include/irc_string.h \
+  ../include/sprintf_irc.h ../include/ircd.h ../libcharybdis/memory.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/snomask.h \
+  ../include/client.h ../include/common.h ../libcharybdis/event.h \
+  ../include/hash.h ../include/irc_string.h ../include/sprintf_irc.h \
+  ../include/ircd.h ../include/ircd_defs.h ../include/numeric.h \
+  ../include/packet.h ../include/res.h ../libcharybdis/commio.h \
+  ../include/s_conf.h ../include/class.h ../include/patricia.h \
+  ../include/numeric.h ../include/s_newconf.h ../include/s_log.h \
+  ../include/s_stats.h ../include/s_user.h ../include/scache.h \
+  ../include/send.h ../libcharybdis/memory.h ../include/channel.h \
+  ../include/hook.h ../include/msg.h
+s_stats.o: s_stats.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/s_stats.h \
+  ../include/client.h ../include/ircd_defs.h ../include/s_log.h \
+  ../include/send.h ../libcharybdis/linebuf.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/res.h ../include/common.h \
+  ../libcharybdis/commio.h ../include/setup.h ../include/config.h \
+  ../include/ircd_defs.h ../include/reslib.h ../include/irc_string.h \
+  ../include/sprintf_irc.h ../include/ircd.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/snomask.h ../include/client.h \
+  ../include/irc_string.h ../include/ircd.h ../include/numeric.h \
+  ../libcharybdis/commio.h ../include/send.h ../libcharybdis/memory.h \
+  ../include/s_conf.h ../include/class.h ../include/patricia.h \
+  ../include/numeric.h ../include/s_newconf.h ../include/whowas.h \
+  ../include/hash.h ../include/scache.h ../include/reject.h
+s_user.o: s_user.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../libcharybdis/tools.h \
+  ../include/s_user.h ../include/channel.h ../include/ircd_defs.h \
+  ../include/s_log.h ../include/send.h ../include/class.h \
+  ../libcharybdis/tools.h ../include/client.h ../libcharybdis/linebuf.h \
+  ../libcharybdis/tools.h ../include/channel.h ../include/res.h \
+  ../include/common.h ../libcharybdis/commio.h ../include/setup.h \
+  ../include/config.h ../include/ircd_defs.h ../include/reslib.h \
+  ../include/irc_string.h ../include/sprintf_irc.h ../include/ircd.h \
+  ../libcharybdis/memory.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/snomask.h ../include/client.h \
+  ../include/common.h ../include/hash.h ../include/irc_string.h \
+  ../include/sprintf_irc.h ../include/ircd.h ../include/listener.h \
+  ../include/msg.h ../include/numeric.h ../libcharybdis/commio.h \
+  ../include/s_conf.h ../include/class.h ../include/patricia.h \
+  ../include/numeric.h ../include/s_newconf.h ../include/s_log.h \
+  ../include/s_serv.h ../include/s_stats.h ../include/scache.h \
+  ../include/send.h ../include/supported.h ../include/whowas.h \
+  ../libcharybdis/memory.h ../include/packet.h ../include/reject.h \
+  ../include/cache.h ../include/hook.h ../include/monitor.h \
+  ../include/snomask.h
+scache.o: scache.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/common.h ../libcharybdis/commio.h \
+  ../include/setup.h ../include/config.h ../include/ircd_defs.h \
+  ../include/reslib.h ../include/irc_string.h ../include/sprintf_irc.h \
+  ../include/ircd.h ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/snomask.h \
+  ../include/client.h ../include/common.h ../include/irc_string.h \
+  ../include/ircd.h ../include/numeric.h ../include/send.h \
+  ../include/scache.h ../libcharybdis/memory.h
+send.o: send.c ../include/stdinc.h ../include/config.h ../include/setup.h \
+  ../include/defaults.h ../libcharybdis/tools.h ../include/send.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../include/channel.h ../include/class.h ../libcharybdis/tools.h \
+  ../include/client.h ../libcharybdis/linebuf.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/res.h ../include/common.h \
+  ../libcharybdis/commio.h ../include/setup.h ../include/config.h \
+  ../include/ircd_defs.h ../include/reslib.h ../include/irc_string.h \
+  ../include/sprintf_irc.h ../include/ircd.h ../libcharybdis/memory.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/snomask.h \
+  ../include/client.h ../include/common.h ../include/irc_string.h \
+  ../include/ircd.h ../include/numeric.h ../libcharybdis/commio.h \
+  ../include/s_serv.h ../include/sprintf_irc.h ../include/s_conf.h \
+  ../include/class.h ../include/patricia.h ../include/numeric.h \
+  ../include/s_newconf.h ../libcharybdis/linebuf.h ../include/s_log.h \
+  ../libcharybdis/memory.h ../include/hook.h
+snomask.o: snomask.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/client.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../libcharybdis/linebuf.h ../libcharybdis/tools.h ../include/channel.h \
+  ../include/res.h ../include/common.h ../libcharybdis/commio.h \
+  ../include/setup.h ../include/config.h ../include/ircd_defs.h \
+  ../include/reslib.h ../include/irc_string.h ../include/sprintf_irc.h \
+  ../include/ircd.h ../libcharybdis/tools.h ../libcharybdis/memory.h \
+  ../libcharybdis/balloc.h ../libcharybdis/memory.h ../include/snomask.h \
+  ../include/client.h ../include/snomask.h
+whowas.o: whowas.c ../include/stdinc.h ../include/config.h \
+  ../include/setup.h ../include/defaults.h ../include/whowas.h \
+  ../include/ircd_defs.h ../include/s_log.h ../include/send.h \
+  ../include/client.h ../libcharybdis/linebuf.h ../libcharybdis/tools.h \
+  ../include/channel.h ../include/res.h ../include/common.h \
+  ../libcharybdis/commio.h ../include/setup.h ../include/config.h \
+  ../include/ircd_defs.h ../include/reslib.h ../include/irc_string.h \
+  ../include/sprintf_irc.h ../include/ircd.h ../libcharybdis/tools.h \
+  ../libcharybdis/memory.h ../libcharybdis/balloc.h \
+  ../libcharybdis/memory.h ../include/snomask.h ../include/client.h \
+  ../include/common.h ../include/hash.h ../include/irc_string.h \
+  ../include/ircd.h ../include/ircd_defs.h ../include/numeric.h \
+  ../include/s_serv.h ../include/s_user.h ../include/send.h \
+  ../include/s_conf.h ../include/class.h ../include/patricia.h \
+  ../include/numeric.h ../libcharybdis/memory.h
diff --git a/src/.indent.pro b/src/.indent.pro
new file mode 100644 (file)
index 0000000..ac7f7fc
--- /dev/null
@@ -0,0 +1,49 @@
+/* $Id: .indent.pro 813 2006-02-14 20:52:15Z nenolod $ */
+
+/* copy this file to the source dir then run indent file.c */
+
+--gnu-style
+
+/* This is the indent before the brace not inside the block. */
+--brace-indent0
+
+/* Indent case: by 2 and braces inside case by 0(then by 0)... */
+--case-brace-indentation0
+--case-indentation2
+
+--indent-level8
+
+/* Put while() on the brace from do... */
+--cuddle-do-while
+
+/* Disable an annoying format... */
+--no-space-after-function-call-names
+
+/* Disable an annoying format... */
+--dont-break-procedure-type
+
+/* Disable an annoying format... */
+--no-space-after-casts
+
+--line-length100
+
+/* typedefs */
+-T boolean_t
+-T node_t
+-T list_t
+-T tld_t
+-T kline_t
+-T EVH
+-T sra_t
+-T server_t
+-T user_t
+-T channel_t
+-T chanuser_t
+-T myuser_t
+-T mychan_t
+-T chanacs_t
+-T CONFIGENTRY
+-T CONFIGFILE
+-T Block
+-T MemBlock
+-T BlockHeap
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644 (file)
index 0000000..0306d03
--- /dev/null
@@ -0,0 +1,165 @@
+#
+# Makefile.in for ircd/src
+#
+# $Id: Makefile.in 1887 2006-08-29 13:42:56Z jilles $
+#
+CC             = @CC@
+INSTALL                = @INSTALL@
+INSTALL_BIN    = @INSTALL_PROGRAM@
+INSTALL_DATA   = @INSTALL_DATA@
+INSTALL_SUID   = @INSTALL_PROGRAM@ -o root -m 4755
+RM             = @RM@
+LEX            = @LEX@
+LEXLIB         = @LEXLIB@
+PICFLAGS       = @PICFLAGS@
+CFLAGS         = @IRC_CFLAGS@ -DIRCD_PREFIX=\"@prefix@\"
+LDFLAGS        = @LDFLAGS@
+MKDEP          = @MKDEP@ -DIRCD_PREFIX=\"@prefix@\"
+MV             = @MV@
+RM             = @RM@
+YACC           = @YACC@
+prefix         = @prefix@
+exec_prefix    = @exec_prefix@
+bindir         = @bindir@
+libdir         = @libdir@
+libexecdir     = @libexecdir@
+
+FNVHASH_S      = @FNVHASH_S@
+
+DOLLAR = $$
+
+IRCD_EXE       = ircd
+
+PROGS          = $(IRCD_EXE)
+
+SSL_LIBS       = @SSL_LIBS@
+SSL_INCLUDES   = @SSL_INCLUDES@
+
+IRCDLIBS       = @MODULES_LIBS@ -L../libcharybdis -lcharybdis @LIBS@ $(SSL_LIBS)
+
+INCLUDES       = -I../include -I../libcharybdis $(SSL_INCLUDES)
+CPPFLAGS       = ${INCLUDES} @CPPFLAGS@
+default:       all
+
+y.tab.o:       y.tab.c ircd_parser.y
+       ${CC} ${CPPFLAGS} ${PICFLAGS} ${CFLAGS} -I. -c y.tab.c
+
+# Note GNU bison uses <file>.tab.c not y.tab.c
+y.tab.c:       ircd_parser.y
+       ${YACC} -d ircd_parser.y
+
+lex.yy.o:      lex.yy.c ircd_lexer.l
+       ${CC} ${CPPFLAGS} ${PICFLAGS} ${CFLAGS} -I. -c lex.yy.c
+
+lex.yy.c:      ircd_lexer.l
+       ${LEX} ircd_lexer.l
+
+BASE_SRCS =                     \
+  blacklist.c                  \
+  cache.c                      \
+  channel.c                     \
+  chmode.c                     \
+  class.c                       \
+  client.c                      \
+  extban.c                      \
+  getopt.c                      \
+  hash.c                        \
+  hook.c                        \
+  hostmask.c                   \
+  irc_string.c                  \
+  ircd.c                        \
+  ircd_signal.c                 \
+  ircd_state.c                 \
+  kdparse.c                    \
+  listener.c                    \
+  match.c                       \
+  modules.c                     \
+  monitor.c                    \
+  newconf.c                    \
+  numeric.c                     \
+  packet.c                      \
+  parse.c                       \
+  patricia.c                   \
+  res.c                                \
+  reslib.c                     \
+  reject.c                     \
+  restart.c                     \
+  s_auth.c                      \
+  s_conf.c                      \
+  s_newconf.c                  \
+  s_gline.c                     \
+  s_log.c                       \
+  s_serv.c                      \
+  s_stats.c                     \
+  s_user.c                      \
+  scache.c                      \
+  send.c                        \
+  snomask.c                    \
+  supported.c                  \
+  whowas.c                     \
+  $(FNVHASH_S)
+
+SRCS = ${BASE_SRCS:.s=.o}
+
+OBJS = ${SRCS:.c=.o}
+
+all: ircd
+
+build: all
+
+ircd: $(OBJS) y.tab.o lex.yy.o version.o
+       ${CC} ${CFLAGS} ${LDFLAGS} -o $@ ${OBJS} lex.yy.o y.tab.o version.o ${IRCDLIBS} ${LEXLIB}
+       mv version.c version.c.last
+
+install-mkdirs:
+       -@if test ! -d $(DESTDIR)$(prefix); then \
+               echo "ircd: setting up ircd directory structure"; \
+               mkdir $(DESTDIR)$(prefix); \
+       fi
+       -@if test ! -d $(DESTDIR)$(exec_prefix); then \
+               mkdir $(DESTDIR)$(exec_prefix); \
+       fi
+       -@if test ! -d $(DESTDIR)$(bindir); then \
+               mkdir $(DESTDIR)$(bindir); \
+       fi
+       -@if test ! -d $(DESTDIR)$(libdir); then \
+               mkdir $(DESTDIR)$(libdir); \
+       fi
+
+install: install-mkdirs build
+       -@if test -f $(DESTDIR)$(bindir)/ircd; then \
+               echo "ircd: backing up ircd"; \
+       fi
+       @echo "ircd: installing ircd ($(PROGS))"
+       @for i in $(PROGS); do \
+               if test -f $(DESTDIR)$(bindir)/$$i; then \
+                       $(MV) $(DESTDIR)$(bindir)/$$i $(DESTDIR)$(bindir)/$$i.old; \
+               fi; \
+               $(INSTALL_BIN) $$i $(DESTDIR)$(bindir); \
+       done
+
+version.c: version.c.SH
+       /bin/sh ./version.c.SH
+
+
+# this is really the default rule for c files
+.c.o:
+       ${CC} ${CPPFLAGS} ${CFLAGS} -c $<
+.s.o:
+       ${CC} ${CPPFLAGS} ${CFLAGS} -c $<
+
+.PHONY: depend clean distclean
+depend:
+       ${MKDEP} ${CPPFLAGS} ${BASE_SRCS} > .depend
+
+clean:
+       ${RM} -f *.o *.exe *~ y.tab.* lex.yy.c ircd.core core ircd
+
+lint:
+       lint -aacgprxhH $(CPPFLAGS) -DIRCD_PREFIX=\"@prefix@\" $(SRCS) >>../lint.out
+
+distclean: clean
+       ${RM} -f Makefile version.c.last
+
+include .depend
diff --git a/src/blacklist.c b/src/blacklist.c
new file mode 100644 (file)
index 0000000..382ea91
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * charybdis: A slightly useful ircd.
+ * blacklist.c: Manages DNS blacklist entries and lookups
+ *
+ * Copyright (C) 2006 charybdis development team
+ *
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: blacklist.c 2743 2006-11-10 15:15:00Z jilles $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "res.h"
+#include "tools.h"
+#include "memory.h"
+#include "numeric.h"
+#include "reject.h"
+#include "s_conf.h"
+#include "s_user.h"
+#include "blacklist.h"
+
+dlink_list blacklist_list = { NULL, NULL, 0 };
+
+/* private interfaces */
+static struct Blacklist *find_blacklist(char *name)
+{
+       dlink_node *nptr;
+
+       DLINK_FOREACH(nptr, blacklist_list.head)
+       {
+               struct Blacklist *blptr = (struct Blacklist *) nptr->data;
+
+               if (!irccmp(blptr->host, name))
+                       return blptr;
+       }
+
+       return NULL;
+}
+
+static void blacklist_dns_callback(void *vptr, struct DNSReply *reply)
+{
+       struct BlacklistClient *blcptr = (struct BlacklistClient *) vptr;
+
+       if (blcptr == NULL || blcptr->client_p == NULL)
+               return;
+
+       if (blcptr->client_p->preClient == NULL)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                               "blacklist_dns_callback(): blcptr->client_p->preClient (%s) is NULL", get_client_name(blcptr->client_p, HIDE_IP));
+               MyFree(blcptr);
+               return;
+       }
+
+       /* they have a blacklist entry for this client */
+       if (reply != NULL && blcptr->client_p->preClient->dnsbl_listed == NULL)
+       {
+               blcptr->client_p->preClient->dnsbl_listed = blcptr->blacklist;
+               /* reference to blacklist moves from blcptr to client_p->preClient... */
+       }
+       else
+               unref_blacklist(blcptr->blacklist);
+
+       dlinkDelete(&blcptr->node, &blcptr->client_p->preClient->dnsbl_queries);
+
+       /* yes, it can probably happen... */
+       if (dlink_list_length(&blcptr->client_p->preClient->dnsbl_queries) == 0 && blcptr->client_p->flags & FLAGS_SENTUSER && !EmptyString(blcptr->client_p->name))
+       {
+               char buf[USERLEN + 1];
+               strlcpy(buf, blcptr->client_p->username, sizeof buf);
+               register_local_user(blcptr->client_p, blcptr->client_p, buf);
+       }
+
+       MyFree(blcptr);
+}
+
+/* XXX: no IPv6 implementation, not to concerned right now though. */
+static void initiate_blacklist_dnsquery(struct Blacklist *blptr, struct Client *client_p)
+{
+       struct BlacklistClient *blcptr = MyMalloc(sizeof(struct BlacklistClient));
+       char buf[IRCD_BUFSIZE];
+       int ip[4];
+
+       blcptr->blacklist = blptr;
+       blcptr->client_p = client_p;
+
+       blcptr->dns_query.ptr = blcptr;
+       blcptr->dns_query.callback = blacklist_dns_callback;
+
+       /* XXX: yes I know this is bad, I don't really care right now */
+       sscanf(client_p->sockhost, "%d.%d.%d.%d", &ip[3], &ip[2], &ip[1], &ip[0]);
+
+       /* becomes 2.0.0.127.torbl.ahbl.org or whatever */
+       ircsnprintf(buf, IRCD_BUFSIZE, "%d.%d.%d.%d.%s", ip[0], ip[1], ip[2], ip[3], blptr->host);
+
+       gethost_byname_type(buf, &blcptr->dns_query, T_A);
+
+       dlinkAdd(blcptr, &blcptr->node, &client_p->preClient->dnsbl_queries);
+       blptr->refcount++;
+}
+
+/* public interfaces */
+struct Blacklist *new_blacklist(char *name, char *reject_reason)
+{
+       struct Blacklist *blptr;
+
+       if (name == NULL || reject_reason == NULL)
+               return NULL;
+
+       blptr = find_blacklist(name);
+       if (blptr == NULL)
+       {
+               blptr = MyMalloc(sizeof(struct Blacklist));
+               dlinkAddAlloc(blptr, &blacklist_list);
+       }
+       else
+               blptr->status &= ~CONF_ILLEGAL;
+       strlcpy(blptr->host, name, HOSTLEN);
+       strlcpy(blptr->reject_reason, reject_reason, IRCD_BUFSIZE);
+
+       return blptr;
+}
+
+void unref_blacklist(struct Blacklist *blptr)
+{
+       blptr->refcount--;
+       if (blptr->status & CONF_ILLEGAL && blptr->refcount <= 0)
+       {
+               dlinkFindDestroy(blptr, &blacklist_list);
+               MyFree(blptr);
+       }
+}
+
+void lookup_blacklists(struct Client *client_p)
+{
+       dlink_node *nptr;
+
+       /* We don't do IPv6 right now, sorry! */
+       if (client_p->localClient->ip.ss_family == AF_INET6)
+               return;
+
+       DLINK_FOREACH(nptr, blacklist_list.head)
+       {
+               struct Blacklist *blptr = (struct Blacklist *) nptr->data;
+
+               if (!(blptr->status & CONF_ILLEGAL))
+                       initiate_blacklist_dnsquery(blptr, client_p);
+       }
+}
+
+void abort_blacklist_queries(struct Client *client_p)
+{
+       dlink_node *ptr, *next_ptr;
+       struct BlacklistClient *blcptr;
+
+       if (client_p->preClient == NULL)
+               return;
+       DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->preClient->dnsbl_queries.head)
+       {
+               blcptr = ptr->data;
+               dlinkDelete(&blcptr->node, &client_p->preClient->dnsbl_queries);
+               unref_blacklist(blcptr->blacklist);
+               delete_resolver_queries(&blcptr->dns_query);
+               MyFree(blcptr);
+       }
+}
+
+void destroy_blacklists(void)
+{
+       dlink_node *ptr, *next_ptr;
+       struct Blacklist *blptr;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, blacklist_list.head)
+       {
+               blptr = ptr->data;
+               blptr->hits = 0; /* keep it simple and consistent */
+               if (blptr->refcount > 0)
+                       blptr->status |= CONF_ILLEGAL;
+               else
+               {
+                       MyFree(ptr->data);
+                       dlinkDestroy(ptr, &blacklist_list);
+               }
+       }
+}
diff --git a/src/cache.c b/src/cache.c
new file mode 100644 (file)
index 0000000..d8ac748
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * ircd-ratbox: an advanced Internet Relay Chat Daemon(ircd).
+ * cache.c - code for caching files
+ *
+ * Copyright (C) 2003 Lee Hardy <lee@leeh.co.uk>
+ * Copyright (C) 2003-2005 ircd-ratbox development team
+ *
+ * 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.The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: cache.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "ircd_defs.h"
+#include "common.h"
+#include "s_conf.h"
+#include "tools.h"
+#include "client.h"
+#include "memory.h"
+#include "balloc.h"
+#include "event.h"
+#include "hash.h"
+#include "cache.h"
+#include "sprintf_irc.h"
+
+static BlockHeap *cachefile_heap = NULL;
+static BlockHeap *cacheline_heap = NULL;
+
+struct cachefile *user_motd = NULL;
+struct cachefile *oper_motd = NULL;
+struct cacheline *emptyline = NULL;
+dlink_list links_cache_list;
+char user_motd_changed[MAX_DATE_STRING];
+
+/* init_cache()
+ *
+ * inputs      -
+ * outputs     -
+ * side effects - inits the file/line cache blockheaps, loads motds
+ */
+void
+init_cache(void)
+{
+       cachefile_heap = BlockHeapCreate(sizeof(struct cachefile), CACHEFILE_HEAP_SIZE);
+       cacheline_heap = BlockHeapCreate(sizeof(struct cacheline), CACHELINE_HEAP_SIZE);
+
+       /* allocate the emptyline */
+       emptyline = BlockHeapAlloc(cacheline_heap);
+       emptyline->data[0] = ' ';
+       emptyline->data[1] = '\0';
+       user_motd_changed[0] = '\0';
+
+       user_motd = cache_file(MPATH, "ircd.motd", 0);
+       oper_motd = cache_file(OPATH, "opers.motd", 0);
+       memset(&links_cache_list, 0, sizeof(links_cache_list));
+}
+
+/* cache_file()
+ *
+ * inputs      - file to cache, files "shortname", flags to set
+ * outputs     - pointer to file cached, else NULL
+ * side effects -
+ */
+struct cachefile *
+cache_file(const char *filename, const char *shortname, int flags)
+{
+       FILE *in;
+       struct cachefile *cacheptr;
+       struct cacheline *lineptr;
+       char line[BUFSIZE];
+       char *p;
+
+       if((in = fopen(filename, "r")) == NULL)
+               return NULL;
+
+       if(strcmp(shortname, "ircd.motd") == 0)
+       {
+               struct stat sb;
+               struct tm *local_tm;
+
+               if(fstat(fileno(in), &sb) < 0)
+                       return NULL;
+
+               local_tm = localtime(&sb.st_mtime);
+
+               if(local_tm != NULL)
+                       ircsnprintf(user_motd_changed, sizeof(user_motd_changed),
+                                "%d/%d/%d %d:%d",
+                                local_tm->tm_mday, local_tm->tm_mon + 1,
+                                1900 + local_tm->tm_year, local_tm->tm_hour,
+                                local_tm->tm_min);
+       }
+
+       cacheptr = BlockHeapAlloc(cachefile_heap);
+
+       strlcpy(cacheptr->name, shortname, sizeof(cacheptr->name));
+       cacheptr->flags = flags;
+
+       /* cache the file... */
+       while(fgets(line, sizeof(line), in) != NULL)
+       {
+               if((p = strchr(line, '\n')) != NULL)
+                       *p = '\0';
+
+               if(!EmptyString(line))
+               {
+                       lineptr = BlockHeapAlloc(cacheline_heap);
+                       strlcpy(lineptr->data, line, sizeof(lineptr->data));
+                       dlinkAddTail(lineptr, &lineptr->linenode, &cacheptr->contents);
+               }
+               else
+                       dlinkAddTailAlloc(emptyline, &cacheptr->contents);
+       }
+
+       fclose(in);
+       return cacheptr;
+}
+
+void
+cache_links(void *unused)
+{
+       struct Client *target_p;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+       char *links_line;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, links_cache_list.head)
+       {
+               MyFree(ptr->data);
+               free_dlink_node(ptr);
+       }
+
+       links_cache_list.head = links_cache_list.tail = NULL;
+       links_cache_list.length = 0;
+
+       DLINK_FOREACH(ptr, global_serv_list.head)
+       {
+               target_p = ptr->data;
+
+               /* skip ourselves (done in /links) and hidden servers */
+               if(IsMe(target_p) ||
+                  (IsHidden(target_p) && !ConfigServerHide.disable_hidden))
+                       continue;
+
+               /* if the below is ever modified, change LINKSLINELEN */
+               links_line = MyMalloc(LINKSLINELEN);
+               ircsnprintf(links_line, LINKSLINELEN, "%s %s :1 %s",
+                          target_p->name, me.name, 
+                          target_p->info[0] ? target_p->info : 
+                           "(Unknown Location)");
+
+               dlinkAddTailAlloc(links_line, &links_cache_list);
+       }
+}
+
+/* free_cachefile()
+ *
+ * inputs      - cachefile to free
+ * outputs     -
+ * side effects - cachefile and its data is free'd
+ */
+void
+free_cachefile(struct cachefile *cacheptr)
+{
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+
+       if(cacheptr == NULL)
+               return;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, cacheptr->contents.head)
+       {
+               if(ptr->data != emptyline)
+                       BlockHeapFree(cacheline_heap, ptr->data);
+       }
+
+       BlockHeapFree(cachefile_heap, cacheptr);
+}
+
+/* load_help()
+ *
+ * inputs      -
+ * outputs     -
+ * side effects - contents of help directories are loaded.
+ */
+void
+load_help(void)
+{
+       DIR *helpfile_dir = NULL;
+       struct dirent *ldirent= NULL;
+       char filename[MAXPATHLEN];
+       struct cachefile *cacheptr;
+
+#if defined(S_ISLNK) && defined(HAVE_LSTAT)
+       struct stat sb;
+#endif
+
+       /* opers must be done first */
+       helpfile_dir = opendir(HPATH);
+
+       if(helpfile_dir == NULL)
+               return;
+
+       while((ldirent = readdir(helpfile_dir)) != NULL)
+       {
+               ircsnprintf(filename, sizeof(filename), "%s/%s", HPATH, ldirent->d_name);
+               cacheptr = cache_file(filename, ldirent->d_name, HELP_OPER);
+               add_to_help_hash(cacheptr->name, cacheptr);
+       }
+
+       closedir(helpfile_dir);
+       helpfile_dir = opendir(UHPATH);
+
+       if(helpfile_dir == NULL)
+               return;
+
+       while((ldirent = readdir(helpfile_dir)) != NULL)
+       {
+               ircsnprintf(filename, sizeof(filename), "%s/%s", UHPATH, ldirent->d_name);
+
+#if defined(S_ISLNK) && defined(HAVE_LSTAT)
+               if(lstat(filename, &sb) < 0)
+                       continue;
+
+               /* ok, if its a symlink, we work on the presumption if an
+                * oper help exists of that name, its a symlink to that --fl
+                */
+               if(S_ISLNK(sb.st_mode))
+               {
+                       cacheptr = hash_find_help(ldirent->d_name, HELP_OPER);
+
+                       if(cacheptr != NULL)
+                       {
+                               cacheptr->flags |= HELP_USER;
+                               continue;
+                       }
+               }
+#endif
+
+               cacheptr = cache_file(filename, ldirent->d_name, HELP_USER);
+               add_to_help_hash(cacheptr->name, cacheptr);
+       }
+
+       closedir(helpfile_dir);
+}
+
+/* send_user_motd()
+ *
+ * inputs      - client to send motd to
+ * outputs     - client is sent motd if exists, else ERR_NOMOTD
+ * side effects -
+ */
+void
+send_user_motd(struct Client *source_p)
+{
+       struct cacheline *lineptr;
+       dlink_node *ptr;
+       const char *myname = get_id(&me, source_p);
+       const char *nick = get_id(source_p, source_p);
+
+       if(user_motd == NULL || dlink_list_length(&user_motd->contents) == 0)
+       {
+               sendto_one(source_p, form_str(ERR_NOMOTD), myname, nick);
+               return;
+       }
+
+       sendto_one(source_p, form_str(RPL_MOTDSTART), myname, nick, me.name);
+
+       DLINK_FOREACH(ptr, user_motd->contents.head)
+       {
+               lineptr = ptr->data;
+               sendto_one(source_p, form_str(RPL_MOTD), myname, nick, lineptr->data);
+       }
+
+       sendto_one(source_p, form_str(RPL_ENDOFMOTD), myname, nick);
+}
+
+/* send_oper_motd()
+ *
+ * inputs      - client to send motd to
+ * outputs     - client is sent oper motd if exists
+ * side effects -
+ */
+void
+send_oper_motd(struct Client *source_p)
+{
+       struct cacheline *lineptr;
+       dlink_node *ptr;
+
+       if(oper_motd == NULL || dlink_list_length(&oper_motd->contents) == 0)
+               return;
+
+       sendto_one(source_p, form_str(RPL_OMOTDSTART), 
+                  me.name, source_p->name);
+
+       DLINK_FOREACH(ptr, oper_motd->contents.head)
+       {
+               lineptr = ptr->data;
+               sendto_one(source_p, form_str(RPL_OMOTD),
+                          me.name, source_p->name, lineptr->data);
+       }
+
+       sendto_one(source_p, form_str(RPL_ENDOFOMOTD), 
+                  me.name, source_p->name);
+}
+
diff --git a/src/channel.c b/src/channel.c
new file mode 100644 (file)
index 0000000..51f5548
--- /dev/null
@@ -0,0 +1,1385 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  channel.c: Controls channels.
+ *
+ * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center 
+ * Copyright (C) 1996-2002 Hybrid Development Team 
+ * Copyright (C) 2002-2005 ircd-ratbox development 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: channel.c 3131 2007-01-21 15:36:31Z jilles $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "channel.h"
+#include "client.h"
+#include "common.h"
+#include "hash.h"
+#include "hook.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_serv.h"            /* captab */
+#include "s_user.h"
+#include "send.h"
+#include "whowas.h"
+#include "s_conf.h"            /* ConfigFileEntry, ConfigChannel */
+#include "s_newconf.h"
+#include "event.h"
+#include "memory.h"
+#include "balloc.h"
+#include "s_log.h"
+
+extern dlink_list global_channel_list;
+
+extern struct config_channel_entry ConfigChannel;
+extern BlockHeap *channel_heap;
+extern BlockHeap *ban_heap;
+extern BlockHeap *topic_heap;
+extern BlockHeap *member_heap;
+
+static int channel_capabs[] = { CAP_EX, CAP_IE,
+       CAP_SERVICE,
+       CAP_TS6
+};
+
+#define NCHCAPS         (sizeof(channel_capabs)/sizeof(int))
+#define NCHCAP_COMBOS   (1 << NCHCAPS)
+
+static struct ChCapCombo chcap_combos[NCHCAP_COMBOS];
+
+static void free_topic(struct Channel *chptr);
+
+static int h_can_join;
+
+/* init_channels()
+ *
+ * input       -
+ * output      -
+ * side effects - initialises the various blockheaps
+ */
+void
+init_channels(void)
+{
+       channel_heap = BlockHeapCreate(sizeof(struct Channel), CHANNEL_HEAP_SIZE);
+       ban_heap = BlockHeapCreate(sizeof(struct Ban), BAN_HEAP_SIZE);
+       topic_heap = BlockHeapCreate(TOPICLEN + 1 + USERHOST_REPLYLEN, TOPIC_HEAP_SIZE);
+       member_heap = BlockHeapCreate(sizeof(struct membership), MEMBER_HEAP_SIZE);
+
+       h_can_join = register_hook("can_join");
+}
+
+/*
+ * allocate_channel - Allocates a channel
+ */
+struct Channel *
+allocate_channel(const char *chname)
+{
+       struct Channel *chptr;
+       chptr = BlockHeapAlloc(channel_heap);
+       DupNString(chptr->chname, chname, CHANNELLEN);
+       return (chptr);
+}
+
+void
+free_channel(struct Channel *chptr)
+{
+       MyFree(chptr->chname);
+       BlockHeapFree(channel_heap, chptr);
+}
+
+struct Ban *
+allocate_ban(const char *banstr, const char *who)
+{
+       struct Ban *bptr;
+       bptr = BlockHeapAlloc(ban_heap);
+       DupNString(bptr->banstr, banstr, BANLEN);
+       DupNString(bptr->who, who, BANLEN);
+
+       return (bptr);
+}
+
+void
+free_ban(struct Ban *bptr)
+{
+       MyFree(bptr->banstr);
+       MyFree(bptr->who);
+       BlockHeapFree(ban_heap, bptr);
+}
+
+
+/* find_channel_membership()
+ *
+ * input       - channel to find them in, client to find
+ * output      - membership of client in channel, else NULL
+ * side effects        -
+ */
+struct membership *
+find_channel_membership(struct Channel *chptr, struct Client *client_p)
+{
+       struct membership *msptr;
+       dlink_node *ptr;
+
+       if(!IsClient(client_p))
+               return NULL;
+
+       /* Pick the most efficient list to use to be nice to things like
+        * CHANSERV which could be in a large number of channels
+        */
+       if(dlink_list_length(&chptr->members) < dlink_list_length(&client_p->user->channel))
+       {
+               DLINK_FOREACH(ptr, chptr->members.head)
+               {
+                       msptr = ptr->data;
+
+                       if(msptr->client_p == client_p)
+                               return msptr;
+               }
+       }
+       else
+       {
+               DLINK_FOREACH(ptr, client_p->user->channel.head)
+               {
+                       msptr = ptr->data;
+
+                       if(msptr->chptr == chptr)
+                               return msptr;
+               }
+       }
+
+       return NULL;
+}
+
+/* find_channel_status()
+ *
+ * input       - membership to get status for, whether we can combine flags
+ * output      - flags of user on channel
+ * side effects -
+ */
+const char *
+find_channel_status(struct membership *msptr, int combine)
+{
+       static char buffer[3];
+       char *p;
+
+       p = buffer;
+
+       if(is_chanop(msptr))
+       {
+               if(!combine)
+                       return "@";
+               *p++ = '@';
+       }
+
+       if(is_voiced(msptr))
+               *p++ = '+';
+
+       *p = '\0';
+       return buffer;
+}
+
+/* add_user_to_channel()
+ *
+ * input       - channel to add client to, client to add, channel flags
+ * output      - 
+ * side effects - user is added to channel
+ */
+void
+add_user_to_channel(struct Channel *chptr, struct Client *client_p, int flags)
+{
+       struct membership *msptr;
+
+       s_assert(client_p->user != NULL);
+       if(client_p->user == NULL)
+               return;
+
+       msptr = BlockHeapAlloc(member_heap);
+
+       msptr->chptr = chptr;
+       msptr->client_p = client_p;
+       msptr->flags = flags;
+
+       dlinkAdd(msptr, &msptr->usernode, &client_p->user->channel);
+       dlinkAdd(msptr, &msptr->channode, &chptr->members);
+
+       if(MyClient(client_p))
+               dlinkAdd(msptr, &msptr->locchannode, &chptr->locmembers);
+}
+
+/* remove_user_from_channel()
+ *
+ * input       - membership pointer to remove from channel
+ * output      -
+ * side effects - membership (thus user) is removed from channel
+ */
+void
+remove_user_from_channel(struct membership *msptr)
+{
+       struct Client *client_p;
+       struct Channel *chptr;
+       s_assert(msptr != NULL);
+       if(msptr == NULL)
+               return;
+
+       client_p = msptr->client_p;
+       chptr = msptr->chptr;
+
+       dlinkDelete(&msptr->usernode, &client_p->user->channel);
+       dlinkDelete(&msptr->channode, &chptr->members);
+
+       if(client_p->servptr == &me)
+               dlinkDelete(&msptr->locchannode, &chptr->locmembers);
+
+       chptr->users_last = CurrentTime;
+
+       if(!(chptr->mode.mode & MODE_PERMANENT) && dlink_list_length(&chptr->members) <= 0)
+               destroy_channel(chptr);
+
+       BlockHeapFree(member_heap, msptr);
+
+       return;
+}
+
+/* remove_user_from_channels()
+ *
+ * input        - user to remove from all channels
+ * output       -
+ * side effects - user is removed from all channels
+ */
+void
+remove_user_from_channels(struct Client *client_p)
+{
+       struct Channel *chptr;
+       struct membership *msptr;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+
+       if(client_p == NULL)
+               return;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->user->channel.head)
+       {
+               msptr = ptr->data;
+               chptr = msptr->chptr;
+
+               dlinkDelete(&msptr->channode, &chptr->members);
+
+               if(client_p->servptr == &me)
+                       dlinkDelete(&msptr->locchannode, &chptr->locmembers);
+
+               chptr->users_last = CurrentTime;
+
+               if(!(chptr->mode.mode & MODE_PERMANENT) && dlink_list_length(&chptr->members) <= 0)
+                       destroy_channel(chptr);
+
+               BlockHeapFree(member_heap, msptr);
+       }
+
+       client_p->user->channel.head = client_p->user->channel.tail = NULL;
+       client_p->user->channel.length = 0;
+}
+
+/* invalidate_bancache_user()
+ *
+ * input       - user to invalidate ban cache for
+ * output      -
+ * side effects - ban cache is invalidated for all memberships of that user
+ *                to be used after a nick change
+ */
+void
+invalidate_bancache_user(struct Client *client_p)
+{
+       struct membership *msptr;
+       dlink_node *ptr;
+
+       if(client_p == NULL)
+               return;
+
+       DLINK_FOREACH(ptr, client_p->user->channel.head)
+       {
+               msptr = ptr->data;
+               msptr->bants = 0;
+               msptr->flags &= ~CHFL_BANNED;
+       }
+}
+
+/* check_channel_name()
+ *
+ * input       - channel name
+ * output      - 1 if valid channel name, else 0
+ * side effects -
+ */
+int
+check_channel_name(const char *name)
+{
+       s_assert(name != NULL);
+       if(name == NULL)
+               return 0;
+
+       for (; *name; ++name)
+       {
+               if(!IsChanChar(*name))
+                       return 0;
+       }
+
+       return 1;
+}
+
+/* free_channel_list()
+ *
+ * input       - dlink list to free
+ * output      -
+ * side effects - list of b/e/I modes is cleared
+ */
+void
+free_channel_list(dlink_list * list)
+{
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+       struct Ban *actualBan;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
+       {
+               actualBan = ptr->data;
+               free_ban(actualBan);
+       }
+
+       list->head = list->tail = NULL;
+       list->length = 0;
+}
+
+/* destroy_channel()
+ *
+ * input       - channel to destroy
+ * output      -
+ * side effects - channel is obliterated
+ */
+void
+destroy_channel(struct Channel *chptr)
+{
+       dlink_node *ptr, *next_ptr;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->invites.head)
+       {
+               del_invite(chptr, ptr->data);
+       }
+
+       /* free all bans/exceptions/denies */
+       free_channel_list(&chptr->banlist);
+       free_channel_list(&chptr->exceptlist);
+       free_channel_list(&chptr->invexlist);
+
+       /* Free the topic */
+       free_topic(chptr);
+
+       dlinkDelete(&chptr->node, &global_channel_list);
+       del_from_channel_hash(chptr->chname, chptr);
+       free_channel(chptr);
+}
+
+/* channel_pub_or_secret()
+ *
+ * input       - channel
+ * output      - "=" if public, "@" if secret, else "*"
+ * side effects        -
+ */
+static const char *
+channel_pub_or_secret(struct Channel *chptr)
+{
+       if(PubChannel(chptr))
+               return ("=");
+       else if(SecretChannel(chptr))
+               return ("@");
+       return ("*");
+}
+
+/* channel_member_names()
+ *
+ * input       - channel to list, client to list to, show endofnames
+ * output      -
+ * side effects - client is given list of users on channel
+ */
+void
+channel_member_names(struct Channel *chptr, struct Client *client_p, int show_eon)
+{
+       struct membership *msptr;
+       struct Client *target_p;
+       dlink_node *ptr;
+       char lbuf[BUFSIZE];
+       char *t;
+       int mlen;
+       int tlen;
+       int cur_len;
+       int is_member;
+       int stack = IsCapable(client_p, CLICAP_MULTI_PREFIX);
+
+       if(ShowChannel(client_p, chptr))
+       {
+               is_member = IsMember(client_p, chptr);
+
+               cur_len = mlen = ircsprintf(lbuf, form_str(RPL_NAMREPLY),
+                                           me.name, client_p->name,
+                                           channel_pub_or_secret(chptr), chptr->chname);
+
+               t = lbuf + cur_len;
+
+               DLINK_FOREACH(ptr, chptr->members.head)
+               {
+                       msptr = ptr->data;
+                       target_p = msptr->client_p;
+
+                       if(IsInvisible(target_p) && !is_member)
+                               continue;
+
+                       /* space, possible "@+" prefix */
+                       if(cur_len + strlen(target_p->name) + 3 >= BUFSIZE - 3)
+                       {
+                               *(t - 1) = '\0';
+                               sendto_one(client_p, "%s", lbuf);
+                               cur_len = mlen;
+                               t = lbuf + mlen;
+                       }
+
+                       tlen = ircsprintf(t, "%s%s ", find_channel_status(msptr, stack),
+                                         target_p->name);
+
+                       cur_len += tlen;
+                       t += tlen;
+               }
+
+               /* The old behaviour here was to always output our buffer,
+                * even if there are no clients we can show.  This happens
+                * when a client does "NAMES" with no parameters, and all
+                * the clients on a -sp channel are +i.  I dont see a good
+                * reason for keeping that behaviour, as it just wastes
+                * bandwidth.  --anfl
+                */
+               if(cur_len != mlen)
+               {
+                       *(t - 1) = '\0';
+                       sendto_one(client_p, "%s", lbuf);
+               }
+       }
+
+       if(show_eon)
+               sendto_one(client_p, form_str(RPL_ENDOFNAMES),
+                          me.name, client_p->name, chptr->chname);
+}
+
+/* del_invite()
+ *
+ * input       - channel to remove invite from, client to remove
+ * output      -
+ * side effects - user is removed from invite list, if exists
+ */
+void
+del_invite(struct Channel *chptr, struct Client *who)
+{
+       dlinkFindDestroy(who, &chptr->invites);
+       dlinkFindDestroy(chptr, &who->user->invited);
+}
+
+/* is_banned()
+ *
+ * input       - channel to check bans for, user to check bans against
+ *                optional prebuilt buffers
+ * output      - 1 if banned, else 0
+ * side effects -
+ */
+int
+is_banned(struct Channel *chptr, struct Client *who, struct membership *msptr,
+         const char *s, const char *s2)
+{
+       char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
+       char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
+       char src_althost[NICKLEN + USERLEN + HOSTLEN + 6];
+       char *s3 = NULL;
+       dlink_node *ptr;
+       struct Ban *actualBan = NULL;
+       struct Ban *actualExcept = NULL;
+
+       if(!MyClient(who))
+               return 0;
+
+       /* if the buffers havent been built, do it here */
+       if(s == NULL)
+       {
+               ircsprintf(src_host, "%s!%s@%s", who->name, who->username, who->host);
+               ircsprintf(src_iphost, "%s!%s@%s", who->name, who->username, who->sockhost);
+
+               s = src_host;
+               s2 = src_iphost;
+       }
+       if(who->localClient->mangledhost != NULL)
+       {
+               /* if host mangling mode enabled, also check their real host */
+               if(!strcmp(who->host, who->localClient->mangledhost))
+               {
+                       ircsprintf(src_althost, "%s!%s@%s", who->name, who->username, who->orighost);
+                       s3 = src_althost;
+               }
+               /* if host mangling mode not enabled and no other spoof,
+                * also check the mangled form of their host */
+               else if (!IsDynSpoof(who))
+               {
+                       ircsprintf(src_althost, "%s!%s@%s", who->name, who->username, who->localClient->mangledhost);
+                       s3 = src_althost;
+               }
+       }
+
+       DLINK_FOREACH(ptr, chptr->banlist.head)
+       {
+               actualBan = ptr->data;
+               if(match(actualBan->banstr, s) ||
+                  match(actualBan->banstr, s2) ||
+                  match_cidr(actualBan->banstr, s2) ||
+                  match_extban(actualBan->banstr, who, chptr, CHFL_BAN) ||
+                  (s3 != NULL && match(actualBan->banstr, s3)))
+                       break;
+               else
+                       actualBan = NULL;
+       }
+
+       if((actualBan != NULL) && ConfigChannel.use_except)
+       {
+               DLINK_FOREACH(ptr, chptr->exceptlist.head)
+               {
+                       actualExcept = ptr->data;
+
+                       /* theyre exempted.. */
+                       if(match(actualExcept->banstr, s) ||
+                          match(actualExcept->banstr, s2) ||
+                          match_cidr(actualExcept->banstr, s2) ||
+                          match_extban(actualExcept->banstr, who, chptr, CHFL_EXCEPTION) ||
+                          (s3 != NULL && match(actualExcept->banstr, s3)))
+                       {
+                               /* cache the fact theyre not banned */
+                               if(msptr != NULL)
+                               {
+                                       msptr->bants = chptr->bants;
+                                       msptr->flags &= ~CHFL_BANNED;
+                               }
+
+                               return CHFL_EXCEPTION;
+                       }
+               }
+       }
+
+       /* cache the banned/not banned status */
+       if(msptr != NULL)
+       {
+               msptr->bants = chptr->bants;
+
+               if(actualBan != NULL)
+               {
+                       msptr->flags |= CHFL_BANNED;
+                       return CHFL_BAN;
+               }
+               else
+               {
+                       msptr->flags &= ~CHFL_BANNED;
+                       return 0;
+               }
+       }
+
+       return ((actualBan ? CHFL_BAN : 0));
+}
+
+/* is_quieted()
+ *
+ * input       - channel to check bans for, user to check bans against
+ *                optional prebuilt buffers
+ * output      - 1 if banned, else 0
+ * side effects -
+ */
+int
+is_quieted(struct Channel *chptr, struct Client *who, struct membership *msptr,
+          const char *s, const char *s2)
+{
+       char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
+       char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
+       char src_althost[NICKLEN + USERLEN + HOSTLEN + 6];
+       char *s3 = NULL;
+       dlink_node *ptr;
+       struct Ban *actualBan = NULL;
+       struct Ban *actualExcept = NULL;
+
+       if(!MyClient(who))
+               return 0;
+
+       /* if the buffers havent been built, do it here */
+       if(s == NULL)
+       {
+               ircsprintf(src_host, "%s!%s@%s", who->name, who->username, who->host);
+               ircsprintf(src_iphost, "%s!%s@%s", who->name, who->username, who->sockhost);
+
+               s = src_host;
+               s2 = src_iphost;
+       }
+       if(who->localClient->mangledhost != NULL)
+       {
+               /* if host mangling mode enabled, also check their real host */
+               if(!strcmp(who->host, who->localClient->mangledhost))
+               {
+                       ircsprintf(src_althost, "%s!%s@%s", who->name, who->username, who->orighost);
+                       s3 = src_althost;
+               }
+               /* if host mangling mode not enabled and no other spoof,
+                * also check the mangled form of their host */
+               else if (!IsDynSpoof(who))
+               {
+                       ircsprintf(src_althost, "%s!%s@%s", who->name, who->username, who->localClient->mangledhost);
+                       s3 = src_althost;
+               }
+       }
+
+       DLINK_FOREACH(ptr, chptr->quietlist.head)
+       {
+               actualBan = ptr->data;
+               if(match(actualBan->banstr, s) ||
+                  match(actualBan->banstr, s2) ||
+                  match_cidr(actualBan->banstr, s2) ||
+                  match_extban(actualBan->banstr, who, chptr, CHFL_QUIET) ||
+                  (s3 != NULL && match(actualBan->banstr, s3)))
+                       break;
+               else
+                       actualBan = NULL;
+       }
+
+       if((actualBan != NULL) && ConfigChannel.use_except)
+       {
+               DLINK_FOREACH(ptr, chptr->exceptlist.head)
+               {
+                       actualExcept = ptr->data;
+
+                       /* theyre exempted.. */
+                       if(match(actualExcept->banstr, s) ||
+                          match(actualExcept->banstr, s2) ||
+                          match_cidr(actualExcept->banstr, s2) ||
+                          match_extban(actualExcept->banstr, who, chptr, CHFL_EXCEPTION) ||
+                          (s3 != NULL && match(actualExcept->banstr, s3)))
+                       {
+                               /* cache the fact theyre not banned */
+                               if(msptr != NULL)
+                               {
+                                       msptr->bants = chptr->bants;
+                                       msptr->flags &= ~CHFL_BANNED;
+                               }
+
+                               return CHFL_EXCEPTION;
+                       }
+               }
+       }
+
+       /* cache the banned/not banned status */
+       if(msptr != NULL)
+       {
+               msptr->bants = chptr->bants;
+
+               if(actualBan != NULL)
+               {
+                       msptr->flags |= CHFL_BANNED;
+                       return CHFL_BAN;
+               }
+               else
+               {
+                       msptr->flags &= ~CHFL_BANNED;
+                       return 0;
+               }
+       }
+
+       return ((actualBan ? CHFL_BAN : 0));
+}
+
+/* can_join()
+ *
+ * input       - client to check, channel to check for, key
+ * output      - reason for not being able to join, else 0
+ * side effects -
+ */
+int
+can_join(struct Client *source_p, struct Channel *chptr, char *key)
+{
+       dlink_node *lp;
+       dlink_node *ptr;
+       struct Ban *invex = NULL;
+       char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
+       char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
+       char src_althost[NICKLEN + USERLEN + HOSTLEN + 6];
+       int use_althost = 0;
+       hook_data_channel moduledata;
+
+       s_assert(source_p->localClient != NULL);
+
+       ircsprintf(src_host, "%s!%s@%s", source_p->name, source_p->username, source_p->host);
+       ircsprintf(src_iphost, "%s!%s@%s", source_p->name, source_p->username, source_p->sockhost);
+       if(source_p->localClient->mangledhost != NULL)
+       {
+               /* if host mangling mode enabled, also check their real host */
+               if(!strcmp(source_p->host, source_p->localClient->mangledhost))
+               {
+                       ircsprintf(src_althost, "%s!%s@%s", source_p->name, source_p->username, source_p->orighost);
+                       use_althost = 1;
+               }
+               /* if host mangling mode not enabled and no other spoof,
+                * also check the mangled form of their host */
+               else if (!IsDynSpoof(source_p))
+               {
+                       ircsprintf(src_althost, "%s!%s@%s", source_p->name, source_p->username, source_p->localClient->mangledhost);
+                       use_althost = 1;
+               }
+       }
+
+       if((is_banned(chptr, source_p, NULL, src_host, src_iphost)) == CHFL_BAN)
+               return (ERR_BANNEDFROMCHAN);
+
+       if(chptr->mode.mode & MODE_INVITEONLY)
+       {
+               DLINK_FOREACH(lp, source_p->user->invited.head)
+               {
+                       if(lp->data == chptr)
+                               break;
+               }
+               if(lp == NULL)
+               {
+                       if(!ConfigChannel.use_invex)
+                               return (ERR_INVITEONLYCHAN);
+                       DLINK_FOREACH(ptr, chptr->invexlist.head)
+                       {
+                               invex = ptr->data;
+                               if(match(invex->banstr, src_host)
+                                  || match(invex->banstr, src_iphost)
+                                  || match_cidr(invex->banstr, src_iphost)
+                                  || match_extban(invex->banstr, source_p, chptr, CHFL_INVEX)
+                                  || (use_althost && match(invex->banstr, src_althost)))
+                                       break;
+                       }
+                       if(ptr == NULL)
+                               return (ERR_INVITEONLYCHAN);
+               }
+       }
+
+       if(*chptr->mode.key && (EmptyString(key) || irccmp(chptr->mode.key, key)))
+               return (ERR_BADCHANNELKEY);
+
+       if(chptr->mode.limit &&
+          dlink_list_length(&chptr->members) >= (unsigned long) chptr->mode.limit)
+               return (ERR_CHANNELISFULL);
+
+       if(chptr->mode.mode & MODE_REGONLY && EmptyString(source_p->user->suser))
+               return ERR_NEEDREGGEDNICK;
+
+       /* join throttling stuff --nenolod */
+       if(chptr->mode.join_num > 0 && chptr->mode.join_time > 0)
+       {
+               if ((CurrentTime - chptr->join_delta <= 
+                       chptr->mode.join_time) && (chptr->join_count >=
+                       chptr->mode.join_num))
+                       return ERR_THROTTLE;
+       }
+
+       moduledata.client = source_p;
+       moduledata.chptr = chptr;
+       moduledata.approved = 0;
+
+       call_hook(h_can_join, &moduledata);
+
+       return moduledata.approved;
+}
+
+/* can_send()
+ *
+ * input       - user to check in channel, membership pointer
+ * output      - whether can explicitly send or not, else CAN_SEND_NONOP
+ * side effects -
+ */
+int
+can_send(struct Channel *chptr, struct Client *source_p, struct membership *msptr)
+{
+       if(IsServer(source_p) || IsService(source_p))
+               return CAN_SEND_OPV;
+
+       if(MyClient(source_p) && hash_find_resv(chptr->chname) &&
+          !IsOper(source_p) && !IsExemptResv(source_p))
+               return CAN_SEND_NO;
+
+       if(msptr == NULL)
+       {
+               msptr = find_channel_membership(chptr, source_p);
+
+               if(msptr == NULL)
+               {
+                       /* if its +m or +n and theyre not in the channel,
+                        * they cant send.  we dont check bans here because
+                        * theres no possibility of caching them --fl
+                        */
+                       if(chptr->mode.mode & MODE_NOPRIVMSGS || chptr->mode.mode & MODE_MODERATED)
+                               return CAN_SEND_NO;
+                       else
+                               return CAN_SEND_NONOP;
+               }
+       }
+
+       if(is_chanop_voiced(msptr))
+               return CAN_SEND_OPV;
+
+       if(chptr->mode.mode & MODE_MODERATED)
+               return CAN_SEND_NO;
+
+       if(MyClient(source_p))
+       {
+               /* cached can_send */
+               if(msptr->bants == chptr->bants)
+               {
+                       if(can_send_banned(msptr))
+                               return CAN_SEND_NO;
+               }
+               else if(is_banned(chptr, source_p, msptr, NULL, NULL) == CHFL_BAN
+                       || is_quieted(chptr, source_p, msptr, NULL, NULL) == CHFL_BAN)
+                       return CAN_SEND_NO;
+       }
+
+       return CAN_SEND_NONOP;
+}
+
+/* find_bannickchange_channel()
+ * Input: client to check
+ * Output: channel preventing nick change
+ */
+struct Channel *
+find_bannickchange_channel(struct Client *client_p)
+{
+       struct Channel *chptr;
+       struct membership *msptr;
+       dlink_node *ptr;
+       char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
+       char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
+
+       if (!MyClient(client_p))
+               return NULL;
+
+       ircsprintf(src_host, "%s!%s@%s", client_p->name, client_p->username, client_p->host);
+       ircsprintf(src_iphost, "%s!%s@%s", client_p->name, client_p->username, client_p->sockhost);
+
+       DLINK_FOREACH(ptr, client_p->user->channel.head)
+       {
+               msptr = ptr->data;
+               chptr = msptr->chptr;
+               if (is_chanop_voiced(msptr))
+                       continue;
+               /* cached can_send */
+               if (msptr->bants == chptr->bants)
+               {
+                       if (can_send_banned(msptr))
+                               return chptr;
+               }
+               else if (is_banned(chptr, client_p, msptr, src_host, src_iphost) == CHFL_BAN
+                       || is_quieted(chptr, client_p, msptr, src_host, src_iphost) == CHFL_BAN)
+                       return chptr;
+       }
+       return NULL;
+}
+
+/* void check_spambot_warning(struct Client *source_p)
+ * Input: Client to check, channel name or NULL if this is a part.
+ * Output: none
+ * Side-effects: Updates the client's oper_warn_count_down, warns the
+ *    IRC operators if necessary, and updates join_leave_countdown as
+ *    needed.
+ */
+void
+check_spambot_warning(struct Client *source_p, const char *name)
+{
+       int t_delta;
+       int decrement_count;
+       if((GlobalSetOptions.spam_num &&
+           (source_p->localClient->join_leave_count >= GlobalSetOptions.spam_num)))
+       {
+               if(source_p->localClient->oper_warn_count_down > 0)
+                       source_p->localClient->oper_warn_count_down--;
+               else
+                       source_p->localClient->oper_warn_count_down = 0;
+               if(source_p->localClient->oper_warn_count_down == 0)
+               {
+                       /* Its already known as a possible spambot */
+                       if(name != NULL)
+                               sendto_realops_snomask(SNO_BOTS, L_ALL,
+                                                    "User %s (%s@%s) trying to join %s is a possible spambot",
+                                                    source_p->name,
+                                                    source_p->username, source_p->host, name);
+                       else
+                               sendto_realops_snomask(SNO_BOTS, L_ALL,
+                                                    "User %s (%s@%s) is a possible spambot",
+                                                    source_p->name,
+                                                    source_p->username, source_p->host);
+                       source_p->localClient->oper_warn_count_down = OPER_SPAM_COUNTDOWN;
+               }
+       }
+       else
+       {
+               if((t_delta =
+                   (CurrentTime - source_p->localClient->last_leave_time)) >
+                  JOIN_LEAVE_COUNT_EXPIRE_TIME)
+               {
+                       decrement_count = (t_delta / JOIN_LEAVE_COUNT_EXPIRE_TIME);
+                       if(decrement_count > source_p->localClient->join_leave_count)
+                               source_p->localClient->join_leave_count = 0;
+                       else
+                               source_p->localClient->join_leave_count -= decrement_count;
+               }
+               else
+               {
+                       if((CurrentTime -
+                           (source_p->localClient->last_join_time)) < GlobalSetOptions.spam_time)
+                       {
+                               /* oh, its a possible spambot */
+                               source_p->localClient->join_leave_count++;
+                       }
+               }
+               if(name != NULL)
+                       source_p->localClient->last_join_time = CurrentTime;
+               else
+                       source_p->localClient->last_leave_time = CurrentTime;
+       }
+}
+
+/* check_splitmode()
+ *
+ * input       -
+ * output      -
+ * side effects - compares usercount and servercount against their split
+ *                values and adjusts splitmode accordingly
+ */
+void
+check_splitmode(void *unused)
+{
+       if(splitchecking && (ConfigChannel.no_join_on_split || ConfigChannel.no_create_on_split))
+       {
+               /* not split, we're being asked to check now because someone
+                * has left
+                */
+               if(!splitmode)
+               {
+                       if(eob_count < split_servers || Count.total < split_users)
+                       {
+                               splitmode = 1;
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                                    "Network split, activating splitmode");
+                               eventAddIsh("check_splitmode", check_splitmode, NULL, 2);
+                       }
+               }
+               /* in splitmode, check whether its finished */
+               else if(eob_count >= split_servers && Count.total >= split_users)
+               {
+                       splitmode = 0;
+
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "Network rejoined, deactivating splitmode");
+
+                       eventDelete(check_splitmode, NULL);
+               }
+       }
+}
+
+
+/* allocate_topic()
+ *
+ * input       - channel to allocate topic for
+ * output      - 1 on success, else 0
+ * side effects - channel gets a topic allocated
+ */
+static void
+allocate_topic(struct Channel *chptr)
+{
+       void *ptr;
+
+       if(chptr == NULL)
+               return;
+
+       ptr = BlockHeapAlloc(topic_heap);
+
+       /* Basically we allocate one large block for the topic and
+        * the topic info.  We then split it up into two and shove it
+        * in the chptr 
+        */
+       chptr->topic = ptr;
+       chptr->topic_info = (char *) ptr + TOPICLEN + 1;
+       *chptr->topic = '\0';
+       *chptr->topic_info = '\0';
+}
+
+/* free_topic()
+ *
+ * input       - channel which has topic to free
+ * output      -
+ * side effects - channels topic is free'd
+ */
+static void
+free_topic(struct Channel *chptr)
+{
+       void *ptr;
+
+       if(chptr == NULL || chptr->topic == NULL)
+               return;
+
+       /* This is safe for now - If you change allocate_topic you
+        * MUST change this as well
+        */
+       ptr = chptr->topic;
+       BlockHeapFree(topic_heap, ptr);
+       chptr->topic = NULL;
+       chptr->topic_info = NULL;
+}
+
+/* set_channel_topic()
+ *
+ * input       - channel, topic to set, topic info and topic ts
+ * output      -
+ * side effects - channels topic, topic info and TS are set.
+ */
+void
+set_channel_topic(struct Channel *chptr, const char *topic, const char *topic_info, time_t topicts)
+{
+       if(strlen(topic) > 0)
+       {
+               if(chptr->topic == NULL)
+                       allocate_topic(chptr);
+               strlcpy(chptr->topic, topic, TOPICLEN + 1);
+               strlcpy(chptr->topic_info, topic_info, USERHOST_REPLYLEN);
+               chptr->topic_time = topicts;
+       }
+       else
+       {
+               if(chptr->topic != NULL)
+                       free_topic(chptr);
+               chptr->topic_time = 0;
+       }
+}
+
+static const struct mode_letter
+{
+       const unsigned int mode;
+       const unsigned char letter;
+} flags[] =
+{
+       {MODE_INVITEONLY, 'i'},
+       {MODE_MODERATED, 'm'},
+       {MODE_NOPRIVMSGS, 'n'},
+       {MODE_PRIVATE, 'p'},
+       {MODE_SECRET, 's'},
+       {MODE_TOPICLIMIT, 't'},
+       {MODE_NOCOLOR, 'c'},
+       {MODE_FREEINVITE, 'g'},
+       {MODE_OPMODERATE, 'z'},
+       {MODE_EXLIMIT, 'L'},
+       {MODE_PERMANENT, 'P'},
+       {MODE_FREETARGET, 'F'},
+       {MODE_DISFORWARD, 'Q'},
+       {MODE_REGONLY, 'r'},
+       {0, '\0'}
+};
+
+/* channel_modes()
+ *
+ * inputs       - pointer to channel
+ *              - pointer to client
+ * output       - NONE
+ * side effects - write the "simple" list of channel modes for channel
+ * chptr onto buffer mbuf with the parameters in pbuf.
+ *
+ * Stolen from ShadowIRCd 4 --nenolod
+ */
+const char *
+channel_modes(struct Channel *chptr, struct Client *client_p)
+{
+       int i;
+       char buf1[BUFSIZE];
+       char buf2[BUFSIZE];
+       static char final[BUFSIZE];
+       char *mbuf = buf1;
+       char *pbuf = buf2;
+
+       *mbuf++ = '+';
+       *pbuf = '\0';
+
+       for (i = 0; flags[i].mode; ++i)
+               if(chptr->mode.mode & flags[i].mode)
+                       *mbuf++ = flags[i].letter;
+
+       if(chptr->mode.limit)
+       {
+               *mbuf++ = 'l';
+
+               if(IsMember(client_p, chptr) || IsServer(client_p) || IsMe(client_p))
+                       pbuf += ircsprintf(pbuf, "%d ", chptr->mode.limit);
+       }
+
+       if(*chptr->mode.key)
+       {
+               *mbuf++ = 'k';
+
+               if(*pbuf || IsMember(client_p, chptr) || IsServer(client_p) || IsMe(client_p))
+                       pbuf += ircsprintf(pbuf, "%s ", chptr->mode.key);
+       }
+
+       if(chptr->mode.join_num)
+       {
+               *mbuf++ = 'j';
+
+               if(*pbuf || IsMember(client_p, chptr) || IsServer(client_p) || IsMe(client_p))
+                       pbuf += ircsprintf(pbuf, "%d:%d ", chptr->mode.join_num,
+                                          chptr->mode.join_time);
+       }
+
+       if(*chptr->mode.forward && (ConfigChannel.use_forward || IsServer(client_p) || IsMe(client_p)))
+       {
+               *mbuf++ = 'f';
+
+               if(*pbuf || IsMember(client_p, chptr) || IsServer(client_p) || IsMe(client_p))
+                       pbuf += ircsprintf(pbuf, "%s ", chptr->mode.forward);
+       }
+
+       *mbuf = '\0';
+
+       ircsprintf(final, "%s %s", buf1, buf2);
+       return final;
+}
+
+/* Now lets do some stuff to keep track of what combinations of
+ * servers exist...
+ * Note that the number of combinations doubles each time you add
+ * something to this list. Each one is only quick if no servers use that
+ * combination, but if the numbers get too high here MODE will get too
+ * slow. I suggest if you get more than 7 here, you consider getting rid
+ * of some and merging or something. If it wasn't for irc+cs we would
+ * probably not even need to bother about most of these, but unfortunately
+ * we do. -A1kmm
+ */
+
+/* void init_chcap_usage_counts(void)
+ *
+ * Inputs      - none
+ * Output      - none
+ * Side-effects        - Initialises the usage counts to zero. Fills in the
+ *                chcap_yes and chcap_no combination tables.
+ */
+void
+init_chcap_usage_counts(void)
+{
+       unsigned long m, c, y, n;
+
+       memset(chcap_combos, 0, sizeof(chcap_combos));
+
+       /* For every possible combination */
+       for (m = 0; m < NCHCAP_COMBOS; m++)
+       {
+               /* Check each capab */
+               for (c = y = n = 0; c < NCHCAPS; c++)
+               {
+                       if((m & (1 << c)) == 0)
+                               n |= channel_capabs[c];
+                       else
+                               y |= channel_capabs[c];
+               }
+               chcap_combos[m].cap_yes = y;
+               chcap_combos[m].cap_no = n;
+       }
+}
+
+/* void set_chcap_usage_counts(struct Client *serv_p)
+ * Input: serv_p; The client whose capabs to register.
+ * Output: none
+ * Side-effects: Increments the usage counts for the correct capab
+ *               combination.
+ */
+void
+set_chcap_usage_counts(struct Client *serv_p)
+{
+       int n;
+
+       for (n = 0; n < NCHCAP_COMBOS; n++)
+       {
+               if(IsCapable(serv_p, chcap_combos[n].cap_yes) &&
+                  NotCapable(serv_p, chcap_combos[n].cap_no))
+               {
+                       chcap_combos[n].count++;
+                       return;
+               }
+       }
+
+       /* This should be impossible -A1kmm. */
+       s_assert(0);
+}
+
+/* void set_chcap_usage_counts(struct Client *serv_p)
+ *
+ * Inputs      - serv_p; The client whose capabs to register.
+ * Output      - none
+ * Side-effects        - Decrements the usage counts for the correct capab
+ *                combination.
+ */
+void
+unset_chcap_usage_counts(struct Client *serv_p)
+{
+       int n;
+
+       for (n = 0; n < NCHCAP_COMBOS; n++)
+       {
+               if(IsCapable(serv_p, chcap_combos[n].cap_yes) &&
+                  NotCapable(serv_p, chcap_combos[n].cap_no))
+               {
+                       /* Hopefully capabs can't change dynamically or anything... */
+                       s_assert(chcap_combos[n].count > 0);
+
+                       if(chcap_combos[n].count > 0)
+                               chcap_combos[n].count--;
+                       return;
+               }
+       }
+
+       /* This should be impossible -A1kmm. */
+       s_assert(0);
+}
+
+/* void send_cap_mode_changes(struct Client *client_p,
+ *                        struct Client *source_p,
+ *                        struct Channel *chptr, int cap, int nocap)
+ * Input: The client sending(client_p), the source client(source_p),
+ *        the channel to send mode changes for(chptr)
+ * Output: None.
+ * Side-effects: Sends the appropriate mode changes to capable servers.
+ *
+ * Reverted back to my original design, except that we now keep a count
+ * of the number of servers which each combination as an optimisation, so
+ * the capabs combinations which are not needed are not worked out. -A1kmm
+ */
+void
+send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
+                     struct Channel *chptr, struct ChModeChange mode_changes[], int mode_count)
+{
+       static char modebuf[BUFSIZE];
+       static char parabuf[BUFSIZE];
+       int i, mbl, pbl, nc, mc, preflen, len;
+       char *pbuf;
+       const char *arg;
+       int dir;
+       int j;
+       int cap;
+       int nocap;
+       int arglen;
+
+       /* Now send to servers... */
+       for (j = 0; j < NCHCAP_COMBOS; j++)
+       {
+               if(chcap_combos[j].count == 0)
+                       continue;
+
+               mc = 0;
+               nc = 0;
+               pbl = 0;
+               parabuf[0] = 0;
+               pbuf = parabuf;
+               dir = MODE_QUERY;
+
+               cap = chcap_combos[j].cap_yes;
+               nocap = chcap_combos[j].cap_no;
+
+               if(cap & CAP_TS6)
+                       mbl = preflen = ircsprintf(modebuf, ":%s TMODE %ld %s ",
+                                                  use_id(source_p), (long) chptr->channelts,
+                                                  chptr->chname);
+               else
+                       mbl = preflen = ircsprintf(modebuf, ":%s MODE %s ",
+                                                  source_p->name, chptr->chname);
+
+               /* loop the list of - modes we have */
+               for (i = 0; i < mode_count; i++)
+               {
+                       /* if they dont support the cap we need, or they do support a cap they
+                        * cant have, then dont add it to the modebuf.. that way they wont see
+                        * the mode
+                        */
+                       if((mode_changes[i].letter == 0) ||
+                          ((cap & mode_changes[i].caps) != mode_changes[i].caps)
+                          || ((nocap & mode_changes[i].nocaps) != mode_changes[i].nocaps))
+                               continue;
+
+                       if((cap & CAP_TS6) && !EmptyString(mode_changes[i].id))
+                               arg = mode_changes[i].id;
+                       else
+                               arg = mode_changes[i].arg;
+
+                       if(arg)
+                       {
+                               arglen = strlen(arg);
+
+                               /* dont even think about it! --fl */
+                               if(arglen > MODEBUFLEN - 5)
+                                       continue;
+                       }
+
+                       /* if we're creeping past the buf size, we need to send it and make
+                        * another line for the other modes
+                        * XXX - this could give away server topology with uids being
+                        * different lengths, but not much we can do, except possibly break
+                        * them as if they were the longest of the nick or uid at all times,
+                        * which even then won't work as we don't always know the uid -A1kmm.
+                        */
+                       if(arg && ((mc == MAXMODEPARAMSSERV) ||
+                                  ((mbl + pbl + arglen + 4) > (BUFSIZE - 3))))
+                       {
+                               if(nc != 0)
+                                       sendto_server(client_p, chptr, cap, nocap,
+                                                     "%s %s", modebuf, parabuf);
+                               nc = 0;
+                               mc = 0;
+
+                               mbl = preflen;
+                               pbl = 0;
+                               pbuf = parabuf;
+                               parabuf[0] = 0;
+                               dir = MODE_QUERY;
+                       }
+
+                       if(dir != mode_changes[i].dir)
+                       {
+                               modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
+                               dir = mode_changes[i].dir;
+                       }
+
+                       modebuf[mbl++] = mode_changes[i].letter;
+                       modebuf[mbl] = 0;
+                       nc++;
+
+                       if(arg != NULL)
+                       {
+                               len = ircsprintf(pbuf, "%s ", arg);
+                               pbuf += len;
+                               pbl += len;
+                               mc++;
+                       }
+               }
+
+               if(pbl && parabuf[pbl - 1] == ' ')
+                       parabuf[pbl - 1] = 0;
+
+               if(nc != 0)
+                       sendto_server(client_p, chptr, cap, nocap, "%s %s", modebuf, parabuf);
+       }
+}
diff --git a/src/chmode.c b/src/chmode.c
new file mode 100644 (file)
index 0000000..1d8f711
--- /dev/null
@@ -0,0 +1,1590 @@
+/*
+ *  charybdis: A slightly useful ircd.
+ *  chmode.c: channel mode management
+ *
+ * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center 
+ * Copyright (C) 1996-2002 Hybrid Development Team 
+ * Copyright (C) 2002-2005 ircd-ratbox development team 
+ * Copyright (C) 2005-2006 charybdis development 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: chmode.c 3131 2007-01-21 15:36:31Z jilles $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "channel.h"
+#include "client.h"
+#include "common.h"
+#include "hash.h"
+#include "hook.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_serv.h"            /* captab */
+#include "s_user.h"
+#include "send.h"
+#include "whowas.h"
+#include "s_conf.h"            /* ConfigFileEntry, ConfigChannel */
+#include "s_newconf.h"
+#include "event.h"
+#include "memory.h"
+#include "balloc.h"
+#include "s_log.h"
+
+/* bitmasks for error returns, so we send once per call */
+#define SM_ERR_NOTS             0x00000001     /* No TS on channel */
+#define SM_ERR_NOOPS            0x00000002     /* No chan ops */
+#define SM_ERR_UNKNOWN          0x00000004
+#define SM_ERR_RPL_C            0x00000008
+#define SM_ERR_RPL_B            0x00000010
+#define SM_ERR_RPL_E            0x00000020
+#define SM_ERR_NOTONCHANNEL     0x00000040     /* Not on channel */
+#define SM_ERR_RPL_I            0x00000100
+#define SM_ERR_RPL_D            0x00000200
+#define SM_ERR_NOPRIVS          0x00000400
+#define SM_ERR_RPL_Q            0x00000800
+#define SM_ERR_RPL_F            0x00001000
+
+void set_channel_mode(struct Client *, struct Client *,
+                    struct Channel *, struct membership *, int, const char **);
+
+int add_id(struct Client *source_p, struct Channel *chptr,
+                 const char *banid, dlink_list * list, long mode_type);
+
+static struct ChModeChange mode_changes[BUFSIZE];
+static int mode_count;
+static int mode_limit;
+static int mask_pos;
+
+int
+get_channel_access(struct Client *source_p, struct membership *msptr)
+{
+       if(!MyClient(source_p) || is_chanop(msptr))
+               return CHFL_CHANOP;
+
+       return CHFL_PEON;
+}
+
+/* add_id()
+ *
+ * inputs      - client, channel, id to add, type
+ * outputs     - 0 on failure, 1 on success
+ * side effects - given id is added to the appropriate list
+ */
+int
+add_id(struct Client *source_p, struct Channel *chptr, const char *banid,
+       dlink_list * list, long mode_type)
+{
+       struct Ban *actualBan;
+       static char who[BANLEN];
+       char *realban = LOCAL_COPY(banid);
+       dlink_node *ptr;
+
+       /* dont let local clients overflow the banlist, or set redundant
+        * bans
+        */
+       if(MyClient(source_p))
+       {
+               if((dlink_list_length(&chptr->banlist) + dlink_list_length(&chptr->exceptlist) + dlink_list_length(&chptr->invexlist) + dlink_list_length(&chptr->quietlist)) >= (chptr->mode.mode & MODE_EXLIMIT ? ConfigChannel.max_bans_large : ConfigChannel.max_bans))
+               {
+                       sendto_one(source_p, form_str(ERR_BANLISTFULL),
+                                  me.name, source_p->name, chptr->chname, realban);
+                       return 0;
+               }
+
+               collapse(realban);
+
+               DLINK_FOREACH(ptr, list->head)
+               {
+                       actualBan = ptr->data;
+                       if(match(actualBan->banstr, realban))
+                               return 0;
+               }
+       }
+       /* dont let remotes set duplicates */
+       else
+       {
+               DLINK_FOREACH(ptr, list->head)
+               {
+                       actualBan = ptr->data;
+                       if(!irccmp(actualBan->banstr, realban))
+                               return 0;
+               }
+       }
+
+
+       if(IsPerson(source_p))
+               ircsprintf(who, "%s!%s@%s", source_p->name, source_p->username, source_p->host);
+       else
+               strlcpy(who, source_p->name, sizeof(who));
+
+       actualBan = allocate_ban(realban, who);
+       actualBan->when = CurrentTime;
+
+       dlinkAdd(actualBan, &actualBan->node, list);
+
+       /* invalidate the can_send() cache */
+       if(mode_type == CHFL_BAN || mode_type == CHFL_QUIET || mode_type == CHFL_EXCEPTION)
+               chptr->bants++;
+
+       return 1;
+}
+
+/* del_id()
+ *
+ * inputs      - channel, id to remove, type
+ * outputs     - 0 on failure, 1 on success
+ * side effects - given id is removed from the appropriate list
+ */
+int
+del_id(struct Channel *chptr, const char *banid, dlink_list * list, long mode_type)
+{
+       dlink_node *ptr;
+       struct Ban *banptr;
+
+       if(EmptyString(banid))
+               return 0;
+
+       DLINK_FOREACH(ptr, list->head)
+       {
+               banptr = ptr->data;
+
+               if(irccmp(banid, banptr->banstr) == 0)
+               {
+                       dlinkDelete(&banptr->node, list);
+                       free_ban(banptr);
+
+                       /* invalidate the can_send() cache */
+                       if(mode_type == CHFL_BAN || mode_type == CHFL_QUIET || mode_type == CHFL_EXCEPTION)
+                               chptr->bants++;
+
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+/* check_string()
+ *
+ * input       - string to check
+ * output      - pointer to 'fixed' string, or "*" if empty
+ * side effects - any white space found becomes \0
+ */
+static char *
+check_string(char *s)
+{
+       char *str = s;
+       static char splat[] = "*";
+       if(!(s && *s))
+               return splat;
+
+       for(; *s; ++s)
+       {
+               if(IsSpace(*s))
+               {
+                       *s = '\0';
+                       break;
+               }
+       }
+       return str;
+}
+
+/* pretty_mask()
+ *
+ * inputs      - mask to pretty
+ * outputs     - better version of the mask
+ * side effects - mask is chopped to limits, and transformed:
+ *                x!y@z => x!y@z
+ *                y@z   => *!y@z
+ *                x!y   => x!y@*
+ *                x     => x!*@*
+ *                z.d   => *!*@z.d
+ */
+static char *
+pretty_mask(const char *idmask)
+{
+       static char mask_buf[BUFSIZE];
+       int old_mask_pos;
+       char *nick, *user, *host;
+       char splat[] = "*";
+       char *t, *at, *ex;
+       char ne = 0, ue = 0, he = 0;    /* save values at nick[NICKLEN], et all */
+       char *mask;
+
+       mask = LOCAL_COPY(idmask);
+       mask = check_string(mask);
+       collapse(mask);
+
+       nick = user = host = splat;
+
+       if((size_t) BUFSIZE - mask_pos < strlen(mask) + 5)
+               return NULL;
+
+       old_mask_pos = mask_pos;
+
+       if (*mask == '$')
+       {
+               mask_pos += ircsprintf(mask_buf + mask_pos, "%s", mask) + 1;
+               t = mask_buf + old_mask_pos + 1;
+               if (*t == '!')
+                       *t = '~';
+               if (*t == '~')
+                       t++;
+               *t = ToLower(*t);
+               return mask_buf + old_mask_pos;
+       }
+
+       at = ex = NULL;
+       if((t = strchr(mask, '@')) != NULL)
+       {
+               at = t;
+               *t++ = '\0';
+               if(*t != '\0')
+                       host = t;
+
+               if((t = strchr(mask, '!')) != NULL)
+               {
+                       ex = t;
+                       *t++ = '\0';
+                       if(*t != '\0')
+                               user = t;
+                       if(*mask != '\0')
+                               nick = mask;
+               }
+               else
+               {
+                       if(*mask != '\0')
+                               user = mask;
+               }
+       }
+       else if((t = strchr(mask, '!')) != NULL)
+       {
+               ex = t;
+               *t++ = '\0';
+               if(*mask != '\0')
+                       nick = mask;
+               if(*t != '\0')
+                       user = t;
+       }
+       else if(strchr(mask, '.') != NULL || strchr(mask, ':') != NULL)
+       {
+               if(*mask != '\0')
+                       host = mask;
+       }
+       else
+       {
+               if(*mask != '\0')
+                       nick = mask;
+       }
+
+       /* truncate values to max lengths */
+       if(strlen(nick) > NICKLEN - 1)
+       {
+               ne = nick[NICKLEN - 1];
+               nick[NICKLEN - 1] = '\0';
+       }
+       if(strlen(user) > USERLEN)
+       {
+               ue = user[USERLEN];
+               user[USERLEN] = '\0';
+       }
+       if(strlen(host) > HOSTLEN)
+       {
+               he = host[HOSTLEN];
+               host[HOSTLEN] = '\0';
+       }
+
+       mask_pos += ircsprintf(mask_buf + mask_pos, "%s!%s@%s", nick, user, host) + 1;
+
+       /* restore mask, since we may need to use it again later */
+       if(at)
+               *at = '@';
+       if(ex)
+               *ex = '!';
+       if(ne)
+               nick[NICKLEN - 1] = ne;
+       if(ue)
+               user[USERLEN] = ue;
+       if(he)
+               host[HOSTLEN] = he;
+
+       return mask_buf + old_mask_pos;
+}
+
+/* fix_key()
+ *
+ * input       - key to fix
+ * output      - the same key, fixed
+ * side effects - anything below ascii 13 is discarded, ':' discarded,
+ *                high ascii is dropped to lower half of ascii table
+ */
+static char *
+fix_key(char *arg)
+{
+       u_char *s, *t, c;
+
+       for(s = t = (u_char *) arg; (c = *s); s++)
+       {
+               c &= 0x7f;
+               if(c != ':' && c != ',' && c > ' ')
+                       *t++ = c;
+       }
+
+       *t = '\0';
+       return arg;
+}
+
+/* fix_key_remote()
+ *
+ * input       - key to fix
+ * ouput       - the same key, fixed
+ * side effects - high ascii dropped to lower half of table,
+ *                CR/LF/':' are dropped
+ */
+static char *
+fix_key_remote(char *arg)
+{
+       u_char *s, *t, c;
+
+       for(s = t = (u_char *) arg; (c = *s); s++)
+       {
+               c &= 0x7f;
+               if((c != 0x0a) && (c != ':') && (c != ',') && (c != 0x0d) && (c != ' '))
+                       *t++ = c;
+       }
+
+       *t = '\0';
+       return arg;
+}
+
+/* chm_*()
+ *
+ * The handlers for each specific mode.
+ */
+void
+chm_nosuch(struct Client *source_p, struct Channel *chptr,
+          int alevel, int parc, int *parn,
+          const char **parv, int *errors, int dir, char c, long mode_type)
+{
+       if(*errors & SM_ERR_UNKNOWN)
+               return;
+       *errors |= SM_ERR_UNKNOWN;
+       sendto_one(source_p, form_str(ERR_UNKNOWNMODE), me.name, source_p->name, c);
+}
+
+void
+chm_simple(struct Client *source_p, struct Channel *chptr,
+          int alevel, int parc, int *parn,
+          const char **parv, int *errors, int dir, char c, long mode_type)
+{
+       if(alevel != CHFL_CHANOP)
+       {
+               if(!(*errors & SM_ERR_NOOPS))
+                       sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
+                                  me.name, source_p->name, chptr->chname);
+               *errors |= SM_ERR_NOOPS;
+               return;
+       }
+
+       /* +ntspmaikl == 9 + MAXMODEPARAMS (4 * +o) */
+       if(MyClient(source_p) && (++mode_limit > (9 + MAXMODEPARAMS)))
+               return;
+
+       /* setting + */
+       if((dir == MODE_ADD) && !(chptr->mode.mode & mode_type))
+       {
+               /* if +f is disabled, ignore an attempt to set +QF locally */
+               if(!ConfigChannel.use_forward && MyClient(source_p) &&
+                  (c == 'Q' || c == 'F'))
+                       return;
+
+               chptr->mode.mode |= mode_type;
+
+               mode_changes[mode_count].letter = c;
+               mode_changes[mode_count].dir = MODE_ADD;
+               mode_changes[mode_count].caps = 0;
+               mode_changes[mode_count].nocaps = 0;
+               mode_changes[mode_count].id = NULL;
+               mode_changes[mode_count].mems = ALL_MEMBERS;
+               mode_changes[mode_count++].arg = NULL;
+       }
+       else if((dir == MODE_DEL) && (chptr->mode.mode & mode_type))
+       {
+               chptr->mode.mode &= ~mode_type;
+
+               mode_changes[mode_count].letter = c;
+               mode_changes[mode_count].dir = MODE_DEL;
+               mode_changes[mode_count].caps = 0;
+               mode_changes[mode_count].nocaps = 0;
+               mode_changes[mode_count].mems = ALL_MEMBERS;
+               mode_changes[mode_count].id = NULL;
+               mode_changes[mode_count++].arg = NULL;
+       }
+}
+
+void
+chm_staff(struct Client *source_p, struct Channel *chptr,
+         int alevel, int parc, int *parn,
+         const char **parv, int *errors, int dir, char c, long mode_type)
+{
+       if(!IsOper(source_p) && !IsServer(source_p))
+       {
+               if(!(*errors & SM_ERR_NOPRIVS))
+                       sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES));
+               *errors |= SM_ERR_NOPRIVS;
+               return;
+       }
+
+       /* setting + */
+       if((dir == MODE_ADD) && !(chptr->mode.mode & mode_type))
+       {
+               chptr->mode.mode |= mode_type;
+
+               mode_changes[mode_count].letter = c;
+               mode_changes[mode_count].dir = MODE_ADD;
+               mode_changes[mode_count].caps = 0;
+               mode_changes[mode_count].nocaps = 0;
+               mode_changes[mode_count].id = NULL;
+               mode_changes[mode_count].mems = ALL_MEMBERS;
+               mode_changes[mode_count++].arg = NULL;
+       }
+       else if((dir == MODE_DEL) && (chptr->mode.mode & mode_type))
+       {
+               chptr->mode.mode &= ~mode_type;
+
+               mode_changes[mode_count].letter = c;
+               mode_changes[mode_count].dir = MODE_DEL;
+               mode_changes[mode_count].caps = 0;
+               mode_changes[mode_count].nocaps = 0;
+               mode_changes[mode_count].mems = ALL_MEMBERS;
+               mode_changes[mode_count].id = NULL;
+               mode_changes[mode_count++].arg = NULL;
+       }
+}
+
+void
+chm_ban(struct Client *source_p, struct Channel *chptr,
+       int alevel, int parc, int *parn,
+       const char **parv, int *errors, int dir, char c, long mode_type)
+{
+       const char *mask;
+       const char *raw_mask;
+       dlink_list *list;
+       dlink_node *ptr;
+       struct Ban *banptr;
+       int errorval;
+       int rpl_list;
+       int rpl_endlist;
+       int caps;
+       int mems;
+
+       switch (mode_type)
+       {
+       case CHFL_BAN:
+               list = &chptr->banlist;
+               errorval = SM_ERR_RPL_B;
+               rpl_list = RPL_BANLIST;
+               rpl_endlist = RPL_ENDOFBANLIST;
+               mems = ALL_MEMBERS;
+               caps = 0;
+               break;
+
+       case CHFL_EXCEPTION:
+               /* if +e is disabled, allow all but +e locally */
+               if(!ConfigChannel.use_except && MyClient(source_p) &&
+                  ((dir == MODE_ADD) && (parc > *parn)))
+                       return;
+
+               list = &chptr->exceptlist;
+               errorval = SM_ERR_RPL_E;
+               rpl_list = RPL_EXCEPTLIST;
+               rpl_endlist = RPL_ENDOFEXCEPTLIST;
+               caps = CAP_EX;
+
+               if(ConfigChannel.use_except || (dir == MODE_DEL))
+                       mems = ONLY_CHANOPS;
+               else
+                       mems = ONLY_SERVERS;
+               break;
+
+       case CHFL_INVEX:
+               /* if +I is disabled, allow all but +I locally */
+               if(!ConfigChannel.use_invex && MyClient(source_p) &&
+                  (dir == MODE_ADD) && (parc > *parn))
+                       return;
+
+               list = &chptr->invexlist;
+               errorval = SM_ERR_RPL_I;
+               rpl_list = RPL_INVITELIST;
+               rpl_endlist = RPL_ENDOFINVITELIST;
+               caps = CAP_IE;
+
+               if(ConfigChannel.use_invex || (dir == MODE_DEL))
+                       mems = ONLY_CHANOPS;
+               else
+                       mems = ONLY_SERVERS;
+               break;
+
+       case CHFL_QUIET:
+               list = &chptr->quietlist;
+               errorval = SM_ERR_RPL_Q;
+               rpl_list = RPL_BANLIST;
+               rpl_endlist = RPL_ENDOFBANLIST;
+               mems = ALL_MEMBERS;
+               caps = 0;
+               break;
+
+       default:
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "chm_ban() called with unknown type!");
+               return;
+               break;
+       }
+
+       if(dir == 0 || parc <= *parn)
+       {
+               if((*errors & errorval) != 0)
+                       return;
+               *errors |= errorval;
+
+               /* non-ops cant see +eI lists.. */
+               if(alevel != CHFL_CHANOP && mode_type != CHFL_BAN &&
+                               mode_type != CHFL_QUIET)
+               {
+                       if(!(*errors & SM_ERR_NOOPS))
+                               sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
+                                          me.name, source_p->name, chptr->chname);
+                       *errors |= SM_ERR_NOOPS;
+                       return;
+               }
+
+               DLINK_FOREACH(ptr, list->head)
+               {
+                       banptr = ptr->data;
+                       sendto_one(source_p, form_str(rpl_list),
+                                  me.name, source_p->name, chptr->chname,
+                                  banptr->banstr, banptr->who, banptr->when);
+               }
+               sendto_one(source_p, form_str(rpl_endlist), me.name, source_p->name, chptr->chname);
+               return;
+       }
+
+       if(alevel != CHFL_CHANOP)
+       {
+               if(!(*errors & SM_ERR_NOOPS))
+                       sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
+                                  me.name, source_p->name, chptr->chname);
+               *errors |= SM_ERR_NOOPS;
+               return;
+       }
+
+       if(MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
+               return;
+
+       raw_mask = parv[(*parn)];
+       (*parn)++;
+
+       /* empty ban, or starts with ':' which messes up s2s, ignore it */
+       if(EmptyString(raw_mask) || *raw_mask == ':')
+               return;
+
+       if(!MyClient(source_p))
+       {
+               if(strchr(raw_mask, ' '))
+                       return;
+
+               mask = raw_mask;
+       }
+       else
+               mask = pretty_mask(raw_mask);
+
+       /* we'd have problems parsing this, hyb6 does it too */
+       if(strlen(mask) > (MODEBUFLEN - 2))
+               return;
+
+       /* if we're adding a NEW id */
+       if(dir == MODE_ADD)
+       {
+               if (*mask == '$' && MyClient(source_p))
+               {
+                       if (!valid_extban(mask, source_p, chptr, mode_type))
+                               /* XXX perhaps return an error message here */
+                               return;
+               }
+
+               /* dont allow local clients to overflow the banlist, dont
+                * let remote servers set duplicate bans
+                */
+               if(!add_id(source_p, chptr, mask, list, mode_type))
+                       return;
+
+               mode_changes[mode_count].letter = c;
+               mode_changes[mode_count].dir = MODE_ADD;
+               mode_changes[mode_count].caps = caps;
+               mode_changes[mode_count].nocaps = 0;
+               mode_changes[mode_count].mems = mems;
+               mode_changes[mode_count].id = NULL;
+               mode_changes[mode_count++].arg = mask;
+       }
+       else if(dir == MODE_DEL)
+       {
+               if(del_id(chptr, mask, list, mode_type) == 0)
+               {
+                       /* mask isn't a valid ban, check raw_mask */
+                       if(del_id(chptr, raw_mask, list, mode_type))
+                               mask = raw_mask;
+               }
+
+               mode_changes[mode_count].letter = c;
+               mode_changes[mode_count].dir = MODE_DEL;
+               mode_changes[mode_count].caps = caps;
+               mode_changes[mode_count].nocaps = 0;
+               mode_changes[mode_count].mems = mems;
+               mode_changes[mode_count].id = NULL;
+               mode_changes[mode_count++].arg = mask;
+       }
+}
+
+void
+chm_op(struct Client *source_p, struct Channel *chptr,
+       int alevel, int parc, int *parn,
+       const char **parv, int *errors, int dir, char c, long mode_type)
+{
+       struct membership *mstptr;
+       const char *opnick;
+       struct Client *targ_p;
+
+       if(alevel != CHFL_CHANOP)
+       {
+               if(!(*errors & SM_ERR_NOOPS))
+                       sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
+                                  me.name, source_p->name, chptr->chname);
+               *errors |= SM_ERR_NOOPS;
+               return;
+       }
+
+       if((dir == MODE_QUERY) || (parc <= *parn))
+               return;
+
+       opnick = parv[(*parn)];
+       (*parn)++;
+
+       /* empty nick */
+       if(EmptyString(opnick))
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), "*");
+               return;
+       }
+
+       if((targ_p = find_chasing(source_p, opnick, NULL)) == NULL)
+       {
+               return;
+       }
+
+       mstptr = find_channel_membership(chptr, targ_p);
+
+       if(mstptr == NULL)
+       {
+               if(!(*errors & SM_ERR_NOTONCHANNEL) && MyClient(source_p))
+                       sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,
+                                          form_str(ERR_USERNOTINCHANNEL), opnick, chptr->chname);
+               *errors |= SM_ERR_NOTONCHANNEL;
+               return;
+       }
+
+       if(MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
+               return;
+
+       if(dir == MODE_ADD)
+       {
+               if(targ_p == source_p)
+                       return;
+
+               mode_changes[mode_count].letter = c;
+               mode_changes[mode_count].dir = MODE_ADD;
+               mode_changes[mode_count].caps = 0;
+               mode_changes[mode_count].nocaps = 0;
+               mode_changes[mode_count].mems = ALL_MEMBERS;
+               mode_changes[mode_count].id = targ_p->id;
+               mode_changes[mode_count].arg = targ_p->name;
+               mode_changes[mode_count++].client = targ_p;
+
+               mstptr->flags |= CHFL_CHANOP;
+               mstptr->flags &= ~CHFL_DEOPPED;
+       }
+       else
+       {
+               if(MyClient(source_p) && IsService(targ_p))
+               {
+                       sendto_one(source_p, form_str(ERR_ISCHANSERVICE),
+                                  me.name, source_p->name, targ_p->name, chptr->chname);
+                       return;
+               }
+
+               mode_changes[mode_count].letter = c;
+               mode_changes[mode_count].dir = MODE_DEL;
+               mode_changes[mode_count].caps = 0;
+               mode_changes[mode_count].nocaps = 0;
+               mode_changes[mode_count].mems = ALL_MEMBERS;
+               mode_changes[mode_count].id = targ_p->id;
+               mode_changes[mode_count].arg = targ_p->name;
+               mode_changes[mode_count++].client = targ_p;
+
+               mstptr->flags &= ~CHFL_CHANOP;
+       }
+}
+
+void
+chm_voice(struct Client *source_p, struct Channel *chptr,
+         int alevel, int parc, int *parn,
+         const char **parv, int *errors, int dir, char c, long mode_type)
+{
+       struct membership *mstptr;
+       const char *opnick;
+       struct Client *targ_p;
+
+       if(alevel != CHFL_CHANOP)
+       {
+               if(!(*errors & SM_ERR_NOOPS))
+                       sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
+                                  me.name, source_p->name, chptr->chname);
+               *errors |= SM_ERR_NOOPS;
+               return;
+       }
+
+       if((dir == MODE_QUERY) || parc <= *parn)
+               return;
+
+       opnick = parv[(*parn)];
+       (*parn)++;
+
+       /* empty nick */
+       if(EmptyString(opnick))
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), "*");
+               return;
+       }
+
+       if((targ_p = find_chasing(source_p, opnick, NULL)) == NULL)
+       {
+               return;
+       }
+
+       mstptr = find_channel_membership(chptr, targ_p);
+
+       if(mstptr == NULL)
+       {
+               if(!(*errors & SM_ERR_NOTONCHANNEL) && MyClient(source_p))
+                       sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,
+                                          form_str(ERR_USERNOTINCHANNEL), opnick, chptr->chname);
+               *errors |= SM_ERR_NOTONCHANNEL;
+               return;
+       }
+
+       if(MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
+               return;
+
+       if(dir == MODE_ADD)
+       {
+               mode_changes[mode_count].letter = c;
+               mode_changes[mode_count].dir = MODE_ADD;
+               mode_changes[mode_count].caps = 0;
+               mode_changes[mode_count].nocaps = 0;
+               mode_changes[mode_count].mems = ALL_MEMBERS;
+               mode_changes[mode_count].id = targ_p->id;
+               mode_changes[mode_count].arg = targ_p->name;
+               mode_changes[mode_count++].client = targ_p;
+
+               mstptr->flags |= CHFL_VOICE;
+       }
+       else
+       {
+               mode_changes[mode_count].letter = 'v';
+               mode_changes[mode_count].dir = MODE_DEL;
+               mode_changes[mode_count].caps = 0;
+               mode_changes[mode_count].nocaps = 0;
+               mode_changes[mode_count].mems = ALL_MEMBERS;
+               mode_changes[mode_count].id = targ_p->id;
+               mode_changes[mode_count].arg = targ_p->name;
+               mode_changes[mode_count++].client = targ_p;
+
+               mstptr->flags &= ~CHFL_VOICE;
+       }
+}
+
+void
+chm_limit(struct Client *source_p, struct Channel *chptr,
+         int alevel, int parc, int *parn,
+         const char **parv, int *errors, int dir, char c, long mode_type)
+{
+       const char *lstr;
+       static char limitstr[30];
+       int limit;
+
+       if(alevel != CHFL_CHANOP)
+       {
+               if(!(*errors & SM_ERR_NOOPS))
+                       sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
+                                  me.name, source_p->name, chptr->chname);
+               *errors |= SM_ERR_NOOPS;
+               return;
+       }
+
+       if(dir == MODE_QUERY)
+               return;
+
+       if((dir == MODE_ADD) && parc > *parn)
+       {
+               lstr = parv[(*parn)];
+               (*parn)++;
+
+               if(EmptyString(lstr) || (limit = atoi(lstr)) <= 0)
+                       return;
+
+               ircsprintf(limitstr, "%d", limit);
+
+               mode_changes[mode_count].letter = c;
+               mode_changes[mode_count].dir = MODE_ADD;
+               mode_changes[mode_count].caps = 0;
+               mode_changes[mode_count].nocaps = 0;
+               mode_changes[mode_count].mems = ALL_MEMBERS;
+               mode_changes[mode_count].id = NULL;
+               mode_changes[mode_count++].arg = limitstr;
+
+               chptr->mode.limit = limit;
+       }
+       else if(dir == MODE_DEL)
+       {
+               if(!chptr->mode.limit)
+                       return;
+
+               chptr->mode.limit = 0;
+
+               mode_changes[mode_count].letter = c;
+               mode_changes[mode_count].dir = MODE_DEL;
+               mode_changes[mode_count].caps = 0;
+               mode_changes[mode_count].nocaps = 0;
+               mode_changes[mode_count].mems = ALL_MEMBERS;
+               mode_changes[mode_count].id = NULL;
+               mode_changes[mode_count++].arg = NULL;
+       }
+}
+
+void
+chm_throttle(struct Client *source_p, struct Channel *chptr,
+            int alevel, int parc, int *parn,
+            const char **parv, int *errors, int dir, char c, long mode_type)
+{
+       int joins = 0, timeslice = 0;
+
+       if(alevel != CHFL_CHANOP)
+       {
+               if(!(*errors & SM_ERR_NOOPS))
+                       sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
+                                  me.name, source_p->name, chptr->chname);
+               *errors |= SM_ERR_NOOPS;
+               return;
+       }
+
+       if(dir == MODE_QUERY)
+               return;
+
+       if((dir == MODE_ADD) && parc > *parn)
+       {
+               sscanf(parv[(*parn)], "%d:%d", &joins, &timeslice);
+
+               if(!joins || !timeslice)
+                       return;
+
+               mode_changes[mode_count].letter = c;
+               mode_changes[mode_count].dir = MODE_ADD;
+               mode_changes[mode_count].caps = 0;
+               mode_changes[mode_count].nocaps = 0;
+               mode_changes[mode_count].mems = ALL_MEMBERS;
+               mode_changes[mode_count].id = NULL;
+               mode_changes[mode_count++].arg = parv[(*parn)];
+
+               (*parn)++;
+
+               chptr->mode.join_num = joins;
+               chptr->mode.join_time = timeslice;
+       }
+       else if(dir == MODE_DEL)
+       {
+               if(!chptr->mode.join_num)
+                       return;
+
+               chptr->mode.join_num = 0;
+               chptr->mode.join_time = 0;
+               chptr->join_count = 0;
+               chptr->join_delta = 0;
+
+               mode_changes[mode_count].letter = c;
+               mode_changes[mode_count].dir = MODE_DEL;
+               mode_changes[mode_count].caps = 0;
+               mode_changes[mode_count].nocaps = 0;
+               mode_changes[mode_count].mems = ALL_MEMBERS;
+               mode_changes[mode_count].id = NULL;
+               mode_changes[mode_count++].arg = NULL;
+       }
+}
+
+void
+chm_forward(struct Client *source_p, struct Channel *chptr,
+       int alevel, int parc, int *parn,
+       const char **parv, int *errors, int dir, char c, long mode_type)
+{
+       struct Channel *targptr = NULL;
+       struct membership *msptr;
+       const char *forward;
+
+       /* if +f is disabled, ignore local attempts to set it */
+       if(!ConfigChannel.use_forward && MyClient(source_p) &&
+          (dir == MODE_ADD) && (parc > *parn))
+               return;
+
+       if(dir == MODE_QUERY || (dir == MODE_ADD && parc <= *parn))
+       {
+               if (!(*errors & SM_ERR_RPL_F))
+               {
+                       if (*chptr->mode.forward == '\0')
+                               sendto_one(source_p, ":%s NOTICE %s :%s has no forward channel", me.name, source_p->name, chptr->chname);
+                       else
+                               sendto_one(source_p, ":%s NOTICE %s :%s forward channel is %s", me.name, source_p->name, chptr->chname, chptr->mode.forward);
+                       *errors |= SM_ERR_RPL_F;
+               }
+               return;
+       }
+
+#ifndef FORWARD_OPERONLY
+       if(alevel != CHFL_CHANOP)
+       {
+               if(!(*errors & SM_ERR_NOOPS))
+                       sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
+                                  me.name, source_p->name, chptr->chname);
+               *errors |= SM_ERR_NOOPS;
+               return;
+       }
+#else
+       if(!IsOper(source_p) && !IsServer(source_p))
+       {
+               if(!(*errors & SM_ERR_NOPRIVS))
+                       sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES));
+               *errors |= SM_ERR_NOPRIVS;
+               return;
+       }
+#endif
+
+       if(dir == MODE_ADD && parc > *parn)
+       {
+               forward = parv[(*parn)];
+               (*parn)++;
+
+               if(EmptyString(forward))
+                       return;
+               if(!check_channel_name(forward) ||
+                               (MyClient(source_p) && (strlen(forward) > LOC_CHANNELLEN || hash_find_resv(forward))))
+               {
+                       sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), forward);
+                       return;
+               }
+               /* don't forward to inconsistent target -- jilles */
+               if(chptr->chname[0] == '#' && forward[0] == '&')
+               {
+                       sendto_one_numeric(source_p, ERR_BADCHANNAME,
+                                          form_str(ERR_BADCHANNAME), forward);
+                       return;
+               }
+               if(MyClient(source_p) && (targptr = find_channel(forward)) == NULL)
+               {
+                       sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
+                                          form_str(ERR_NOSUCHCHANNEL), forward);
+                       return;
+               }
+               if(MyClient(source_p) && !(targptr->mode.mode & MODE_FREETARGET))
+               {
+                       if((msptr = find_channel_membership(targptr, source_p)) == NULL ||
+                               get_channel_access(source_p, msptr) != CHFL_CHANOP)
+                       {
+                               sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
+                                          me.name, source_p->name, targptr->chname);
+                               return;
+                       }
+               }
+
+               strlcpy(chptr->mode.forward, forward, sizeof(chptr->mode.forward));
+
+               mode_changes[mode_count].letter = c;
+               mode_changes[mode_count].dir = MODE_ADD;
+               mode_changes[mode_count].caps = 0;
+               mode_changes[mode_count].nocaps = 0;
+               mode_changes[mode_count].mems = ConfigChannel.use_forward ? ALL_MEMBERS : ONLY_SERVERS;
+               mode_changes[mode_count].id = NULL;
+               mode_changes[mode_count++].arg = forward;
+       }
+       else if(dir == MODE_DEL)
+       {
+               if(!(*chptr->mode.forward))
+                       return;
+
+               *chptr->mode.forward = '\0';
+
+               mode_changes[mode_count].letter = c;
+               mode_changes[mode_count].dir = MODE_DEL;
+               mode_changes[mode_count].caps = 0;
+               mode_changes[mode_count].nocaps = 0;
+               mode_changes[mode_count].mems = ALL_MEMBERS;
+               mode_changes[mode_count].id = NULL;
+               mode_changes[mode_count++].arg = NULL;
+       }
+}
+
+void
+chm_key(struct Client *source_p, struct Channel *chptr,
+       int alevel, int parc, int *parn,
+       const char **parv, int *errors, int dir, char c, long mode_type)
+{
+       char *key;
+
+       if(alevel != CHFL_CHANOP)
+       {
+               if(!(*errors & SM_ERR_NOOPS))
+                       sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
+                                  me.name, source_p->name, chptr->chname);
+               *errors |= SM_ERR_NOOPS;
+               return;
+       }
+
+       if(dir == MODE_QUERY)
+               return;
+
+       if((dir == MODE_ADD) && parc > *parn)
+       {
+               key = LOCAL_COPY(parv[(*parn)]);
+               (*parn)++;
+
+               if(MyClient(source_p))
+                       fix_key(key);
+               else
+                       fix_key_remote(key);
+
+               if(EmptyString(key))
+                       return;
+
+               s_assert(key[0] != ' ');
+               strlcpy(chptr->mode.key, key, sizeof(chptr->mode.key));
+
+               mode_changes[mode_count].letter = c;
+               mode_changes[mode_count].dir = MODE_ADD;
+               mode_changes[mode_count].caps = 0;
+               mode_changes[mode_count].nocaps = 0;
+               mode_changes[mode_count].mems = ALL_MEMBERS;
+               mode_changes[mode_count].id = NULL;
+               mode_changes[mode_count++].arg = chptr->mode.key;
+       }
+       else if(dir == MODE_DEL)
+       {
+               static char splat[] = "*";
+               int i;
+
+               if(parc > *parn)
+                       (*parn)++;
+
+               if(!(*chptr->mode.key))
+                       return;
+
+               /* hack time.  when we get a +k-k mode, the +k arg is
+                * chptr->mode.key, which the -k sets to \0, so hunt for a
+                * +k when we get a -k, and set the arg to splat. --anfl
+                */
+               for(i = 0; i < mode_count; i++)
+               {
+                       if(mode_changes[i].letter == 'k' && mode_changes[i].dir == MODE_ADD)
+                               mode_changes[i].arg = splat;
+               }
+
+               *chptr->mode.key = 0;
+
+               mode_changes[mode_count].letter = c;
+               mode_changes[mode_count].dir = MODE_DEL;
+               mode_changes[mode_count].caps = 0;
+               mode_changes[mode_count].nocaps = 0;
+               mode_changes[mode_count].mems = ALL_MEMBERS;
+               mode_changes[mode_count].id = NULL;
+               mode_changes[mode_count++].arg = "*";
+       }
+}
+
+void
+chm_regonly(struct Client *source_p, struct Channel *chptr,
+           int alevel, int parc, int *parn,
+           const char **parv, int *errors, int dir, char c, long mode_type)
+{
+       if(alevel != CHFL_CHANOP)
+       {
+               if(!(*errors & SM_ERR_NOOPS))
+                       sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
+                                  me.name, source_p->name, chptr->chname);
+               *errors |= SM_ERR_NOOPS;
+               return;
+       }
+
+       if(dir == MODE_QUERY)
+               return;
+
+       if(((dir == MODE_ADD) && (chptr->mode.mode & MODE_REGONLY)) ||
+          ((dir == MODE_DEL) && !(chptr->mode.mode & MODE_REGONLY)))
+               return;
+
+       if(dir == MODE_ADD)
+               chptr->mode.mode |= MODE_REGONLY;
+       else
+               chptr->mode.mode &= ~MODE_REGONLY;
+
+       mode_changes[mode_count].letter = c;
+       mode_changes[mode_count].dir = dir;
+       mode_changes[mode_count].caps = CAP_SERVICE;
+       mode_changes[mode_count].nocaps = 0;
+       mode_changes[mode_count].mems = ALL_MEMBERS;
+       mode_changes[mode_count].id = NULL;
+       mode_changes[mode_count++].arg = NULL;
+}
+
+/* *INDENT-OFF* */
+struct ChannelMode chmode_table[256] =
+{
+  {chm_nosuch,  0 },                   /* 0x00 */
+  {chm_nosuch,  0 },                   /* 0x01 */
+  {chm_nosuch,  0 },                   /* 0x02 */
+  {chm_nosuch,  0 },                   /* 0x03 */
+  {chm_nosuch,  0 },                   /* 0x04 */
+  {chm_nosuch,  0 },                   /* 0x05 */
+  {chm_nosuch,  0 },                   /* 0x06 */
+  {chm_nosuch,  0 },                   /* 0x07 */
+  {chm_nosuch,  0 },                   /* 0x08 */
+  {chm_nosuch,  0 },                   /* 0x09 */
+  {chm_nosuch,  0 },                   /* 0x0a */
+  {chm_nosuch,  0 },                   /* 0x0b */
+  {chm_nosuch,  0 },                   /* 0x0c */
+  {chm_nosuch,  0 },                   /* 0x0d */
+  {chm_nosuch,  0 },                   /* 0x0e */
+  {chm_nosuch,  0 },                   /* 0x0f */
+  {chm_nosuch,  0 },                   /* 0x10 */
+  {chm_nosuch,  0 },                   /* 0x11 */
+  {chm_nosuch,  0 },                   /* 0x12 */
+  {chm_nosuch,  0 },                   /* 0x13 */
+  {chm_nosuch,  0 },                   /* 0x14 */
+  {chm_nosuch,  0 },                   /* 0x15 */
+  {chm_nosuch,  0 },                   /* 0x16 */
+  {chm_nosuch,  0 },                   /* 0x17 */
+  {chm_nosuch,  0 },                   /* 0x18 */
+  {chm_nosuch,  0 },                   /* 0x19 */
+  {chm_nosuch,  0 },                   /* 0x1a */
+  {chm_nosuch,  0 },                   /* 0x1b */
+  {chm_nosuch,  0 },                   /* 0x1c */
+  {chm_nosuch,  0 },                   /* 0x1d */
+  {chm_nosuch,  0 },                   /* 0x1e */
+  {chm_nosuch,  0 },                   /* 0x1f */
+  {chm_nosuch,  0 },                   /* 0x20 */
+  {chm_nosuch,  0 },                   /* 0x21 */
+  {chm_nosuch,  0 },                   /* 0x22 */
+  {chm_nosuch,  0 },                   /* 0x23 */
+  {chm_nosuch,  0 },                   /* 0x24 */
+  {chm_nosuch,  0 },                   /* 0x25 */
+  {chm_nosuch,  0 },                   /* 0x26 */
+  {chm_nosuch,  0 },                   /* 0x27 */
+  {chm_nosuch,  0 },                   /* 0x28 */
+  {chm_nosuch,  0 },                   /* 0x29 */
+  {chm_nosuch,  0 },                   /* 0x2a */
+  {chm_nosuch,  0 },                   /* 0x2b */
+  {chm_nosuch,  0 },                   /* 0x2c */
+  {chm_nosuch,  0 },                   /* 0x2d */
+  {chm_nosuch,  0 },                   /* 0x2e */
+  {chm_nosuch,  0 },                   /* 0x2f */
+  {chm_nosuch,  0 },                   /* 0x30 */
+  {chm_nosuch,  0 },                   /* 0x31 */
+  {chm_nosuch,  0 },                   /* 0x32 */
+  {chm_nosuch,  0 },                   /* 0x33 */
+  {chm_nosuch,  0 },                   /* 0x34 */
+  {chm_nosuch,  0 },                   /* 0x35 */
+  {chm_nosuch,  0 },                   /* 0x36 */
+  {chm_nosuch,  0 },                   /* 0x37 */
+  {chm_nosuch,  0 },                   /* 0x38 */
+  {chm_nosuch,  0 },                   /* 0x39 */
+  {chm_nosuch,  0 },                   /* 0x3a */
+  {chm_nosuch,  0 },                   /* 0x3b */
+  {chm_nosuch,  0 },                   /* 0x3c */
+  {chm_nosuch,  0 },                   /* 0x3d */
+  {chm_nosuch,  0 },                   /* 0x3e */
+  {chm_nosuch,  0 },                   /* 0x3f */
+
+  {chm_nosuch, 0 },                    /* @ */
+  {chm_nosuch, 0 },                    /* A */
+  {chm_nosuch, 0 },                    /* B */
+  {chm_nosuch, 0 },                    /* C */
+  {chm_nosuch, 0 },                    /* D */
+  {chm_nosuch, 0 },                    /* E */
+  {chm_simple, MODE_FREETARGET },      /* F */
+  {chm_nosuch, 0 },                    /* G */
+  {chm_nosuch, 0 },                    /* H */
+  {chm_ban,    CHFL_INVEX },           /* I */
+  {chm_nosuch, 0 },                    /* J */
+  {chm_nosuch, 0 },                    /* K */
+  {chm_staff,  MODE_EXLIMIT },         /* L */
+  {chm_nosuch, 0 },                    /* M */
+  {chm_nosuch, 0 },                    /* N */
+  {chm_nosuch, 0 },                    /* O */
+  {chm_staff,  MODE_PERMANENT },       /* P */
+  {chm_simple, MODE_DISFORWARD },      /* Q */
+  {chm_nosuch, 0 },                    /* R */
+  {chm_nosuch, 0 },                    /* S */
+  {chm_nosuch, 0 },                    /* T */
+  {chm_nosuch, 0 },                    /* U */
+  {chm_nosuch, 0 },                    /* V */
+  {chm_nosuch, 0 },                    /* W */
+  {chm_nosuch, 0 },                    /* X */
+  {chm_nosuch, 0 },                    /* Y */
+  {chm_nosuch, 0 },                    /* Z */
+  {chm_nosuch, 0 },
+  {chm_nosuch, 0 },
+  {chm_nosuch, 0 },
+  {chm_nosuch, 0 },
+  {chm_nosuch, 0 },
+  {chm_nosuch, 0 },
+  {chm_nosuch, 0 },                    /* a */
+  {chm_ban,    CHFL_BAN },             /* b */
+  {chm_simple, MODE_NOCOLOR },         /* c */
+  {chm_nosuch, 0 },                    /* d */
+  {chm_ban,    CHFL_EXCEPTION },       /* e */
+  {chm_forward,        0 },                    /* f */
+  {chm_simple, MODE_FREEINVITE },      /* g */
+  {chm_nosuch, 0 },                    /* h */
+  {chm_simple, MODE_INVITEONLY },      /* i */
+  {chm_throttle, 0 },                  /* j */
+  {chm_key,    0 },                    /* k */
+  {chm_limit,  0 },                    /* l */
+  {chm_simple, MODE_MODERATED },       /* m */
+  {chm_simple, MODE_NOPRIVMSGS },      /* n */
+  {chm_op,     0 },                    /* o */
+  {chm_simple, MODE_PRIVATE },         /* p */
+  {chm_ban,    CHFL_QUIET },           /* q */
+  {chm_regonly, 0 },                   /* r */
+  {chm_simple, MODE_SECRET },          /* s */
+  {chm_simple, MODE_TOPICLIMIT },      /* t */
+  {chm_nosuch, 0 },                    /* u */
+  {chm_voice,  0 },                    /* v */
+  {chm_nosuch, 0 },                    /* w */
+  {chm_nosuch, 0 },                    /* x */
+  {chm_nosuch, 0 },                    /* y */
+  {chm_simple, MODE_OPMODERATE },      /* z */
+
+  {chm_nosuch,  0 },                   /* 0x7b */
+  {chm_nosuch,  0 },                   /* 0x7c */
+  {chm_nosuch,  0 },                   /* 0x7d */
+  {chm_nosuch,  0 },                   /* 0x7e */
+  {chm_nosuch,  0 },                   /* 0x7f */
+
+  {chm_nosuch,  0 },                   /* 0x80 */
+  {chm_nosuch,  0 },                   /* 0x81 */
+  {chm_nosuch,  0 },                   /* 0x82 */
+  {chm_nosuch,  0 },                   /* 0x83 */
+  {chm_nosuch,  0 },                   /* 0x84 */
+  {chm_nosuch,  0 },                   /* 0x85 */
+  {chm_nosuch,  0 },                   /* 0x86 */
+  {chm_nosuch,  0 },                   /* 0x87 */
+  {chm_nosuch,  0 },                   /* 0x88 */
+  {chm_nosuch,  0 },                   /* 0x89 */
+  {chm_nosuch,  0 },                   /* 0x8a */
+  {chm_nosuch,  0 },                   /* 0x8b */
+  {chm_nosuch,  0 },                   /* 0x8c */
+  {chm_nosuch,  0 },                   /* 0x8d */
+  {chm_nosuch,  0 },                   /* 0x8e */
+  {chm_nosuch,  0 },                   /* 0x8f */
+
+  {chm_nosuch,  0 },                   /* 0x90 */
+  {chm_nosuch,  0 },                   /* 0x91 */
+  {chm_nosuch,  0 },                   /* 0x92 */
+  {chm_nosuch,  0 },                   /* 0x93 */
+  {chm_nosuch,  0 },                   /* 0x94 */
+  {chm_nosuch,  0 },                   /* 0x95 */
+  {chm_nosuch,  0 },                   /* 0x96 */
+  {chm_nosuch,  0 },                   /* 0x97 */
+  {chm_nosuch,  0 },                   /* 0x98 */
+  {chm_nosuch,  0 },                   /* 0x99 */
+  {chm_nosuch,  0 },                   /* 0x9a */
+  {chm_nosuch,  0 },                   /* 0x9b */
+  {chm_nosuch,  0 },                   /* 0x9c */
+  {chm_nosuch,  0 },                   /* 0x9d */
+  {chm_nosuch,  0 },                   /* 0x9e */
+  {chm_nosuch,  0 },                   /* 0x9f */
+
+  {chm_nosuch,  0 },                   /* 0xa0 */
+  {chm_nosuch,  0 },                   /* 0xa1 */
+  {chm_nosuch,  0 },                   /* 0xa2 */
+  {chm_nosuch,  0 },                   /* 0xa3 */
+  {chm_nosuch,  0 },                   /* 0xa4 */
+  {chm_nosuch,  0 },                   /* 0xa5 */
+  {chm_nosuch,  0 },                   /* 0xa6 */
+  {chm_nosuch,  0 },                   /* 0xa7 */
+  {chm_nosuch,  0 },                   /* 0xa8 */
+  {chm_nosuch,  0 },                   /* 0xa9 */
+  {chm_nosuch,  0 },                   /* 0xaa */
+  {chm_nosuch,  0 },                   /* 0xab */
+  {chm_nosuch,  0 },                   /* 0xac */
+  {chm_nosuch,  0 },                   /* 0xad */
+  {chm_nosuch,  0 },                   /* 0xae */
+  {chm_nosuch,  0 },                   /* 0xaf */
+
+  {chm_nosuch,  0 },                   /* 0xb0 */
+  {chm_nosuch,  0 },                   /* 0xb1 */
+  {chm_nosuch,  0 },                   /* 0xb2 */
+  {chm_nosuch,  0 },                   /* 0xb3 */
+  {chm_nosuch,  0 },                   /* 0xb4 */
+  {chm_nosuch,  0 },                   /* 0xb5 */
+  {chm_nosuch,  0 },                   /* 0xb6 */
+  {chm_nosuch,  0 },                   /* 0xb7 */
+  {chm_nosuch,  0 },                   /* 0xb8 */
+  {chm_nosuch,  0 },                   /* 0xb9 */
+  {chm_nosuch,  0 },                   /* 0xba */
+  {chm_nosuch,  0 },                   /* 0xbb */
+  {chm_nosuch,  0 },                   /* 0xbc */
+  {chm_nosuch,  0 },                   /* 0xbd */
+  {chm_nosuch,  0 },                   /* 0xbe */
+  {chm_nosuch,  0 },                   /* 0xbf */
+
+  {chm_nosuch,  0 },                   /* 0xc0 */
+  {chm_nosuch,  0 },                   /* 0xc1 */
+  {chm_nosuch,  0 },                   /* 0xc2 */
+  {chm_nosuch,  0 },                   /* 0xc3 */
+  {chm_nosuch,  0 },                   /* 0xc4 */
+  {chm_nosuch,  0 },                   /* 0xc5 */
+  {chm_nosuch,  0 },                   /* 0xc6 */
+  {chm_nosuch,  0 },                   /* 0xc7 */
+  {chm_nosuch,  0 },                   /* 0xc8 */
+  {chm_nosuch,  0 },                   /* 0xc9 */
+  {chm_nosuch,  0 },                   /* 0xca */
+  {chm_nosuch,  0 },                   /* 0xcb */
+  {chm_nosuch,  0 },                   /* 0xcc */
+  {chm_nosuch,  0 },                   /* 0xcd */
+  {chm_nosuch,  0 },                   /* 0xce */
+  {chm_nosuch,  0 },                   /* 0xcf */
+
+  {chm_nosuch,  0 },                   /* 0xd0 */
+  {chm_nosuch,  0 },                   /* 0xd1 */
+  {chm_nosuch,  0 },                   /* 0xd2 */
+  {chm_nosuch,  0 },                   /* 0xd3 */
+  {chm_nosuch,  0 },                   /* 0xd4 */
+  {chm_nosuch,  0 },                   /* 0xd5 */
+  {chm_nosuch,  0 },                   /* 0xd6 */
+  {chm_nosuch,  0 },                   /* 0xd7 */
+  {chm_nosuch,  0 },                   /* 0xd8 */
+  {chm_nosuch,  0 },                   /* 0xd9 */
+  {chm_nosuch,  0 },                   /* 0xda */
+  {chm_nosuch,  0 },                   /* 0xdb */
+  {chm_nosuch,  0 },                   /* 0xdc */
+  {chm_nosuch,  0 },                   /* 0xdd */
+  {chm_nosuch,  0 },                   /* 0xde */
+  {chm_nosuch,  0 },                   /* 0xdf */
+
+  {chm_nosuch,  0 },                   /* 0xe0 */
+  {chm_nosuch,  0 },                   /* 0xe1 */
+  {chm_nosuch,  0 },                   /* 0xe2 */
+  {chm_nosuch,  0 },                   /* 0xe3 */
+  {chm_nosuch,  0 },                   /* 0xe4 */
+  {chm_nosuch,  0 },                   /* 0xe5 */
+  {chm_nosuch,  0 },                   /* 0xe6 */
+  {chm_nosuch,  0 },                   /* 0xe7 */
+  {chm_nosuch,  0 },                   /* 0xe8 */
+  {chm_nosuch,  0 },                   /* 0xe9 */
+  {chm_nosuch,  0 },                   /* 0xea */
+  {chm_nosuch,  0 },                   /* 0xeb */
+  {chm_nosuch,  0 },                   /* 0xec */
+  {chm_nosuch,  0 },                   /* 0xed */
+  {chm_nosuch,  0 },                   /* 0xee */
+  {chm_nosuch,  0 },                   /* 0xef */
+
+  {chm_nosuch,  0 },                   /* 0xf0 */
+  {chm_nosuch,  0 },                   /* 0xf1 */
+  {chm_nosuch,  0 },                   /* 0xf2 */
+  {chm_nosuch,  0 },                   /* 0xf3 */
+  {chm_nosuch,  0 },                   /* 0xf4 */
+  {chm_nosuch,  0 },                   /* 0xf5 */
+  {chm_nosuch,  0 },                   /* 0xf6 */
+  {chm_nosuch,  0 },                   /* 0xf7 */
+  {chm_nosuch,  0 },                   /* 0xf8 */
+  {chm_nosuch,  0 },                   /* 0xf9 */
+  {chm_nosuch,  0 },                   /* 0xfa */
+  {chm_nosuch,  0 },                   /* 0xfb */
+  {chm_nosuch,  0 },                   /* 0xfc */
+  {chm_nosuch,  0 },                   /* 0xfd */
+  {chm_nosuch,  0 },                   /* 0xfe */
+  {chm_nosuch,  0 },                   /* 0xff */
+};
+
+/* *INDENT-ON* */
+
+/* set_channel_mode()
+ *
+ * inputs      - client, source, channel, membership pointer, params
+ * output      - 
+ * side effects - channel modes/memberships are changed, MODE is issued
+ *
+ * Extensively modified to be hotpluggable, 03/09/06 -- nenolod
+ */
+void
+set_channel_mode(struct Client *client_p, struct Client *source_p,
+                struct Channel *chptr, struct membership *msptr, int parc, const char *parv[])
+{
+       static char modebuf[BUFSIZE];
+       static char parabuf[BUFSIZE];
+       char *mbuf;
+       char *pbuf;
+       int cur_len, mlen, paralen, paracount, arglen, len;
+       int i, j, flags;
+       int dir = MODE_ADD;
+       int parn = 1;
+       int errors = 0;
+       int alevel;
+       const char *ml = parv[0];
+       char c;
+       struct Client *fakesource_p;
+
+       mask_pos = 0;
+       mode_count = 0;
+       mode_limit = 0;
+
+       alevel = get_channel_access(source_p, msptr);
+
+       /* Hide connecting server on netburst -- jilles */
+       if (ConfigServerHide.flatten_links && IsServer(source_p) && !has_id(source_p) && !HasSentEob(source_p))
+               fakesource_p = &me;
+       else
+               fakesource_p = source_p;
+
+       for(; (c = *ml) != 0; ml++)
+       {
+               switch (c)
+               {
+               case '+':
+                       dir = MODE_ADD;
+                       break;
+               case '-':
+                       dir = MODE_DEL;
+                       break;
+               case '=':
+                       dir = MODE_QUERY;
+                       break;
+               default:
+                       chmode_table[(unsigned char) c].set_func(fakesource_p, chptr, alevel,
+                                      parc, &parn, parv,
+                                      &errors, dir, c,
+                                      chmode_table[(unsigned char) c].mode_type);
+                       break;
+               }
+       }
+
+       /* bail out if we have nothing to do... */
+       if(!mode_count)
+               return;
+
+       if(IsServer(source_p))
+               mlen = ircsprintf(modebuf, ":%s MODE %s ", fakesource_p->name, chptr->chname);
+       else
+               mlen = ircsprintf(modebuf, ":%s!%s@%s MODE %s ",
+                                 source_p->name, source_p->username,
+                                 source_p->host, chptr->chname);
+
+       for(j = 0, flags = ALL_MEMBERS; j < 2; j++, flags = ONLY_CHANOPS)
+       {
+               cur_len = mlen;
+               mbuf = modebuf + mlen;
+               pbuf = parabuf;
+               parabuf[0] = '\0';
+               paracount = paralen = 0;
+               dir = MODE_QUERY;
+
+               for(i = 0; i < mode_count; i++)
+               {
+                       if(mode_changes[i].letter == 0 || mode_changes[i].mems != flags)
+                               continue;
+
+                       if(mode_changes[i].arg != NULL)
+                       {
+                               arglen = strlen(mode_changes[i].arg);
+
+                               if(arglen > MODEBUFLEN - 5)
+                                       continue;
+                       }
+                       else
+                               arglen = 0;
+
+                       /* if we're creeping over MAXMODEPARAMSSERV, or over
+                        * bufsize (4 == +/-,modechar,two spaces) send now.
+                        */
+                       if(mode_changes[i].arg != NULL &&
+                          ((paracount == MAXMODEPARAMSSERV) ||
+                           ((cur_len + paralen + arglen + 4) > (BUFSIZE - 3))))
+                       {
+                               *mbuf = '\0';
+
+                               if(cur_len > mlen)
+                                       sendto_channel_local(flags, chptr, "%s %s", modebuf,
+                                                            parabuf);
+                               else
+                                       continue;
+
+                               paracount = paralen = 0;
+                               cur_len = mlen;
+                               mbuf = modebuf + mlen;
+                               pbuf = parabuf;
+                               parabuf[0] = '\0';
+                               dir = MODE_QUERY;
+                       }
+
+                       if(dir != mode_changes[i].dir)
+                       {
+                               *mbuf++ = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
+                               cur_len++;
+                               dir = mode_changes[i].dir;
+                       }
+
+                       *mbuf++ = mode_changes[i].letter;
+                       cur_len++;
+
+                       if(mode_changes[i].arg != NULL)
+                       {
+                               paracount++;
+                               len = ircsprintf(pbuf, "%s ", mode_changes[i].arg);
+                               pbuf += len;
+                               paralen += len;
+                       }
+               }
+
+               if(paralen && parabuf[paralen - 1] == ' ')
+                       parabuf[paralen - 1] = '\0';
+
+               *mbuf = '\0';
+               if(cur_len > mlen)
+                       sendto_channel_local(flags, chptr, "%s %s", modebuf, parabuf);
+       }
+
+       /* only propagate modes originating locally, or if we're hubbing */
+       if(MyClient(source_p) || dlink_list_length(&serv_list) > 1)
+               send_cap_mode_changes(client_p, source_p, chptr, mode_changes, mode_count);
+}
diff --git a/src/class.c b/src/class.c
new file mode 100644 (file)
index 0000000..95f7b8f
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  class.c: Controls connection classes.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: class.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "config.h"
+
+#include "tools.h"
+#include "class.h"
+#include "client.h"
+#include "common.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "send.h"
+#include "irc_string.h"
+#include "memory.h"
+#include "patricia.h"
+
+#define BAD_CONF_CLASS          -1
+#define BAD_PING                -2
+#define BAD_CLIENT_CLASS        -3
+
+dlink_list class_list;
+struct Class *default_class;
+
+struct Class *
+make_class(void)
+{
+       struct Class *tmp;
+
+       tmp = (struct Class *) MyMalloc(sizeof(struct Class));
+
+       ConFreq(tmp) = DEFAULT_CONNECTFREQUENCY;
+       PingFreq(tmp) = DEFAULT_PINGFREQUENCY;
+       MaxUsers(tmp) = 1;
+       MaxSendq(tmp) = DEFAULT_SENDQ;
+
+       tmp->ip_limits = New_Patricia(PATRICIA_BITS);
+       return tmp;
+}
+
+void
+free_class(struct Class *tmp)
+{
+       if(tmp->ip_limits)
+               Destroy_Patricia(tmp->ip_limits, NULL);
+
+       MyFree(tmp->class_name);
+       MyFree(tmp);
+
+}
+
+/*
+ * get_conf_ping
+ *
+ * inputs      - pointer to struct ConfItem
+ * output      - ping frequency
+ * side effects - NONE
+ */
+static int
+get_conf_ping(struct ConfItem *aconf)
+{
+       if((aconf) && ClassPtr(aconf))
+               return (ConfPingFreq(aconf));
+
+       return (BAD_PING);
+}
+
+/*
+ * get_client_class
+ *
+ * inputs      - pointer to client struct
+ * output      - pointer to name of class
+ * side effects - NONE
+ */
+const char *
+get_client_class(struct Client *target_p)
+{
+       const char *retc = "unknown";
+
+       if(target_p == NULL || IsMe(target_p))
+               return retc;
+
+       if(IsServer(target_p))
+       {
+               struct server_conf *server_p = target_p->localClient->att_sconf;
+               return server_p->class_name;
+       }
+       else
+       {
+               struct ConfItem *aconf;
+               aconf = target_p->localClient->att_conf;
+
+               if((aconf == NULL) || (aconf->className == NULL))
+                       retc = "default";
+               else
+                       retc = aconf->className;
+       }
+
+       return (retc);
+}
+
+/*
+ * get_client_ping
+ *
+ * inputs      - pointer to client struct
+ * output      - ping frequency
+ * side effects - NONE
+ */
+int
+get_client_ping(struct Client *target_p)
+{
+       int ping = 0;
+
+       if(IsServer(target_p))
+       {
+               struct server_conf *server_p = target_p->localClient->att_sconf;
+               ping = PingFreq(server_p->class);
+       }
+       else
+       {
+               struct ConfItem *aconf;
+
+               aconf = target_p->localClient->att_conf;
+
+               if(aconf != NULL)
+                       ping = get_conf_ping(aconf);
+               else
+                       ping = DEFAULT_PINGFREQUENCY;
+       }
+
+       if(ping <= 0)
+               ping = DEFAULT_PINGFREQUENCY;
+
+       return ping;
+}
+
+/*
+ * get_con_freq
+ *
+ * inputs      - pointer to class struct
+ * output      - connection frequency
+ * side effects - NONE
+ */
+int
+get_con_freq(struct Class *clptr)
+{
+       if(clptr)
+               return (ConFreq(clptr));
+       return (DEFAULT_CONNECTFREQUENCY);
+}
+
+/* add_class()
+ *
+ * input       - class to add
+ * output      -
+ * side effects - class is added to class_list if new, else old class
+ *                is updated with new values.
+ */
+void
+add_class(struct Class *classptr)
+{
+       struct Class *tmpptr;
+
+       tmpptr = find_class(classptr->class_name);
+
+       if(tmpptr == default_class)
+       {
+               dlinkAddAlloc(classptr, &class_list);
+               CurrUsers(classptr) = 0;
+       }
+       else
+       {
+               MaxUsers(tmpptr) = MaxUsers(classptr);
+               MaxLocal(tmpptr) = MaxLocal(classptr);
+               MaxGlobal(tmpptr) = MaxGlobal(classptr);
+               MaxIdent(tmpptr) = MaxIdent(classptr);
+               PingFreq(tmpptr) = PingFreq(classptr);
+               MaxSendq(tmpptr) = MaxSendq(classptr);
+               ConFreq(tmpptr) = ConFreq(classptr);
+               CidrBitlen(tmpptr) = CidrBitlen(classptr);
+               CidrAmount(tmpptr) = CidrAmount(classptr);
+
+               free_class(classptr);
+       }
+}
+
+
+/*
+ * find_class
+ *
+ * inputs      - string name of class
+ * output      - corresponding class pointer
+ * side effects        - NONE
+ */
+struct Class *
+find_class(const char *classname)
+{
+       struct Class *cltmp;
+       dlink_node *ptr;
+
+       if(classname == NULL)
+               return default_class;
+
+       DLINK_FOREACH(ptr, class_list.head)
+       {
+               cltmp = ptr->data;
+
+               if(!strcmp(ClassName(cltmp), classname))
+                       return cltmp;
+       }
+
+       return default_class;
+}
+
+/*
+ * check_class
+ *
+ * inputs      - NONE
+ * output      - NONE
+ * side effects        - 
+ */
+void
+check_class()
+{
+       struct Class *cltmp;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, class_list.head)
+       {
+               cltmp = ptr->data;
+
+               if(MaxUsers(cltmp) < 0)
+               {
+                       dlinkDestroy(ptr, &class_list);
+                       if(CurrUsers(cltmp) <= 0)
+                               free_class(cltmp);
+               }
+       }
+}
+
+/*
+ * initclass
+ *
+ * inputs      - NONE
+ * output      - NONE
+ * side effects        - 
+ */
+void
+initclass()
+{
+       default_class = make_class();
+       DupString(ClassName(default_class), "default");
+}
+
+/*
+ * report_classes
+ *
+ * inputs      - pointer to client to report to
+ * output      - NONE
+ * side effects        - class report is done to this client
+ */
+void
+report_classes(struct Client *source_p)
+{
+       struct Class *cltmp;
+       dlink_node *ptr;
+
+       DLINK_FOREACH(ptr, class_list.head)
+       {
+               cltmp = ptr->data;
+
+               sendto_one_numeric(source_p, RPL_STATSYLINE, 
+                               form_str(RPL_STATSYLINE),
+                               ClassName(cltmp), PingFreq(cltmp), 
+                               ConFreq(cltmp), MaxUsers(cltmp), 
+                               MaxSendq(cltmp), 
+                               MaxLocal(cltmp), MaxIdent(cltmp),
+                               MaxGlobal(cltmp), MaxIdent(cltmp),
+                               CurrUsers(cltmp));
+       }
+
+       /* also output the default class */
+       sendto_one_numeric(source_p, RPL_STATSYLINE, form_str(RPL_STATSYLINE),
+                       ClassName(default_class), PingFreq(default_class), 
+                       ConFreq(default_class), MaxUsers(default_class), 
+                       MaxSendq(default_class), 
+                       MaxLocal(default_class), MaxIdent(default_class),
+                       MaxGlobal(default_class), MaxIdent(default_class),
+                       CurrUsers(default_class));
+}
+
+/*
+ * get_sendq
+ *
+ * inputs      - pointer to client
+ * output      - sendq for this client as found from its class
+ * side effects        - NONE
+ */
+long
+get_sendq(struct Client *client_p)
+{
+       if(client_p == NULL || IsMe(client_p))
+               return DEFAULT_SENDQ;
+
+       if(IsServer(client_p))
+       {
+               struct server_conf *server_p;
+               server_p = client_p->localClient->att_sconf;
+               return MaxSendq(server_p->class);
+       }
+       else
+       {
+               struct ConfItem *aconf = client_p->localClient->att_conf;
+
+               if(aconf != NULL && aconf->status & CONF_CLIENT)
+                       return ConfMaxSendq(aconf);
+       }
+
+       return DEFAULT_SENDQ;
+}
diff --git a/src/client.c b/src/client.c
new file mode 100644 (file)
index 0000000..eea5429
--- /dev/null
@@ -0,0 +1,2182 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  client.c: Controls clients.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: client.c 1861 2006-08-26 23:21:42Z jilles $
+ */
+#include "stdinc.h"
+#include "config.h"
+
+#include "tools.h"
+#include "client.h"
+#include "class.h"
+#include "common.h"
+#include "event.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "s_gline.h"
+#include "numeric.h"
+#include "packet.h"
+#include "s_auth.h"
+#include "commio.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "s_log.h"
+#include "s_serv.h"
+#include "s_stats.h"
+#include "send.h"
+#include "whowas.h"
+#include "s_user.h"
+#include "linebuf.h"
+#include "hash.h"
+#include "memory.h"
+#include "hostmask.h"
+#include "balloc.h"
+#include "listener.h"
+#include "hook.h"
+#include "msg.h"
+#include "monitor.h"
+#include "blacklist.h"
+
+#define DEBUG_EXITED_CLIENTS
+
+static void check_pings_list(dlink_list * list);
+static void check_unknowns_list(dlink_list * list);
+static void free_exited_clients(void *unused);
+static void exit_aborted_clients(void *unused);
+
+static int exit_remote_client(struct Client *, struct Client *, struct Client *,const char *);
+static int exit_remote_server(struct Client *, struct Client *, struct Client *,const char *);
+static int exit_local_client(struct Client *, struct Client *, struct Client *,const char *);
+static int exit_unknown_client(struct Client *, struct Client *, struct Client *,const char *);
+static int exit_local_server(struct Client *, struct Client *, struct Client *,const char *);
+static int qs_server(struct Client *, struct Client *, struct Client *, const char *comment);
+
+static EVH check_pings;
+
+extern BlockHeap *client_heap;
+extern BlockHeap *lclient_heap;
+extern BlockHeap *pclient_heap;
+
+extern char current_uid[IDLEN];
+
+enum
+{
+       D_LINED,
+       K_LINED,
+       G_LINED
+};
+
+dlink_list dead_list;
+#ifdef DEBUG_EXITED_CLIENTS
+static dlink_list dead_remote_list;
+#endif
+
+struct abort_client
+{
+       dlink_node node;
+       struct Client *client;
+       char notice[REASONLEN];
+};
+
+static dlink_list abort_list;
+
+
+/*
+ * init_client
+ *
+ * inputs      - NONE
+ * output      - NONE
+ * side effects        - initialize client free memory
+ */
+void
+init_client(void)
+{
+       /*
+        * start off the check ping event ..  -- adrian
+        * Every 30 seconds is plenty -- db
+        */
+       client_heap = BlockHeapCreate(sizeof(struct Client), CLIENT_HEAP_SIZE);
+       lclient_heap = BlockHeapCreate(sizeof(struct LocalUser), LCLIENT_HEAP_SIZE);
+       pclient_heap = BlockHeapCreate(sizeof(struct PreClient), PCLIENT_HEAP_SIZE);
+       eventAddIsh("check_pings", check_pings, NULL, 30);
+       eventAddIsh("free_exited_clients", &free_exited_clients, NULL, 4);
+       eventAddIsh("exit_aborted_clients", exit_aborted_clients, NULL, 1);
+}
+
+
+/*
+ * make_client - create a new Client struct and set it to initial state.
+ *
+ *      from == NULL,   create local client (a client connected
+ *                      to a socket).
+ *
+ *      from,   create remote client (behind a socket
+ *                      associated with the client defined by
+ *                      'from'). ('from' is a local client!!).
+ */
+struct Client *
+make_client(struct Client *from)
+{
+       struct Client *client_p = NULL;
+       struct LocalUser *localClient;
+
+       client_p = BlockHeapAlloc(client_heap);
+
+       if(from == NULL)
+       {
+               client_p->from = client_p;      /* 'from' of local client is self! */
+
+               localClient = (struct LocalUser *) BlockHeapAlloc(lclient_heap);
+               SetMyConnect(client_p);
+               client_p->localClient = localClient;
+
+               client_p->localClient->lasttime = client_p->localClient->firsttime = CurrentTime;
+
+               client_p->localClient->fd = -1;
+               client_p->localClient->ctrlfd = -1;
+
+               client_p->preClient = (struct PreClient *) BlockHeapAlloc(pclient_heap);
+
+               /* as good a place as any... */
+               dlinkAdd(client_p, &client_p->localClient->tnode, &unknown_list);
+       }
+       else
+       {                       /* from is not NULL */
+               client_p->localClient = NULL;
+               client_p->preClient = NULL;
+               client_p->from = from;  /* 'from' of local client is self! */
+       }
+       
+       SetUnknown(client_p);
+       strcpy(client_p->username, "unknown");
+
+       return client_p;
+}
+
+void
+free_pre_client(struct Client *client_p)
+{
+       struct Blacklist *blptr;
+
+       s_assert(NULL != client_p);
+
+       if(client_p->preClient == NULL)
+               return;
+
+       blptr = client_p->preClient->dnsbl_listed;
+       if (blptr != NULL)
+               unref_blacklist(blptr);
+       abort_blacklist_queries(client_p);
+       BlockHeapFree(pclient_heap, client_p->preClient);
+       client_p->preClient = NULL;
+}
+
+static void
+free_local_client(struct Client *client_p)
+{
+       s_assert(NULL != client_p);
+       s_assert(&me != client_p);
+
+       if(client_p->localClient == NULL)
+               return;
+
+       /*
+        * clean up extra sockets from P-lines which have been discarded.
+        */
+       if(client_p->localClient->listener)
+       {
+               s_assert(0 < client_p->localClient->listener->ref_count);
+               if(0 == --client_p->localClient->listener->ref_count
+                  && !client_p->localClient->listener->active)
+                       free_listener(client_p->localClient->listener);
+               client_p->localClient->listener = 0;
+       }
+
+       if(client_p->localClient->fd >= 0)
+               comm_close(client_p->localClient->fd);
+
+       if(client_p->localClient->passwd)
+       {
+               memset(client_p->localClient->passwd, 0,
+                       strlen(client_p->localClient->passwd));
+               MyFree(client_p->localClient->passwd);
+       }
+
+       MyFree(client_p->localClient->challenge);
+       MyFree(client_p->localClient->fullcaps);
+       MyFree(client_p->localClient->opername);
+       MyFree(client_p->localClient->mangledhost);
+
+       BlockHeapFree(lclient_heap, client_p->localClient);
+       client_p->localClient = NULL;
+}
+
+void
+free_client(struct Client *client_p)
+{
+       s_assert(NULL != client_p);
+       s_assert(&me != client_p);
+       free_local_client(client_p);
+       free_pre_client(client_p);
+       BlockHeapFree(client_heap, client_p);
+}
+
+/*
+ * check_pings - go through the local client list and check activity
+ * kill off stuff that should die
+ *
+ * inputs       - NOT USED (from event)
+ * output       - next time_t when check_pings() should be called again
+ * side effects - 
+ *
+ *
+ * A PING can be sent to clients as necessary.
+ *
+ * Client/Server ping outs are handled.
+ */
+
+/*
+ * Addon from adrian. We used to call this after nextping seconds,
+ * however I've changed it to run once a second. This is only for
+ * PING timeouts, not K/etc-line checks (thanks dianora!). Having it
+ * run once a second makes life a lot easier - when a new client connects
+ * and they need a ping in 4 seconds, if nextping was set to 20 seconds
+ * we end up waiting 20 seconds. This is stupid. :-)
+ * I will optimise (hah!) check_pings() once I've finished working on
+ * tidying up other network IO evilnesses.
+ *     -- adrian
+ */
+
+static void
+check_pings(void *notused)
+{
+       check_pings_list(&lclient_list);
+       check_pings_list(&serv_list);
+       check_unknowns_list(&unknown_list);
+}
+
+/*
+ * Check_pings_list()
+ *
+ * inputs      - pointer to list to check
+ * output      - NONE
+ * side effects        - 
+ */
+static void
+check_pings_list(dlink_list * list)
+{
+       char scratch[32];       /* way too generous but... */
+       struct Client *client_p;        /* current local client_p being examined */
+       int ping = 0;           /* ping time value from client */
+       dlink_node *ptr, *next_ptr;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
+       {
+               client_p = ptr->data;
+
+               /*
+                ** Note: No need to notify opers here. It's
+                ** already done when "FLAGS_DEADSOCKET" is set.
+                */
+               if(!MyConnect(client_p) || IsDead(client_p))
+                       continue;
+
+               if(IsPerson(client_p))
+               {
+                       if(!IsExemptKline(client_p) &&
+                          GlobalSetOptions.idletime &&
+                          !IsOper(client_p) &&
+                          !IsIdlelined(client_p) &&
+                          ((CurrentTime - client_p->localClient->last) > GlobalSetOptions.idletime))
+                       {
+                               struct ConfItem *aconf;
+
+                               aconf = make_conf();
+                               aconf->status = CONF_KILL;
+
+                               DupString(aconf->host, client_p->host);
+                               DupString(aconf->passwd, "idle exceeder");
+                               DupString(aconf->user, client_p->username);
+                               aconf->port = 0;
+                               aconf->hold = CurrentTime + 60;
+                               add_temp_kline(aconf);
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                                    "Idle time limit exceeded for %s - temp k-lining",
+                                                    get_client_name(client_p, HIDE_IP));
+
+                               exit_client(client_p, client_p, &me, aconf->passwd);
+                               continue;
+                       }
+               }
+
+               if(!IsRegistered(client_p))
+                       ping = ConfigFileEntry.connect_timeout;
+               else
+                       ping = get_client_ping(client_p);
+
+               if(ping < (CurrentTime - client_p->localClient->lasttime))
+               {
+                       /*
+                        * If the client/server hasnt talked to us in 2*ping seconds
+                        * and it has a ping time, then close its connection.
+                        */
+                       if(((CurrentTime - client_p->localClient->lasttime) >= (2 * ping)
+                           && (client_p->flags & FLAGS_PINGSENT)))
+                       {
+                               if(IsAnyServer(client_p))
+                               {
+                                       sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) && !IsServer(client_p) ? L_NETWIDE : L_ALL,
+                                                            "No response from %s, closing link",
+                                                            get_server_name(client_p, HIDE_IP));
+                                       ilog(L_SERVER,
+                                            "No response from %s, closing link",
+                                            log_client_name(client_p, HIDE_IP));
+                               }
+                               (void) ircsnprintf(scratch, sizeof(scratch),
+                                                 "Ping timeout: %d seconds",
+                                                 (int) (CurrentTime - client_p->localClient->lasttime));
+
+                               exit_client(client_p, client_p, &me, scratch);
+                               continue;
+                       }
+                       else if((client_p->flags & FLAGS_PINGSENT) == 0)
+                       {
+                               /*
+                                * if we havent PINGed the connection and we havent
+                                * heard from it in a while, PING it to make sure
+                                * it is still alive.
+                                */
+                               client_p->flags |= FLAGS_PINGSENT;
+                               /* not nice but does the job */
+                               client_p->localClient->lasttime = CurrentTime - ping;
+                               sendto_one(client_p, "PING :%s", me.name);
+                       }
+               }
+               /* ping_timeout: */
+
+       }
+}
+
+/*
+ * check_unknowns_list
+ *
+ * inputs      - pointer to list of unknown clients
+ * output      - NONE
+ * side effects        - unknown clients get marked for termination after n seconds
+ */
+static void
+check_unknowns_list(dlink_list * list)
+{
+       dlink_node *ptr, *next_ptr;
+       struct Client *client_p;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
+       {
+               client_p = ptr->data;
+
+               if(IsDead(client_p) || IsClosing(client_p))
+                       continue;
+
+               /*
+                * Check UNKNOWN connections - if they have been in this state
+                * for > 30s, close them.
+                */
+
+               if((CurrentTime - client_p->localClient->firsttime) > 30)
+                       exit_client(client_p, client_p, &me, "Connection timed out");
+       }
+}
+
+static void
+notify_banned_client(struct Client *client_p, struct ConfItem *aconf, int ban)
+{
+       static const char conn_closed[] = "Connection closed";
+       static const char d_lined[] = "D-lined";
+       static const char k_lined[] = "K-lined";
+       static const char g_lined[] = "G-lined";
+       const char *reason = NULL;
+       const char *exit_reason = conn_closed;
+
+       if(ConfigFileEntry.kline_with_reason && !EmptyString(aconf->passwd))
+       {
+               reason = aconf->passwd;
+               exit_reason = aconf->passwd;
+       }
+       else
+       {
+               switch (aconf->status)
+               {
+               case D_LINED:
+                       reason = d_lined;
+                       break;
+               case G_LINED:
+                       reason = g_lined;
+                       break;
+               default:
+                       reason = k_lined;
+                       break;
+               }
+       }
+
+       if(ban == D_LINED && !IsPerson(client_p))
+               sendto_one(client_p, "NOTICE DLINE :*** You have been D-lined");
+       else
+               sendto_one(client_p, form_str(ERR_YOUREBANNEDCREEP),
+                          me.name, client_p->name, reason);
+       
+       exit_client(client_p, client_p, &me, 
+                       EmptyString(ConfigFileEntry.kline_reason) ? exit_reason :
+                        ConfigFileEntry.kline_reason);
+}
+
+/*
+ * check_banned_lines
+ * inputs      - NONE
+ * output      - NONE
+ * side effects - Check all connections for a pending k/d/gline against the
+ *               client, exit the client if found.
+ */
+void
+check_banned_lines(void)
+{
+       struct Client *client_p;        /* current local client_p being examined */
+       struct ConfItem *aconf = NULL;
+       dlink_node *ptr, *next_ptr;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, lclient_list.head)
+       {
+               client_p = ptr->data;
+
+               if(IsMe(client_p))
+                       continue;
+
+               /* if there is a returned struct ConfItem then kill it */
+               if((aconf = find_dline((struct sockaddr *)&client_p->localClient->ip, client_p->localClient->ip.ss_family)))
+               {
+                       if(aconf->status & CONF_EXEMPTDLINE)
+                               continue;
+
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "DLINE active for %s",
+                                            get_client_name(client_p, HIDE_IP));
+
+                       notify_banned_client(client_p, aconf, D_LINED);
+                       continue;       /* and go examine next fd/client_p */
+               }
+
+               if(!IsPerson(client_p))
+                       continue;
+
+               if((aconf = find_kline(client_p)) != NULL)
+               {
+                       if(IsExemptKline(client_p))
+                       {
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                               "KLINE over-ruled for %s, client is kline_exempt [%s@%s]",
+                                               get_client_name(client_p, HIDE_IP),
+                                               aconf->user, aconf->host);
+                               continue;
+                       }
+
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                       "KLINE active for %s",
+                                       get_client_name(client_p, HIDE_IP));
+                       notify_banned_client(client_p, aconf, K_LINED);
+                       continue;
+               }
+               else if((aconf = find_gline(client_p)) != NULL)
+               {
+                       if(IsExemptKline(client_p))
+                       {
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                               "GLINE over-ruled for %s, client is kline_exempt [%s@%s]",
+                                               get_client_name(client_p, HIDE_IP),
+                                               aconf->user, aconf->host);
+                               continue;
+                       }
+
+                       if(IsExemptGline(client_p))
+                       {
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                               "GLINE over-ruled for %s, client is gline_exempt [%s@%s]",
+                                               get_client_name(client_p, HIDE_IP),
+                                               aconf->user, aconf->host);
+                               continue;
+                       }
+
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                       "GLINE active for %s",
+                                       get_client_name(client_p, HIDE_IP));
+
+                       notify_banned_client(client_p, aconf, G_LINED);
+                       continue;
+               }
+               else if((aconf = find_xline(client_p->info, 1)) != NULL)
+               {
+                       if(IsExemptKline(client_p))
+                       {
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                               "XLINE over-ruled for %s, client is kline_exempt [%s]",
+                                               get_client_name(client_p, HIDE_IP),
+                                               aconf->name);
+                               continue;
+                       }
+
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL, "XLINE active for %s",
+                                       get_client_name(client_p, HIDE_IP));
+
+                       (void) exit_client(client_p, client_p, &me, "Bad user info");
+                       continue;
+               }
+       }
+
+       /* also check the unknowns list for new dlines */
+       DLINK_FOREACH_SAFE(ptr, next_ptr, unknown_list.head)
+       {
+               client_p = ptr->data;
+
+               if((aconf = find_dline((struct sockaddr *)&client_p->localClient->ip,client_p->localClient->ip.ss_family)))
+               {
+                       if(aconf->status & CONF_EXEMPTDLINE)
+                               continue;
+
+                       notify_banned_client(client_p, aconf, D_LINED);
+               }
+       }
+
+}
+
+/* check_klines_event()
+ *
+ * inputs      -
+ * outputs     -
+ * side effects - check_klines() is called, kline_queued unset
+ */
+void
+check_klines_event(void *unused)
+{
+       kline_queued = 0;
+       check_klines();
+}
+
+/* check_klines
+ *
+ * inputs       -
+ * outputs      -
+ * side effects - all clients will be checked for klines
+ */
+void
+check_klines(void)
+{
+       struct Client *client_p;
+       struct ConfItem *aconf;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, lclient_list.head)
+       {
+               client_p = ptr->data;
+
+               if(IsMe(client_p) || !IsPerson(client_p))
+                       continue;
+
+               if((aconf = find_kline(client_p)) != NULL)
+               {
+                       if(IsExemptKline(client_p))
+                       {
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                                    "KLINE over-ruled for %s, client is kline_exempt",
+                                                    get_client_name(client_p, HIDE_IP));
+                               continue;
+                       }
+
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "KLINE active for %s",
+                                            get_client_name(client_p, HIDE_IP));
+
+                       notify_banned_client(client_p, aconf, K_LINED);
+                       continue;
+               }
+       }
+}
+
+/* check_glines()
+ *
+ * inputs       -
+ * outputs      -
+ * side effects - all clients will be checked for glines
+ */
+void
+check_glines(void)
+{
+       struct Client *client_p;
+       struct ConfItem *aconf;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, lclient_list.head)
+       {
+               client_p = ptr->data;
+
+               if(IsMe(client_p) || !IsPerson(client_p))
+                       continue;
+
+               if((aconf = find_gline(client_p)) != NULL)
+               {
+                       if(IsExemptKline(client_p))
+                       {
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                                    "GLINE over-ruled for %s, client is kline_exempt",
+                                                    get_client_name(client_p, HIDE_IP));
+                               continue;
+                       }
+
+                       if(IsExemptGline(client_p))
+                       {
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                                    "GLINE over-ruled for %s, client is gline_exempt",
+                                                    get_client_name(client_p, HIDE_IP));
+                               continue;
+                       }
+
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "GLINE active for %s",
+                                            get_client_name(client_p, HIDE_IP));
+
+                       notify_banned_client(client_p, aconf, K_LINED);
+                       continue;
+               }
+       }
+}
+
+/* check_dlines()
+ *
+ * inputs       -
+ * outputs      -
+ * side effects - all clients will be checked for dlines
+ */
+void
+check_dlines(void)
+{
+       struct Client *client_p;
+       struct ConfItem *aconf;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, lclient_list.head)
+       {
+               client_p = ptr->data;
+
+               if(IsMe(client_p))
+                       continue;
+
+               if((aconf = find_dline((struct sockaddr *)&client_p->localClient->ip,client_p->localClient->ip.ss_family)) != NULL)
+               {
+                       if(aconf->status & CONF_EXEMPTDLINE)
+                               continue;
+
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "DLINE active for %s",
+                                            get_client_name(client_p, HIDE_IP));
+
+                       notify_banned_client(client_p, aconf, D_LINED);
+                       continue;
+               }
+       }
+
+       /* dlines need to be checked against unknowns too */
+       DLINK_FOREACH_SAFE(ptr, next_ptr, unknown_list.head)
+       {
+               client_p = ptr->data;
+
+               if((aconf = find_dline((struct sockaddr *)&client_p->localClient->ip,client_p->localClient->ip.ss_family)) != NULL)
+               {
+                       if(aconf->status & CONF_EXEMPTDLINE)
+                               continue;
+
+                       notify_banned_client(client_p, aconf, D_LINED);
+               }
+       }
+}
+
+/* check_xlines
+ *
+ * inputs       -
+ * outputs      -
+ * side effects - all clients will be checked for xlines
+ */
+void
+check_xlines(void)
+{
+       struct Client *client_p;
+       struct ConfItem *aconf;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, lclient_list.head)
+       {
+               client_p = ptr->data;
+
+               if(IsMe(client_p) || !IsPerson(client_p))
+                       continue;
+
+               if((aconf = find_xline(client_p->info, 1)) != NULL)
+               {
+                       if(IsExemptKline(client_p))
+                       {
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                                    "XLINE over-ruled for %s, client is kline_exempt",
+                                                    get_client_name(client_p, HIDE_IP));
+                               continue;
+                       }
+
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL, "XLINE active for %s",
+                                            get_client_name(client_p, HIDE_IP));
+
+                       (void) exit_client(client_p, client_p, &me, "Bad user info");
+                       continue;
+               }
+       }
+}
+
+/*
+ * update_client_exit_stats
+ *
+ * input       - pointer to client
+ * output      - NONE
+ * side effects        - 
+ */
+static void
+update_client_exit_stats(struct Client *client_p)
+{
+       if(IsServer(client_p))
+       {
+               sendto_realops_snomask(SNO_EXTERNAL, L_ALL,
+                                    "Server %s split from %s",
+                                    client_p->name, client_p->servptr->name);
+               if(HasSentEob(client_p))
+                       eob_count--;
+       }
+       else if(IsClient(client_p))
+       {
+               --Count.total;
+               if(IsOper(client_p))
+                       --Count.oper;
+               if(IsInvisible(client_p))
+                       --Count.invisi;
+       }
+
+       if(splitchecking && !splitmode)
+               check_splitmode(NULL);
+}
+
+/*
+ * release_client_state
+ *
+ * input       - pointer to client to release
+ * output      - NONE
+ * side effects        - 
+ */
+static void
+release_client_state(struct Client *client_p)
+{
+       if(client_p->user != NULL)
+       {
+               free_user(client_p->user, client_p);    /* try this here */
+       }
+       if(client_p->serv)
+       {
+               if(client_p->serv->user != NULL)
+                       free_user(client_p->serv->user, client_p);
+               if(client_p->serv->fullcaps)
+                       MyFree(client_p->serv->fullcaps);
+               MyFree(client_p->serv);
+       }
+}
+
+/*
+ * remove_client_from_list
+ * inputs      - point to client to remove
+ * output      - NONE
+ * side effects - taken the code from ExitOneClient() for this
+ *               and placed it here. - avalon
+ */
+static void
+remove_client_from_list(struct Client *client_p)
+{
+       s_assert(NULL != client_p);
+
+       if(client_p == NULL)
+               return;
+
+       /* A client made with make_client()
+        * is on the unknown_list until removed.
+        * If it =does= happen to exit before its removed from that list
+        * and its =not= on the global_client_list, it will core here.
+        * short circuit that case now -db
+        */
+       if(client_p->node.prev == NULL && client_p->node.next == NULL)
+               return;
+
+       dlinkDelete(&client_p->node, &global_client_list);
+
+       update_client_exit_stats(client_p);
+}
+
+
+/*
+ * find_person - find person by (nick)name.
+ * inputs      - pointer to name
+ * output      - return client pointer
+ * side effects -
+ */
+struct Client *
+find_person(const char *name)
+{
+       struct Client *c2ptr;
+
+       c2ptr = find_client(name);
+
+       if(c2ptr && IsPerson(c2ptr))
+               return (c2ptr);
+       return (NULL);
+}
+
+struct Client *
+find_named_person(const char *name)
+{
+       struct Client *c2ptr;
+
+       c2ptr = find_named_client(name);
+
+       if(c2ptr && IsPerson(c2ptr))
+               return (c2ptr);
+       return (NULL);
+}
+
+
+/*
+ * find_chasing - 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.
+ */
+struct Client *
+find_chasing(struct Client *source_p, const char *user, int *chasing)
+{
+       struct Client *who;
+
+       if(MyClient(source_p))
+               who = find_named_person(user);
+       else
+               who = find_person(user);
+
+       if(chasing)
+               *chasing = 0;
+
+       if(who || IsDigit(*user))
+               return who;
+
+       if(!(who = get_history(user, (long) KILLCHASETIMELIMIT)))
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHNICK,
+                                  form_str(ERR_NOSUCHNICK), user);
+               return (NULL);
+       }
+       if(chasing)
+               *chasing = 1;
+       return who;
+}
+
+/*
+ * get_client_name -  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 to any client structure.
+ *
+ * NOTE 1:
+ *        Watch out the allocation of "nbuf", if either source_p->name
+ *        or source_p->sockhost gets changed into pointers instead of
+ *        directly allocated within the structure...
+ *
+ * NOTE 2:
+ *        Function return either a pointer to the structure (source_p) or
+ *        to internal buffer (nbuf). *NEVER* use the returned pointer
+ *        to modify what it points!!!
+ */
+
+const char *
+get_client_name(struct Client *client, int showip)
+{
+       static char nbuf[HOSTLEN * 2 + USERLEN + 5];
+
+       s_assert(NULL != client);
+       if(client == NULL)
+               return NULL;
+
+       if(MyConnect(client))
+       {
+               if(!irccmp(client->name, client->host))
+                       return client->name;
+
+               if(ConfigFileEntry.hide_spoof_ips && 
+                  showip == SHOW_IP && IsIPSpoof(client))
+                       showip = MASK_IP;
+#ifdef HIDE_SERVERS_IPS
+               if(IsAnyServer(client))
+                       showip = MASK_IP;
+#endif
+
+               /* And finally, let's get the host information, ip or name */
+               switch (showip)
+               {
+               case SHOW_IP:
+                       ircsnprintf(nbuf, sizeof(nbuf), "%s[%s@%s]", 
+                                  client->name, client->username, 
+                                  client->sockhost);
+                       break;
+               case MASK_IP:
+                       ircsnprintf(nbuf, sizeof(nbuf), "%s[%s@255.255.255.255]",
+                                  client->name, client->username);
+                       break;
+               default:
+                       ircsnprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
+                                  client->name, client->username, client->host);
+               }
+               return nbuf;
+       }
+
+       /* As pointed out by Adel Mezibra 
+        * Neph|l|m@EFnet. Was missing a return here.
+        */
+       return client->name;
+}
+
+const char *
+get_server_name(struct Client *target_p, int showip)
+{
+       static char nbuf[HOSTLEN * 2 + USERLEN + 5];
+
+       if(target_p == NULL)
+               return NULL;
+
+       if(!MyConnect(target_p) || !irccmp(target_p->name, target_p->host))
+               return target_p->name;
+
+#ifdef HIDE_SERVERS_IPS
+       if(EmptyString(target_p->name))
+       {
+               ircsnprintf(nbuf, sizeof(nbuf), "[%s@255.255.255.255]",
+                               target_p->username);
+               return nbuf;
+       }
+       else
+               return target_p->name;
+#endif
+
+       switch (showip)
+       {
+               case SHOW_IP:
+                       ircsnprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
+                               target_p->name, target_p->username, 
+                               target_p->sockhost);
+                       break;
+
+               case MASK_IP:
+                       ircsnprintf(nbuf, sizeof(nbuf), "%s[%s@255.255.255.255]",
+                               target_p->name, target_p->username);
+
+               default:
+                       ircsnprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
+                               target_p->name, target_p->username,
+                               target_p->host);
+       }
+
+       return nbuf;
+}
+       
+/* log_client_name()
+ *
+ * This version is the same as get_client_name, but doesnt contain the
+ * code that will hide IPs always.  This should be used for logfiles.
+ */
+const char *
+log_client_name(struct Client *target_p, int showip)
+{
+       static char nbuf[HOSTLEN * 2 + USERLEN + 5];
+
+       if(target_p == NULL)
+               return NULL;
+
+       if(MyConnect(target_p))
+       {
+               if(irccmp(target_p->name, target_p->host) == 0)
+                       return target_p->name;
+
+               switch (showip)
+               {
+               case SHOW_IP:
+                       ircsnprintf(nbuf, sizeof(nbuf), "%s[%s@%s]", target_p->name,
+                                  target_p->username, target_p->sockhost);
+                       break;
+
+               case MASK_IP:
+                       ircsnprintf(nbuf, sizeof(nbuf), "%s[%s@255.255.255.255]",
+                                  target_p->name, target_p->username);
+
+               default:
+                       ircsnprintf(nbuf, sizeof(nbuf), "%s[%s@%s]", target_p->name,
+                                  target_p->username, target_p->host);
+               }
+
+               return nbuf;
+       }
+
+       return target_p->name;
+}
+
+/* is_remote_connect - Returns whether a server was /connect'ed by a remote
+ * oper (send notices netwide) */
+int
+is_remote_connect(struct Client *client_p)
+{
+       struct Client *oper;
+
+       if (client_p->serv == NULL)
+               return FALSE;
+       oper = find_named_person(client_p->serv->by);
+       return oper != NULL && IsOper(oper) && !MyConnect(oper);
+}
+
+static void
+free_exited_clients(void *unused)
+{
+       dlink_node *ptr, *next;
+       struct Client *target_p;
+
+       DLINK_FOREACH_SAFE(ptr, next, dead_list.head)
+       {
+               target_p = ptr->data;
+
+#ifdef DEBUG_EXITED_CLIENTS
+               {
+                       struct abort_client *abt;
+                       dlink_node *aptr;
+                       int found = 0;
+
+                       DLINK_FOREACH(aptr, abort_list.head)
+                       {
+                               abt = aptr->data;
+                               if(abt->client == target_p)
+                               {
+                                       s_assert(0);
+                                       sendto_realops_snomask(SNO_GENERAL, L_ALL, 
+                                               "On abort_list: %s stat: %u flags: %u/%u handler: %c",
+                                               target_p->name, (unsigned int) target_p->status,
+                                               target_p->flags, target_p->flags2, target_p->handler);
+                                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                               "Please report this to the ratbox developers!");
+                                       found++;
+                               }
+                       }
+
+                       if(found)
+                       {
+                               dlinkDestroy(ptr, &dead_list);
+                               continue;
+                       }
+               }
+#endif
+
+               if(ptr->data == NULL)
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "Warning: null client on dead_list!");
+                       dlinkDestroy(ptr, &dead_list);
+                       continue;
+               }
+               release_client_state(target_p);
+               free_client(target_p);
+               dlinkDestroy(ptr, &dead_list);
+       }
+
+#ifdef DEBUG_EXITED_CLIENTS
+       DLINK_FOREACH_SAFE(ptr, next, dead_remote_list.head)
+       {
+               target_p = ptr->data;
+
+               if(ptr->data == NULL)
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "Warning: null client on dead_list!");
+                       dlinkDestroy(ptr, &dead_list);
+                       continue;
+               }
+               release_client_state(target_p);
+               free_client(target_p);
+               dlinkDestroy(ptr, &dead_remote_list);
+       }
+#endif
+       
+}
+
+/*
+** Recursively send QUITs and SQUITs for source_p and all its dependent clients
+** and servers to those servers that need them.  A server needs the client
+** QUITs if it can't figure them out from the SQUIT (ie pre-TS4) or if it
+** isn't getting the SQUIT because of @#(*&@)# hostmasking.  With TS4, once
+** a link gets a SQUIT, it doesn't need any QUIT/SQUITs for clients depending
+** on that one -orabidoo
+*/
+static void
+recurse_send_quits(struct Client *client_p, struct Client *source_p, 
+                  struct Client *to, const char *comment1,
+                  const char *comment)
+{
+       struct Client *target_p;
+       dlink_node *ptr, *ptr_next;
+       /* If this server can handle quit storm (QS) removal
+        * of dependents, just send the SQUIT
+        */
+
+       if(IsCapable(to, CAP_QS))
+       {
+               sendto_one(to, "SQUIT %s :%s",
+                          get_id(source_p, to), comment);
+       }
+       else
+       {
+               DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->serv->users.head)
+               {
+                       target_p = ptr->data;
+                       sendto_one(to, ":%s QUIT :%s", target_p->name, comment1);
+               }
+               DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->serv->servers.head)
+               {
+                       target_p = ptr->data;
+                       recurse_send_quits(client_p, target_p, to, comment1, comment);
+               }
+               sendto_one(to, "SQUIT %s :%s", source_p->name, comment);
+       }
+}
+
+/* 
+** Remove all clients that depend on source_p; assumes all (S)QUITs have
+** already been sent.  we make sure to exit a server's dependent clients 
+** and servers before the server itself; exit_one_client takes care of 
+** actually removing things off llists.   tweaked from +CSr31  -orabidoo
+*/
+/*
+ * added sanity test code.... source_p->serv might be NULL...
+ */
+static void
+recurse_remove_clients(struct Client *source_p, const char *comment)
+{
+       struct Client *target_p;
+       dlink_node *ptr, *ptr_next;
+
+       if(IsMe(source_p))
+               return;
+
+       if(source_p->serv == NULL)      /* oooops. uh this is actually a major bug */
+               return;
+
+       /* this is very ugly, but it saves cpu :P */
+       if(ConfigFileEntry.nick_delay > 0)
+       {
+               DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->serv->users.head)
+               {
+                       target_p = ptr->data;
+                       target_p->flags |= FLAGS_KILLED;
+                       add_nd_entry(target_p->name);
+
+                       if(!IsDead(target_p) && !IsClosing(target_p))
+                               exit_remote_client(NULL, target_p, &me, comment);
+               }
+       }
+       else
+       {
+               DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->serv->users.head)
+               {
+                       target_p = ptr->data;
+                       target_p->flags |= FLAGS_KILLED;
+
+                       if(!IsDead(target_p) && !IsClosing(target_p))
+                               exit_remote_client(NULL, target_p, &me, comment);
+               }
+       }       
+
+       DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->serv->servers.head)
+       {
+               target_p = ptr->data;
+               recurse_remove_clients(target_p, comment);
+               qs_server(NULL, target_p, &me, comment);
+       }
+}
+
+/*
+** Remove *everything* that depends on source_p, from all lists, and sending
+** all necessary QUITs and SQUITs.  source_p itself is still on the lists,
+** and its SQUITs have been sent except for the upstream one  -orabidoo
+*/
+static void
+remove_dependents(struct Client *client_p,
+                 struct Client *source_p,
+                 struct Client *from, const char *comment, const char *comment1)
+{
+       struct Client *to;
+       dlink_node *ptr, *next;
+
+       DLINK_FOREACH_SAFE(ptr, next, serv_list.head)
+       {
+               to = ptr->data;
+
+               if(IsMe(to) || to == source_p->from || 
+                  (to == client_p && IsCapable(to, CAP_QS)))
+                       continue;
+
+               recurse_send_quits(client_p, source_p, to, comment1, comment);
+       }
+
+       recurse_remove_clients(source_p, comment1);
+}
+
+void
+exit_aborted_clients(void *unused)
+{
+       struct abort_client *abt;
+       dlink_node *ptr, *next;
+       DLINK_FOREACH_SAFE(ptr, next, abort_list.head)
+       {
+               abt = ptr->data;
+
+#ifdef DEBUG_EXITED_CLIENTS
+               {
+                       if(dlinkFind(abt->client, &dead_list))
+                       {
+                               s_assert(0);
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL, 
+                                       "On dead_list: %s stat: %u flags: %u/%u handler: %c",
+                                       abt->client->name, (unsigned int) abt->client->status,
+                                       abt->client->flags, abt->client->flags2, abt->client->handler);
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                       "Please report this to the ratbox developers!");
+                               continue;
+                       }
+               }
+#endif
+
+               s_assert(*((unsigned long*)abt->client) != 0xdeadbeef); /* This is lame but its a debug thing */
+               dlinkDelete(ptr, &abort_list);
+
+               if(IsAnyServer(abt->client))
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "Closing link to %s: %s",
+                                            get_server_name(abt->client, HIDE_IP), abt->notice);
+
+               /* its no longer on abort list - we *must* remove
+                * FLAGS_CLOSING otherwise exit_client() will not run --fl
+                */
+               abt->client->flags &= ~FLAGS_CLOSING;
+               exit_client(abt->client, abt->client, &me, abt->notice);
+               MyFree(abt);
+       }
+}
+
+
+/*
+ * dead_link - Adds client to a list of clients that need an exit_client()
+ *
+ */
+void
+dead_link(struct Client *client_p)
+{
+       struct abort_client *abt;
+
+       s_assert(!IsMe(client_p));
+       if(IsDead(client_p) || IsClosing(client_p) || IsMe(client_p))
+               return;
+
+       abt = (struct abort_client *) MyMalloc(sizeof(struct abort_client));
+
+       if(client_p->flags & FLAGS_SENDQEX)
+               strlcpy(abt->notice, "Max SendQ exceeded", sizeof(abt->notice));
+       else
+               ircsnprintf(abt->notice, sizeof(abt->notice), "Write error: %s", strerror(errno));
+
+       abt->client = client_p;
+       SetIOError(client_p);
+       SetDead(client_p);
+       SetClosing(client_p);
+       dlinkAdd(abt, &abt->node, &abort_list);
+}
+
+
+/* This does the remove of the user from channels..local or remote */
+static inline void
+exit_generic_client(struct Client *client_p, struct Client *source_p, struct Client *from,
+                  const char *comment)
+{
+       dlink_node *ptr, *next_ptr;
+
+       if(IsOper(source_p))
+               dlinkFindDestroy(source_p, &oper_list);
+
+       sendto_common_channels_local(source_p, ":%s!%s@%s QUIT :%s",
+                                    source_p->name,
+                                    source_p->username, source_p->host, comment);
+
+       remove_user_from_channels(source_p);
+
+       /* Should not be in any channels now */
+       s_assert(source_p->user->channel.head == NULL);
+
+       /* Clean up invitefield */
+       DLINK_FOREACH_SAFE(ptr, next_ptr, source_p->user->invited.head)
+       {
+               del_invite(ptr->data, source_p);
+       }
+
+       /* Clean up allow lists */
+       del_all_accepts(source_p);
+
+       add_history(source_p, 0);
+       off_history(source_p);
+
+       monitor_signoff(source_p);
+
+       if(has_id(source_p))
+               del_from_id_hash(source_p->id, source_p);
+
+       del_from_hostname_hash(source_p->orighost, source_p);
+       del_from_client_hash(source_p->name, source_p);
+       remove_client_from_list(source_p);
+}
+
+/* 
+ * Assumes IsPerson(source_p) && !MyConnect(source_p)
+ */
+
+static int
+exit_remote_client(struct Client *client_p, struct Client *source_p, struct Client *from,
+                  const char *comment)
+{
+       exit_generic_client(client_p, source_p, from, comment);
+       
+       if(source_p->servptr && source_p->servptr->serv)
+       {
+               dlinkDelete(&source_p->lnode, &source_p->servptr->serv->users);
+       }
+
+       if((source_p->flags & FLAGS_KILLED) == 0)
+       {
+               sendto_server(client_p, NULL, CAP_TS6, NOCAPS,
+                             ":%s QUIT :%s", use_id(source_p), comment);
+               sendto_server(client_p, NULL, NOCAPS, CAP_TS6,
+                             ":%s QUIT :%s", source_p->name, comment);
+       }
+
+       SetDead(source_p);
+#ifdef DEBUG_EXITED_CLIENTS
+       dlinkAddAlloc(source_p, &dead_remote_list);
+#else
+       dlinkAddAlloc(source_p, &dead_list);
+#endif
+       return(CLIENT_EXITED);
+}
+
+/*
+ * This assumes IsUnknown(source_p) == TRUE and MyConnect(source_p) == TRUE
+ */
+
+static int
+exit_unknown_client(struct Client *client_p, struct Client *source_p, struct Client *from,
+                 const char *comment)
+{
+       delete_auth_queries(source_p);
+       client_flush_input(source_p);
+       dlinkDelete(&source_p->localClient->tnode, &unknown_list);
+
+       if(!IsIOError(source_p))
+               sendto_one(source_p, "ERROR :Closing Link: 127.0.0.1 (%s)", comment);
+
+       close_connection(source_p);
+
+       if(has_id(source_p))
+               del_from_id_hash(source_p->id, source_p);
+
+       del_from_hostname_hash(source_p->host, source_p);
+       del_from_client_hash(source_p->name, source_p);
+       remove_client_from_list(source_p);
+       free_pre_client(source_p);
+       SetDead(source_p);
+       dlinkAddAlloc(source_p, &dead_list);
+
+       /* Note that we don't need to add unknowns to the dead_list */
+       return(CLIENT_EXITED);
+}
+
+static int
+exit_remote_server(struct Client *client_p, struct Client *source_p, struct Client *from, 
+                 const char *comment)
+{
+       static char comment1[(HOSTLEN*2)+2];
+       static char newcomment[BUFSIZE];
+       struct Client *target_p;
+       
+       if(ConfigServerHide.flatten_links)
+               strcpy(comment1, "*.net *.split");
+       else
+       {
+               if((source_p->serv) && (source_p->serv->up))
+                       strcpy(comment1, source_p->serv->up);
+               else
+                       strcpy(comment1, "<Unknown>");
+               
+               strcat(comment1, " ");
+               strcat(comment1, source_p->name);
+       }
+       if (IsPerson(from))
+               ircsnprintf(newcomment, sizeof(newcomment), "by %s: %s",
+                               from->name, comment);
+
+       if(source_p->serv != NULL)
+               remove_dependents(client_p, source_p, from, IsPerson(from) ? newcomment : comment, comment1);
+
+       if(source_p->servptr && source_p->servptr->serv)
+               dlinkDelete(&source_p->lnode, &source_p->servptr->serv->servers);
+       else
+               s_assert(0);
+
+       dlinkFindDestroy(source_p, &global_serv_list);
+       target_p = source_p->from;
+       
+       if(target_p != NULL && IsServer(target_p) && target_p != client_p &&
+          !IsMe(target_p) && (source_p->flags & FLAGS_KILLED) == 0)
+       {
+               sendto_one(target_p, ":%s SQUIT %s :%s", 
+                          get_id(from, target_p), get_id(source_p, target_p),
+                          comment);
+       }
+
+       if(has_id(source_p))
+               del_from_id_hash(source_p->id, source_p);
+
+       del_from_client_hash(source_p->name, source_p);
+       remove_client_from_list(source_p);  
+       
+       SetDead(source_p);
+#ifdef DEBUG_EXITED_CLIENTS
+       dlinkAddAlloc(source_p, &dead_remote_list);
+#else
+       dlinkAddAlloc(source_p, &dead_list);
+#endif
+       return 0;
+}
+
+static int
+qs_server(struct Client *client_p, struct Client *source_p, struct Client *from, 
+                 const char *comment)
+{
+       struct Client *target_p;
+
+       if(source_p->servptr && source_p->servptr->serv)
+               dlinkDelete(&source_p->lnode, &source_p->servptr->serv->servers);
+       else
+               s_assert(0);
+
+       dlinkFindDestroy(source_p, &global_serv_list);
+       target_p = source_p->from;
+       
+       if(has_id(source_p))
+               del_from_id_hash(source_p->id, source_p);
+
+       del_from_client_hash(source_p->name, source_p);
+       remove_client_from_list(source_p);  
+       
+       SetDead(source_p);
+       dlinkAddAlloc(source_p, &dead_list);    
+       return 0;
+}
+
+static int
+exit_local_server(struct Client *client_p, struct Client *source_p, struct Client *from, 
+                 const char *comment)
+{
+       static char comment1[(HOSTLEN*2)+2];
+       static char newcomment[BUFSIZE];
+       unsigned int sendk, recvk;
+       
+       dlinkDelete(&source_p->localClient->tnode, &serv_list);
+       dlinkFindDestroy(source_p, &global_serv_list);
+       
+       unset_chcap_usage_counts(source_p);
+       sendk = source_p->localClient->sendK;
+       recvk = source_p->localClient->receiveK;
+
+       /* Always show source here, so the server notices show
+        * which side initiated the split -- jilles
+        */
+       ircsnprintf(newcomment, sizeof(newcomment), "by %s: %s",
+                       from == source_p ? me.name : from->name, comment);
+       if (!IsIOError(source_p))
+               sendto_one(source_p, "SQUIT %s :%s", use_id(source_p),
+                               newcomment);
+       if(client_p != NULL && source_p != client_p && !IsIOError(source_p))
+       {
+               sendto_one(source_p, "ERROR :Closing Link: 127.0.0.1 %s (%s)",
+                          source_p->name, comment);
+       }
+       
+       if(source_p->localClient->ctrlfd >= 0)
+       {
+               comm_close(source_p->localClient->ctrlfd);
+               source_p->localClient->ctrlfd = -1;
+       }
+
+       if(source_p->servptr && source_p->servptr->serv)
+               dlinkDelete(&source_p->lnode, &source_p->servptr->serv->servers);
+       else
+               s_assert(0);
+
+
+       close_connection(source_p);
+       
+       if(ConfigServerHide.flatten_links)
+               strcpy(comment1, "*.net *.split");
+       else
+       {
+               if((source_p->serv) && (source_p->serv->up))
+                       strcpy(comment1, source_p->serv->up);
+               else
+                       strcpy(comment1, "<Unknown>");
+               
+               strcat(comment1, " ");
+               strcat(comment1, source_p->name);
+       }
+
+       if(source_p->serv != NULL)
+               remove_dependents(client_p, source_p, from, IsPerson(from) ? newcomment : comment, comment1);
+
+       sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s was connected"
+                            " for %ld seconds.  %d/%d sendK/recvK.",
+                            source_p->name, CurrentTime - source_p->localClient->firsttime, sendk, recvk);
+
+       ilog(L_SERVER, "%s was connected for %ld seconds.  %d/%d sendK/recvK.",
+            source_p->name, CurrentTime - source_p->localClient->firsttime, sendk, recvk);
+        
+       if(has_id(source_p))
+               del_from_id_hash(source_p->id, source_p);
+
+       del_from_client_hash(source_p->name, source_p);
+       remove_client_from_list(source_p);
+       
+       SetDead(source_p);
+       dlinkAddAlloc(source_p, &dead_list);
+       return 0;
+}
+
+
+/* 
+ * This assumes IsPerson(source_p) == TRUE && MyConnect(source_p) == TRUE
+ */
+
+static int
+exit_local_client(struct Client *client_p, struct Client *source_p, struct Client *from,
+                 const char *comment)
+{
+       unsigned long on_for;
+
+       exit_generic_client(client_p, source_p, from, comment);
+       clear_monitor(source_p);
+
+       s_assert(IsPerson(source_p));
+       client_flush_input(source_p);
+       dlinkDelete(&source_p->localClient->tnode, &lclient_list);
+       dlinkDelete(&source_p->lnode, &me.serv->users);
+
+       if(IsOper(source_p))
+               dlinkFindDestroy(source_p, &local_oper_list);
+
+       sendto_realops_snomask(SNO_CCONN, L_ALL,
+                            "Client exiting: %s (%s@%s) [%s] [%s]",
+                            source_p->name,
+                            source_p->username, source_p->host, comment,
+                             show_ip(NULL, source_p) ? source_p->sockhost : "255.255.255.255");
+
+       sendto_realops_snomask(SNO_CCONNEXT, L_ALL,
+                       "CLIEXIT %s %s %s %s 0 %s",
+                       source_p->name, source_p->username, source_p->host,
+                        show_ip(NULL, source_p) ? source_p->sockhost : "255.255.255.255",
+                       comment);
+
+       on_for = CurrentTime - source_p->localClient->firsttime;
+
+       ilog(L_USER, "%s (%3lu:%02lu:%02lu): %s!%s@%s %d/%d",
+               myctime(CurrentTime), on_for / 3600,
+               (on_for % 3600) / 60, on_for % 60,
+               source_p->name, source_p->username, source_p->host,
+               source_p->localClient->sendK, source_p->localClient->receiveK);
+
+       sendto_one(source_p, "ERROR :Closing Link: %s (%s)", source_p->host, comment);
+       close_connection(source_p);
+
+       if((source_p->flags & FLAGS_KILLED) == 0)
+       {
+               sendto_server(client_p, NULL, CAP_TS6, NOCAPS,
+                             ":%s QUIT :%s", use_id(source_p), comment);
+               sendto_server(client_p, NULL, NOCAPS, CAP_TS6,
+                             ":%s QUIT :%s", source_p->name, comment);
+       }
+
+       SetDead(source_p);
+       dlinkAddAlloc(source_p, &dead_list);
+       return(CLIENT_EXITED);
+}
+
+
+/*
+** exit_client - This is old "m_bye". Name  changed, because this is not a
+**        protocol function, but a general server utility function.
+**
+**        This function exits a client of *any* type (user, server, etc)
+**        from this server. Also, this generates all necessary prototol
+**        messages that this exit may cause.
+**
+**   1) If the client is a local client, then this implicitly
+**        exits all other clients depending on this connection (e.g.
+**        remote clients having 'from'-field that points to this.
+**
+**   2) If the client is a remote client, then only this is exited.
+**
+** For convenience, this function returns a suitable value for
+** m_function return value:
+**
+**        CLIENT_EXITED        if (client_p == source_p)
+**        0                if (client_p != source_p)
+*/
+int
+exit_client(struct Client *client_p,   /* The local client originating the
+                                        * exit or NULL, if this exit is
+                                        * generated by this server for
+                                        * internal reasons.
+                                        * This will not get any of the
+                                        * generated messages. */
+           struct Client *source_p,    /* Client exiting */
+           struct Client *from,        /* Client firing off this Exit,
+                                        * never NULL! */
+           const char *comment /* Reason for the exit */
+       )
+{
+       hook_data_client_exit hdata;
+       if(IsClosing(source_p))
+               return -1;
+
+       /* note, this HAS to be here, when we exit a client we attempt to
+        * send them data, if this generates a write error we must *not* add
+        * them to the abort list --fl
+        */
+       SetClosing(source_p);
+
+       hdata.local_link = client_p;
+       hdata.target = source_p;
+       hdata.from = from;
+       hdata.comment = comment;
+       call_hook(h_client_exit, &hdata);
+
+       if(MyConnect(source_p))
+       {
+               /* Local clients of various types */
+               if(IsPerson(source_p))
+                       return exit_local_client(client_p, source_p, from, comment);
+               else if(IsServer(source_p))
+                       return exit_local_server(client_p, source_p, from, comment);
+               /* IsUnknown || IsConnecting || IsHandShake */
+               else if(!IsReject(source_p))
+                       return exit_unknown_client(client_p, source_p, from, comment);
+       } 
+       else 
+       {
+               /* Remotes */
+               if(IsPerson(source_p))
+                       return exit_remote_client(client_p, source_p, from, comment);
+               else if(IsServer(source_p))
+                       return exit_remote_server(client_p, source_p, from, comment);
+       }
+
+       return -1;
+}
+
+/*
+ * Count up local client memory
+ */
+
+/* XXX one common Client list now */
+void
+count_local_client_memory(size_t * count, size_t * local_client_memory_used)
+{
+       size_t lusage;
+       BlockHeapUsage(lclient_heap, count, NULL, &lusage);
+       *local_client_memory_used = lusage + (*count * (sizeof(MemBlock) + sizeof(struct Client)));
+}
+
+/*
+ * Count up remote client memory
+ */
+void
+count_remote_client_memory(size_t * count, size_t * remote_client_memory_used)
+{
+       size_t lcount, rcount;
+       BlockHeapUsage(lclient_heap, &lcount, NULL, NULL);
+       BlockHeapUsage(client_heap, &rcount, NULL, NULL);
+       *count = rcount - lcount;
+       *remote_client_memory_used = *count * (sizeof(MemBlock) + sizeof(struct Client));
+}
+
+
+/*
+ * accept processing, this adds a form of "caller ID" to ircd
+ * 
+ * If a client puts themselves into "caller ID only" mode,
+ * only clients that match a client pointer they have put on 
+ * the accept list will be allowed to message them.
+ *
+ * [ source.on_allow_list ] -> [ target1 ] -> [ target2 ]
+ *
+ * [target.allow_list] -> [ source1 ] -> [source2 ]
+ *
+ * i.e. a target will have a link list of source pointers it will allow
+ * each source client then has a back pointer pointing back
+ * to the client that has it on its accept list.
+ * This allows for exit_one_client to remove these now bogus entries
+ * from any client having an accept on them. 
+ */
+/*
+ * del_all_accepts
+ *
+ * inputs      - pointer to exiting client
+ * output      - NONE
+ * side effects - Walk through given clients allow_list and on_allow_list
+ *                remove all references to this client
+ */
+void
+del_all_accepts(struct Client *client_p)
+{
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+       struct Client *target_p;
+
+       if(MyClient(client_p) && client_p->localClient->allow_list.head)
+       {
+               /* clear this clients accept list, and remove them from
+                * everyones on_accept_list
+                */
+               DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->localClient->allow_list.head)
+               {
+                       target_p = ptr->data;
+                       dlinkFindDestroy(client_p, &target_p->on_allow_list);
+                       dlinkDestroy(ptr, &client_p->localClient->allow_list);
+               }
+       }
+
+       /* remove this client from everyones accept list */
+       DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->on_allow_list.head)
+       {
+               target_p = ptr->data;
+               dlinkFindDestroy(client_p, &target_p->localClient->allow_list);
+               dlinkDestroy(ptr, &client_p->on_allow_list);
+       }
+}
+
+/*
+ * show_ip() - asks if the true IP shoudl be shown when source is
+ *             askin for info about target 
+ *
+ * Inputs      - source_p who is asking
+ *             - target_p who do we want the info on
+ * Output      - returns 1 if clear IP can be showed, otherwise 0
+ * Side Effects        - none
+ */
+
+int
+show_ip(struct Client *source_p, struct Client *target_p)
+{
+       if(IsAnyServer(target_p))
+       {
+#ifndef HIDE_SERVERS_IPS
+               if(source_p == NULL || IsOper(source_p))
+                       return 1;
+#endif
+               return 0;
+       }
+       else if(IsIPSpoof(target_p))
+       {
+               /* source == NULL indicates message is being sent
+                * to local opers.
+                */
+               if(!ConfigFileEntry.hide_spoof_ips &&
+                  (source_p == NULL || MyOper(source_p)))
+                       return 1;
+               return 0;
+       }
+       else if(IsDynSpoof(target_p) && (source_p != NULL && !IsOper(source_p)))
+               return 0;
+       else
+               return 1;
+}
+
+int
+show_ip_conf(struct ConfItem *aconf, struct Client *source_p)
+{
+       if(IsConfDoSpoofIp(aconf))
+       {
+               if(!ConfigFileEntry.hide_spoof_ips && MyOper(source_p))
+                       return 1;
+
+               return 0;
+       }
+       else
+               return 1;
+}
+
+/*
+ * initUser
+ *
+ * inputs      - none
+ * outputs     - none
+ *
+ * side effects - Creates a block heap for struct Users
+ *
+ */
+static BlockHeap *user_heap;
+void
+initUser(void)
+{
+       user_heap = BlockHeapCreate(sizeof(struct User), USER_HEAP_SIZE);
+       if(!user_heap)
+               outofmemory();
+}
+
+/*
+ * make_user
+ *
+ * inputs      - pointer to client struct
+ * output      - pointer to struct User
+ * side effects - add's an User information block to a client
+ *                if it was not previously allocated.
+ */
+struct User *
+make_user(struct Client *client_p)
+{
+       struct User *user;
+
+       user = client_p->user;
+       if(!user)
+       {
+               user = (struct User *) BlockHeapAlloc(user_heap);
+               user->refcnt = 1;
+               client_p->user = user;
+       }
+       return user;
+}
+
+/*
+ * make_server
+ *
+ * inputs      - pointer to client struct
+ * output      - pointer to server_t
+ * side effects - add's an Server information block to a client
+ *                if it was not previously allocated.
+ */
+server_t *
+make_server(struct Client *client_p)
+{
+       server_t *serv = client_p->serv;
+
+       if(!serv)
+       {
+               serv = (server_t *) MyMalloc(sizeof(server_t));
+               client_p->serv = serv;
+       }
+       return client_p->serv;
+}
+
+/*
+ * free_user
+ * 
+ * inputs      - pointer to user struct
+ *             - pointer to client struct
+ * output      - none
+ * side effects - Decrease user reference count by one and release block,
+ *                if count reaches 0
+ */
+void
+free_user(struct User *user, struct Client *client_p)
+{
+       if(--user->refcnt <= 0)
+       {
+               if(user->away)
+                       MyFree((char *) user->away);
+               /*
+                * sanity check
+                */
+               if(user->refcnt < 0 || user->invited.head || user->channel.head)
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "* %#lx user (%s!%s@%s) %#lx %#lx %#lx %lu %d *",
+                                            (unsigned long) client_p,
+                                            client_p ? client_p->
+                                            name : "<noname>",
+                                            client_p->username,
+                                            client_p->host,
+                                            (unsigned long) user,
+                                            (unsigned long) user->invited.head,
+                                            (unsigned long) user->channel.head, 
+                                            dlink_list_length(&user->channel),
+                                            user->refcnt);
+                       s_assert(!user->refcnt);
+                       s_assert(!user->invited.head);
+                       s_assert(!user->channel.head);
+               }
+
+               BlockHeapFree(user_heap, user);
+       }
+}
+
+void
+init_uid(void)
+{
+       int i;
+
+       for(i = 0; i < 3; i++)
+               current_uid[i] = me.id[i];
+
+       for(i = 3; i < 9; i++)
+               current_uid[i] = 'A';
+
+       current_uid[9] = '\0';
+}
+
+
+char *
+generate_uid(void)
+{
+       int i;
+
+       for(i = 8; i > 3; i--)
+       {
+               if(current_uid[i] == 'Z')
+               {
+                       current_uid[i] = '0';
+                       return current_uid;
+               }
+               else if(current_uid[i] != '9')
+               {
+                       current_uid[i]++;
+                       return current_uid;
+               }
+               else
+                       current_uid[i] = 'A';
+       }
+
+       /* if this next if() triggers, we're fucked. */
+       if(current_uid[3] == 'Z')
+       {
+               current_uid[i] = 'A';
+               s_assert(0);
+       }
+       else
+               current_uid[i]++;
+
+       return current_uid;
+}
+
+/*
+ * close_connection
+ *        Close the physical connection. This function must make
+ *        MyConnect(client_p) == FALSE, and set client_p->from == NULL.
+ */
+void
+close_connection(struct Client *client_p)
+{
+       s_assert(client_p != NULL);
+       if(client_p == NULL)
+               return;
+
+       s_assert(MyConnect(client_p));
+       if(!MyConnect(client_p))
+               return;
+       
+       if(IsServer(client_p))
+       {
+               struct server_conf *server_p;
+
+               ServerStats->is_sv++;
+               ServerStats->is_sbs += client_p->localClient->sendB;
+               ServerStats->is_sbr += client_p->localClient->receiveB;
+               ServerStats->is_sks += client_p->localClient->sendK;
+               ServerStats->is_skr += client_p->localClient->receiveK;
+               ServerStats->is_sti += CurrentTime - client_p->localClient->firsttime;
+               if(ServerStats->is_sbs > 2047)
+               {
+                       ServerStats->is_sks += (ServerStats->is_sbs >> 10);
+                       ServerStats->is_sbs &= 0x3ff;
+               }
+               if(ServerStats->is_sbr > 2047)
+               {
+                       ServerStats->is_skr += (ServerStats->is_sbr >> 10);
+                       ServerStats->is_sbr &= 0x3ff;
+               }
+
+               /*
+                * If the connection has been up for a long amount of time, schedule
+                * a 'quick' reconnect, else reset the next-connect cycle.
+                */
+               if((server_p = find_server_conf(client_p->name)) != NULL)
+               {
+                       /*
+                        * 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.
+                        */
+                       server_p->hold = time(NULL);
+                       server_p->hold +=
+                               (server_p->hold - client_p->localClient->lasttime >
+                                HANGONGOODLINK) ? HANGONRETRYDELAY : ConFreq(server_p->class);
+               }
+
+       }
+       else if(IsClient(client_p))
+       {
+               ServerStats->is_cl++;
+               ServerStats->is_cbs += client_p->localClient->sendB;
+               ServerStats->is_cbr += client_p->localClient->receiveB;
+               ServerStats->is_cks += client_p->localClient->sendK;
+               ServerStats->is_ckr += client_p->localClient->receiveK;
+               ServerStats->is_cti += CurrentTime - client_p->localClient->firsttime;
+               if(ServerStats->is_cbs > 2047)
+               {
+                       ServerStats->is_cks += (ServerStats->is_cbs >> 10);
+                       ServerStats->is_cbs &= 0x3ff;
+               }
+               if(ServerStats->is_cbr > 2047)
+               {
+                       ServerStats->is_ckr += (ServerStats->is_cbr >> 10);
+                       ServerStats->is_cbr &= 0x3ff;
+               }
+       }
+       else
+               ServerStats->is_ni++;
+
+       if(-1 < client_p->localClient->fd)
+       {
+               /* attempt to flush any pending dbufs. Evil, but .. -- adrian */
+               if(!IsIOError(client_p))
+                       send_queued_write(client_p->localClient->fd, client_p);
+
+               comm_close(client_p->localClient->fd);
+               client_p->localClient->fd = -1;
+       }
+
+       if(HasServlink(client_p))
+       {
+               if(client_p->localClient->fd > -1)
+               {
+                       comm_close(client_p->localClient->ctrlfd);
+                       client_p->localClient->ctrlfd = -1;
+               }
+       }
+
+       linebuf_donebuf(&client_p->localClient->buf_sendq);
+       linebuf_donebuf(&client_p->localClient->buf_recvq);
+       detach_conf(client_p);
+
+       /* XXX shouldnt really be done here. */
+       detach_server_conf(client_p);
+
+       client_p->from = NULL;  /* ...this should catch them! >:) --msa */
+       ClearMyConnect(client_p);
+       SetIOError(client_p);
+}
+
+
+
+void
+error_exit_client(struct Client *client_p, int error)
+{
+       /*
+        * ...hmm, with non-blocking sockets we might get
+        * here from quite valid reasons, although.. why
+        * would select report "data available" when there
+        * wasn't... so, this must be an error anyway...  --msa
+        * actually, EOF occurs when read() returns 0 and
+        * in due course, select() returns that fd as ready
+        * for reading even though it ends up being an EOF. -avalon
+        */
+       char errmsg[255];
+       int current_error = comm_get_sockerr(client_p->localClient->fd);
+
+       SetIOError(client_p);
+
+       if(IsServer(client_p) || IsHandshake(client_p))
+       {
+               int connected = CurrentTime - client_p->localClient->firsttime;
+
+               if(error == 0)
+               {
+                       sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) && !IsServer(client_p) ? L_NETWIDE : L_ALL,
+                                            "Server %s closed the connection",
+                                            get_server_name(client_p, SHOW_IP));
+
+                       ilog(L_SERVER, "Server %s closed the connection",
+                            log_client_name(client_p, SHOW_IP));
+               }
+               else
+               {
+                       sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) && !IsServer(client_p) ? L_NETWIDE : L_ALL,
+                                       "Lost connection to %s: %s",
+                                       client_p->name, strerror(current_error));
+                       ilog(L_SERVER, "Lost connection to %s: %s",
+                               log_client_name(client_p, SHOW_IP), strerror(current_error));
+               }
+
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "%s had been connected for %d day%s, %2d:%02d:%02d",
+                                    client_p->name, connected / 86400,
+                                    (connected / 86400 == 1) ? "" : "s",
+                                    (connected % 86400) / 3600,
+                                    (connected % 3600) / 60, connected % 60);
+       }
+
+       if(error == 0)
+               strlcpy(errmsg, "Remote host closed the connection", sizeof(errmsg));
+       else
+               ircsnprintf(errmsg, sizeof(errmsg), "Read error: %s", strerror(current_error));
+
+       exit_client(client_p, client_p, &me, errmsg);
+}
diff --git a/src/extban.c b/src/extban.c
new file mode 100644 (file)
index 0000000..f02c98c
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ *  charybdis: A slightly useful ircd.
+ *  extban.c: extended ban types ($type:data)
+ *
+ * Copyright (C) 2006 charybdis development 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: extban.c 1389 2006-05-20 19:19:00Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "channel.h"
+#include "client.h"
+#include "common.h"
+
+ExtbanFunc extban_table[256] = { NULL };
+
+int
+match_extban(const char *banstr, struct Client *client_p, struct Channel *chptr, long mode_type)
+{
+       const char *p;
+       int invert = 0, result = EXTBAN_INVALID;
+       ExtbanFunc f;
+
+       if (*banstr != '$')
+               return 0;
+       p = banstr + 1;
+       if (*p == '~')
+       {
+               invert = 1;
+               p++;
+       }
+       f = extban_table[(unsigned char) ToLower(*p)];
+       if (*p != '\0')
+       {
+               p++;
+               if (*p == ':')
+                       p++;
+               else
+                       p = NULL;
+       }
+       if (f != NULL)
+               result = f(p, client_p, chptr, mode_type);
+       else
+               result = EXTBAN_INVALID;
+
+       if (invert)
+               return result == EXTBAN_NOMATCH;
+       else
+               return result == EXTBAN_MATCH;
+}
+
+int
+valid_extban(const char *banstr, struct Client *client_p, struct Channel *chptr, long mode_type)
+{
+       const char *p;
+       int invert = 0, result = EXTBAN_INVALID;
+       ExtbanFunc f;
+
+       if (*banstr != '$')
+               return 0;
+       p = banstr + 1;
+       if (*p == '~')
+       {
+               invert = 1;
+               p++;
+       }
+       f = extban_table[(unsigned char) ToLower(*p)];
+       if (*p != '\0')
+       {
+               p++;
+               if (*p == ':')
+                       p++;
+               else
+                       p = NULL;
+       }
+       if (f != NULL)
+               result = f(p, client_p, chptr, mode_type);
+       else
+               result = EXTBAN_INVALID;
+
+       return result != EXTBAN_INVALID;
+}
+
+const char *
+get_extban_string(void)
+{
+       static char e[256];
+       int i, j;
+
+       j = 0;
+       for (i = 1; i < 256; i++)
+               if (i == ToLower(i) && extban_table[i])
+                       e[j++] = i;
+       e[j] = 0;
+       return e;
+}
diff --git a/src/fnvhash.s b/src/fnvhash.s
new file mode 100644 (file)
index 0000000..7a6daa4
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * charybdis: a slightly useful ircd.
+ * fnvhash.s: x86-optimised FNV hashing implementation
+ *
+ * Copyright (c) 2006 charybdis development team
+ *
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: fnvhash.s 2725 2006-11-09 23:43:35Z jilles $
+ */
+
+/* Safely moves hashv from %edx to %eax and returns back to the calling parent. */
+fnv_out:
+       movzbl  12(%ebp), %ecx
+       movl    -4(%ebp), %eax
+       movl    %eax, %edx
+       shrl    %cl, %edx
+       movl    12(%ebp), %eax
+       xorl    $2, %eax
+       decl    %eax
+       andl    -4(%ebp), %eax
+       xorl    %edx, %eax
+       movl    %eax, -4(%ebp)
+       movl    -4(%ebp), %eax
+       leave
+       ret
+
+/*
+ * Capitalizes the contents of %eax and adds it to the hashv in %edx.
+ * Returns hashv in register %eax.
+ *     - nenolod
+ */
+.globl fnv_hash_upper
+       .type   fnv_hash_upper, @function
+fnv_hash_upper:
+       pushl   %ebp
+       movl    %esp, %ebp
+       subl    $4, %esp
+       movl    $-2128831035, -4(%ebp)          /* u_int32_t h = FNV1_32_INIT */
+.eat_data_upper:                               /* while loop construct */
+       movl    8(%ebp), %eax                   /* move value of *s to %eax */
+       cmpb    $0, (%eax)                      /* is eax == 0? */
+       jne     .hash_capitalized               /* if no, then capitalize and hash */
+       jmp     fnv_out                         /* if yes, then exit out of the loop */
+.hash_capitalized:
+       movl    8(%ebp), %eax
+       movzbl  (%eax), %eax                    /* increment s (%eax) */
+       movzbl  ToUpperTab(%eax), %edx          /* hashv ^= ToUpperTab(%eax) */
+       leal    -4(%ebp), %eax
+       xorl    %edx, (%eax)                    /* hashv = 0 */
+       incl    8(%ebp)
+       movl    -4(%ebp), %eax
+       imull   $16777619, %eax, %eax           /* FNV1_32_PRIME */
+       movl    %eax, -4(%ebp)                  /* add this byte to hashv, and */
+       jmp     .eat_data_upper                 /*   go back for more...       */
+
+/*
+ * Hashes (no case change) the contents of %eax and adds it to the hashv in %edx.
+ * Returns hashv in register %eax.
+ *     - nenolod
+ */
+.globl fnv_hash
+       .type   fnv_hash, @function
+fnv_hash:
+       pushl   %ebp
+       movl    %esp, %ebp
+       subl    $4, %esp
+       movl    $-2128831035, -4(%ebp)          /* u_int32_t h = FNV1_32_INIT */
+.eat_data:                                     /* again, the while loop construct */
+       movl    8(%ebp), %eax                   /* move value of *s to eax */
+       cmpb    $0, (%eax)                      /* is eax == 0? */
+       jne     .hash_lowercase                 /* if not, jump to .hash_lowercase */ 
+       jmp     fnv_out                         /* otherwise, jump to fnv_out */
+.hash_lowercase:
+       movl    8(%ebp), %eax
+       movzbl  (%eax), %edx
+       leal    -4(%ebp), %eax
+       xorl    %edx, (%eax)
+       incl    8(%ebp)                         /* h << 1 */
+       movl    -4(%ebp), %eax
+       imull   $16777619, %eax, %eax           /* FNV1_32_PRIME */
+       movl    %eax, -4(%ebp)                  /* add this byte to hashv, then */
+       jmp     .eat_data                       /*   check for more...          */
+
+/*
+ * Hashes (no case change) the contents of %eax and adds it to the hashv in %edx.
+ * Returns hashv in register %eax.
+ *
+ * Bounds checking is performed.
+ *     - nenolod
+ */
+.globl fnv_hash_len
+       .type   fnv_hash_len, @function
+fnv_hash_len:
+       pushl   %ebp
+       movl    %esp, %ebp
+       subl    $8, %esp
+       movl    $-2128831035, -4(%ebp)
+       movl    16(%ebp), %eax
+       addl    8(%ebp), %eax
+       movl    %eax, -8(%ebp)
+.eat_data_len:
+       movl    8(%ebp), %eax
+       cmpb    $0, (%eax)
+       je      fnv_out
+       movl    8(%ebp), %eax
+       cmpl    -8(%ebp), %eax
+       jb      .hash_lowercase_len
+       jmp     fnv_out
+.hash_lowercase_len:
+       movl    8(%ebp), %eax
+       movzbl  (%eax), %edx
+       leal    -4(%ebp), %eax
+       xorl    %edx, (%eax)
+       incl    8(%ebp)
+       movl    -4(%ebp), %eax
+       imull   $16777619, %eax, %eax           /* FNV1_32_PRIME */
+       movl    %eax, -4(%ebp)
+       jmp     .eat_data_len
+
+/*
+ * Hashes (no case change) the contents of %eax and adds it to the hashv in %edx.
+ * Returns hashv in register %eax.
+ *
+ * Bounds checking is performed.
+ *     - nenolod
+ */
+.globl fnv_hash_upper_len
+       .type   fnv_hash_upper_len, @function
+fnv_hash_upper_len:
+       pushl   %ebp
+       movl    %esp, %ebp
+       subl    $8, %esp
+       movl    $-2128831035, -4(%ebp)
+       movl    16(%ebp), %eax
+       addl    8(%ebp), %eax
+       movl    %eax, -8(%ebp)
+.eat_upper_len:
+       movl    8(%ebp), %eax
+       cmpb    $0, (%eax)
+       je      fnv_out
+       movl    8(%ebp), %eax
+       cmpl    -8(%ebp), %eax
+       jb      .hash_uppercase_len
+       jmp     fnv_out
+.hash_uppercase_len:
+       movl    8(%ebp), %eax
+       movzbl  (%eax), %eax
+       movzbl  ToUpperTab(%eax), %edx
+       leal    -4(%ebp), %eax
+       xorl    %edx, (%eax)
+       incl    8(%ebp)
+       movl    -4(%ebp), %eax
+       imull   $16777619, %eax, %eax           /* FNV1_32_PRIME */
+       movl    %eax, -4(%ebp)
+       jmp     .eat_upper_len
diff --git a/src/getopt.c b/src/getopt.c
new file mode 100644 (file)
index 0000000..aff907e
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  getopt.c: Uses getopt to fetch the command line options.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: getopt.c 6 2005-09-10 01:02:21Z nenolod $
+ */
+
+#include "stdinc.h"
+
+#include "ircd_getopt.h"
+
+# define OPTCHAR '-'
+
+void
+parseargs(int *argc, char ***argv, struct lgetopt *opts)
+{
+       int i;
+       char *progname = (*argv)[0];
+
+       /* loop through each argument */
+       for (;;)
+       {
+               int found = 0;
+
+               (*argc)--;
+               (*argv)++;
+
+               if(*argc < 1)
+               {
+                       return;
+               }
+
+               /* check if it *is* an arg.. */
+               if((*argv)[0][0] != OPTCHAR)
+               {
+                       return;
+               }
+
+               (*argv)[0]++;
+
+               /* search through our argument list, and see if it matches */
+               for (i = 0; opts[i].opt; i++)
+               {
+                       if(!strcmp(opts[i].opt, (*argv)[0]))
+                       {
+                               /* found our argument */
+                               found = 1;
+
+                               switch (opts[i].argtype)
+                               {
+                               case YESNO:
+                                       *((int *) opts[i].argloc) = 1;
+                                       break;
+                               case INTEGER:
+                                       if(*argc < 2)
+                                       {
+                                               fprintf(stderr,
+                                                       "Error: option '%c%s' requires an argument\n",
+                                                       OPTCHAR, opts[i].opt);
+                                               usage((*argv)[0]);
+                                       }
+
+                                       *((int *) opts[i].argloc) = atoi((*argv)[1]);
+
+                                       (*argc)--;
+                                       (*argv)++;
+                                       break;
+                               case STRING:
+                                       if(*argc < 2)
+                                       {
+                                               fprintf(stderr,
+                                                       "error: option '%c%s' requires an argument\n",
+                                                       OPTCHAR, opts[i].opt);
+                                               usage(progname);
+                                       }
+
+                                       *((char **) opts[i].argloc) =
+                                               malloc(strlen((*argv)[1]) + 1);
+                                       strcpy(*((char **) opts[i].argloc), (*argv)[1]);
+
+                                       (*argc)--;
+                                       (*argv)++;
+                                       break;
+
+                               case USAGE:
+                                       usage(progname);
+                                /*NOTREACHED*/ default:
+                                       fprintf(stderr,
+                                               "Error: internal error in parseargs() at %s:%d\n",
+                                               __FILE__, __LINE__);
+                                       exit(EXIT_FAILURE);
+                               }
+                       }
+               }
+               if(!found)
+               {
+                       fprintf(stderr, "error: unknown argument '%c%s'\n", OPTCHAR, (*argv)[0]);
+                       usage(progname);
+               }
+       }
+}
+
+void
+usage(char *name)
+{
+       int i = 0;
+
+       fprintf(stderr, "Usage: %s [options]\n", name);
+       fprintf(stderr, "Where valid options are:\n");
+
+       for (i = 0; myopts[i].opt; i++)
+       {
+               fprintf(stderr, "\t%c%-10s %-20s%s\n", OPTCHAR,
+                       myopts[i].opt, (myopts[i].argtype == YESNO
+                                       || myopts[i].argtype ==
+                                       USAGE) ? "" : myopts[i].argtype ==
+                       INTEGER ? "<number>" : "<string>", myopts[i].desc);
+       }
+
+       exit(EXIT_FAILURE);
+}
diff --git a/src/hash.c b/src/hash.c
new file mode 100644 (file)
index 0000000..86b22bc
--- /dev/null
@@ -0,0 +1,901 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  hash.c: Maintains hashtables.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: hash.c 1321 2006-05-13 23:49:14Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "ircd_defs.h"
+#include "tools.h"
+#include "s_conf.h"
+#include "channel.h"
+#include "client.h"
+#include "common.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "memory.h"
+#include "msg.h"
+#include "cache.h"
+#include "s_newconf.h"
+
+dlink_list *clientTable;
+dlink_list *channelTable;
+dlink_list *idTable;
+dlink_list *resvTable;
+dlink_list *hostTable;
+dlink_list *helpTable;
+dlink_list *ndTable;
+
+/*
+ * look in whowas.c for the missing ...[WW_MAX]; entry
+ */
+
+/*
+ * Hashing.
+ *
+ *   The server uses a chained hash table to provide quick and efficient
+ * hash table maintenance (providing the hash function works evenly over
+ * the input range).  The hash table is thus not susceptible to problems
+ * of filling all the buckets or the need to rehash.
+ *    It is expected that the hash table would look something like this
+ * during use:
+ *                   +-----+    +-----+    +-----+   +-----+
+ *                ---| 224 |----| 225 |----| 226 |---| 227 |---
+ *                   +-----+    +-----+    +-----+   +-----+
+ *                      |          |          |
+ *                   +-----+    +-----+    +-----+
+ *                   |  A  |    |  C  |    |  D  |
+ *                   +-----+    +-----+    +-----+
+ *                      |
+ *                   +-----+
+ *                   |  B  |
+ *                   +-----+
+ *
+ * A - GOPbot, B - chang, C - hanuaway, D - *.mu.OZ.AU
+ *
+ * The order shown above is just one instant of the server. 
+ *
+ *
+ * The hash functions currently used are based Fowler/Noll/Vo hashes
+ * which work amazingly well and have a extremely low collision rate
+ * For more info see http://www.isthe.com/chongo/tech/comp/fnv/index.html
+ *
+ * 
+ */
+
+/* init_hash()
+ *
+ * clears the various hashtables
+ */
+void
+init_hash(void)
+{
+       clientTable = MyMalloc(sizeof(dlink_list) * U_MAX);
+       idTable = MyMalloc(sizeof(dlink_list) * U_MAX);
+       ndTable = MyMalloc(sizeof(dlink_list) * U_MAX);
+       channelTable = MyMalloc(sizeof(dlink_list) * CH_MAX);
+       hostTable = MyMalloc(sizeof(dlink_list) * HOST_MAX);
+       resvTable = MyMalloc(sizeof(dlink_list) * R_MAX);
+       helpTable = MyMalloc(sizeof(dlink_list) * HELP_MAX);
+}
+
+#ifndef RICER_HASHING
+u_int32_t
+fnv_hash_upper(const unsigned char *s, int bits)
+{
+       u_int32_t h = FNV1_32_INIT;
+
+       while (*s)
+       {
+               h ^= ToUpper(*s++);
+               h += (h<<1) + (h<<4) + (h<<7) + (h << 8) + (h << 24);
+       }
+        h = (h >> bits) ^ (h & ((2^bits)-1));
+       return h;
+}
+
+u_int32_t
+fnv_hash(const unsigned char *s, int bits)
+{
+       u_int32_t h = FNV1_32_INIT;
+
+       while (*s)
+       {
+               h ^= *s++;
+               h += (h<<1) + (h<<4) + (h<<7) + (h << 8) + (h << 24);
+       }
+        h = (h >> bits) ^ (h & ((2^bits)-1));
+       return h;
+}
+
+u_int32_t
+fnv_hash_len(const unsigned char *s, int bits, int len)
+{
+       u_int32_t h = FNV1_32_INIT;
+       const unsigned char *x = s + len;
+       while (*s && s < x)
+       {
+               h ^= *s++;
+               h += (h<<1) + (h<<4) + (h<<7) + (h << 8) + (h << 24);
+       }
+        h = (h >> bits) ^ (h & ((2^bits)-1));
+       return h;
+}
+
+u_int32_t
+fnv_hash_upper_len(const unsigned char *s, int bits, int len)
+{
+       u_int32_t h = FNV1_32_INIT;
+       const unsigned char *x = s + len;
+       while (*s && s < x)
+       {
+               h ^= ToUpper(*s++);
+               h += (h<<1) + (h<<4) + (h<<7) + (h << 8) + (h << 24);
+       }
+        h = (h >> bits) ^ (h & ((2^bits)-1));
+       return h;
+}
+#endif
+
+/* hash_nick()
+ *
+ * hashes a nickname, first converting to lowercase
+ */
+static u_int32_t
+hash_nick(const char *name)
+{
+       return fnv_hash_upper((const unsigned char *) name, U_MAX_BITS);
+}
+
+/* hash_id()
+ *
+ * hashes an id, case is kept
+ */
+static u_int32_t
+hash_id(const char *name)
+{
+       return fnv_hash((const unsigned char *) name, U_MAX_BITS);
+}
+
+/* hash_channel()
+ *
+ * hashes a channel name, based on first 30 chars only for efficiency
+ */
+static u_int32_t
+hash_channel(const char *name)
+{
+       return fnv_hash_upper_len((const unsigned char *) name, CH_MAX_BITS, 30);
+}
+
+/* hash_hostname()
+ *
+ * hashes a hostname, based on first 30 chars only, as thats likely to
+ * be more dynamic than rest.
+ */
+static u_int32_t
+hash_hostname(const char *name)
+{
+       return fnv_hash_upper_len((const unsigned char *) name, HOST_MAX_BITS, 30);
+}
+
+/* hash_resv()
+ *
+ * hashes a resv channel name, based on first 30 chars only
+ */
+static u_int32_t
+hash_resv(const char *name)
+{
+       return fnv_hash_upper_len((const unsigned char *) name, R_MAX_BITS, 30);
+}
+
+static unsigned int
+hash_help(const char *name)
+{
+       unsigned int h = 0;
+
+       while(*name)
+       {
+               h += (unsigned int) (ToLower(*name++) & 0xDF);
+       }
+
+       return (h % HELP_MAX);
+}
+
+/* add_to_id_hash()
+ *
+ * adds an entry to the id hash table
+ */
+void
+add_to_id_hash(const char *name, struct Client *client_p)
+{
+       unsigned int hashv;
+
+       if(EmptyString(name) || (client_p == NULL))
+               return;
+
+       hashv = hash_id(name);
+       dlinkAddAlloc(client_p, &idTable[hashv]);
+}
+
+/* add_to_client_hash()
+ *
+ * adds an entry (client/server) to the client hash table
+ */
+void
+add_to_client_hash(const char *name, struct Client *client_p)
+{
+       unsigned int hashv;
+
+       s_assert(name != NULL);
+       s_assert(client_p != NULL);
+       if(EmptyString(name) || (client_p == NULL))
+               return;
+
+       hashv = hash_nick(name);
+       dlinkAddAlloc(client_p, &clientTable[hashv]);
+}
+
+/* add_to_hostname_hash()
+ *
+ * adds a client entry to the hostname hash table
+ */
+void
+add_to_hostname_hash(const char *hostname, struct Client *client_p)
+{
+       unsigned int hashv;
+
+       s_assert(hostname != NULL);
+       s_assert(client_p != NULL);
+       if(EmptyString(hostname) || (client_p == NULL))
+               return;
+
+       hashv = hash_hostname(hostname);
+       dlinkAddAlloc(client_p, &hostTable[hashv]);
+}
+
+/* add_to_resv_hash()
+ *
+ * adds a resv channel entry to the resv hash table
+ */
+void
+add_to_resv_hash(const char *name, struct ConfItem *aconf)
+{
+       unsigned int hashv;
+
+       s_assert(!EmptyString(name));
+       s_assert(aconf != NULL);
+       if(EmptyString(name) || aconf == NULL)
+               return;
+
+       hashv = hash_resv(name);
+       dlinkAddAlloc(aconf, &resvTable[hashv]);
+}
+
+void
+add_to_help_hash(const char *name, struct cachefile *hptr)
+{
+       unsigned int hashv;
+
+       if(EmptyString(name) || hptr == NULL)
+               return;
+
+       hashv = hash_help(name);
+       dlinkAddAlloc(hptr, &helpTable[hashv]);
+}
+
+void
+add_to_nd_hash(const char *name, struct nd_entry *nd)
+{
+       nd->hashv = hash_nick(name);
+       dlinkAdd(nd, &nd->hnode, &ndTable[nd->hashv]);
+}
+
+/* del_from_id_hash()
+ *
+ * removes an id from the id hash table
+ */
+void
+del_from_id_hash(const char *id, struct Client *client_p)
+{
+       unsigned int hashv;
+
+       s_assert(id != NULL);
+       s_assert(client_p != NULL);
+       if(EmptyString(id) || client_p == NULL)
+               return;
+
+       hashv = hash_id(id);
+       dlinkFindDestroy(client_p, &idTable[hashv]);
+}
+
+/* del_from_client_hash()
+ *
+ * removes a client/server from the client hash table
+ */
+void
+del_from_client_hash(const char *name, struct Client *client_p)
+{
+       unsigned int hashv;
+
+       /* no s_asserts, this can happen when removing a client that
+        * is unregistered.
+        */
+       if(EmptyString(name) || client_p == NULL)
+               return;
+
+       hashv = hash_nick(name);
+       dlinkFindDestroy(client_p, &clientTable[hashv]);
+}
+
+/* del_from_channel_hash()
+ * 
+ * removes a channel from the channel hash table
+ */
+void
+del_from_channel_hash(const char *name, struct Channel *chptr)
+{
+       unsigned int hashv;
+
+       s_assert(name != NULL);
+       s_assert(chptr != NULL);
+
+       if(EmptyString(name) || chptr == NULL)
+               return;
+
+       hashv = hash_channel(name);
+       dlinkFindDestroy(chptr, &channelTable[hashv]);
+}
+
+/* del_from_hostname_hash()
+ *
+ * removes a client entry from the hostname hash table
+ */
+void
+del_from_hostname_hash(const char *hostname, struct Client *client_p)
+{
+       unsigned int hashv;
+
+       if(hostname == NULL || client_p == NULL)
+               return;
+
+       hashv = hash_hostname(hostname);
+
+       dlinkFindDestroy(client_p, &hostTable[hashv]);
+}
+
+/* del_from_resv_hash()
+ *
+ * removes a resv entry from the resv hash table
+ */
+void
+del_from_resv_hash(const char *name, struct ConfItem *aconf)
+{
+       unsigned int hashv;
+
+       s_assert(name != NULL);
+       s_assert(aconf != NULL);
+       if(EmptyString(name) || aconf == NULL)
+               return;
+
+       hashv = hash_resv(name);
+
+       dlinkFindDestroy(aconf, &resvTable[hashv]);
+}
+
+void
+clear_help_hash(void)
+{
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+       int i;
+
+       HASH_WALK_SAFE(i, HELP_MAX, ptr, next_ptr, helpTable)
+       {
+               free_cachefile(ptr->data);
+               dlinkDestroy(ptr, &helpTable[i]);
+       }
+       HASH_WALK_END
+}
+
+/* find_id()
+ *
+ * finds a client entry from the id hash table
+ */
+struct Client *
+find_id(const char *name)
+{
+       struct Client *target_p;
+       dlink_node *ptr;
+       unsigned int hashv;
+
+       if(EmptyString(name))
+               return NULL;
+
+       hashv = hash_id(name);
+
+       DLINK_FOREACH(ptr, idTable[hashv].head)
+       {
+               target_p = ptr->data;
+
+               if(strcmp(name, target_p->id) == 0)
+                       return target_p;
+       }
+
+       return NULL;
+}
+
+/* hash_find_masked_server()
+ * 
+ * Whats happening in this next loop ? Well, it takes a name like
+ * foo.bar.edu and proceeds to earch for *.edu and then *.bar.edu.
+ * This is for checking full server names against masks although
+ * it isnt often done this way in lieu of using matches().
+ *
+ * Rewrote to do *.bar.edu first, which is the most likely case,
+ * also made const correct
+ * --Bleep
+ */
+static struct Client *
+hash_find_masked_server(struct Client *source_p, const char *name)
+{
+       char buf[HOSTLEN + 1];
+       char *p = buf;
+       char *s;
+       struct Client *server;
+
+       if('*' == *name || '.' == *name)
+               return NULL;
+
+       /* copy it across to give us a buffer to work on */
+       strlcpy(buf, name, sizeof(buf));
+
+       while ((s = strchr(p, '.')) != 0)
+       {
+               *--s = '*';
+               /*
+                * Dont need to check IsServer() here since nicknames cant
+                * have *'s in them anyway.
+                */
+               if((server = find_server(source_p, s)))
+                       return server;
+               p = s + 2;
+       }
+
+       return NULL;
+}
+
+/* find_any_client()
+ *
+ * finds a client/server/masked server entry from the hash
+ */
+struct Client *
+find_any_client(const char *name)
+{
+       struct Client *target_p;
+       dlink_node *ptr;
+       unsigned int hashv;
+
+       s_assert(name != NULL);
+       if(EmptyString(name))
+               return NULL;
+
+       /* hunting for an id, not a nick */
+       if(IsDigit(*name))
+               return (find_id(name));
+
+       hashv = hash_nick(name);
+
+       DLINK_FOREACH(ptr, clientTable[hashv].head)
+       {
+               target_p = ptr->data;
+
+               if(irccmp(name, target_p->name) == 0)
+                       return target_p;
+       }
+
+       /* wasnt found, look for a masked server */
+       return hash_find_masked_server(NULL, name);
+}
+
+/* find_client()
+ *
+ * finds a client/server entry from the client hash table
+ */
+struct Client *
+find_client(const char *name)
+{
+       struct Client *target_p;
+       dlink_node *ptr;
+       unsigned int hashv;
+
+       s_assert(name != NULL);
+       if(EmptyString(name))
+               return NULL;
+
+       /* hunting for an id, not a nick */
+       if(IsDigit(*name))
+               return (find_id(name));
+
+       hashv = hash_nick(name);
+
+       DLINK_FOREACH(ptr, clientTable[hashv].head)
+       {
+               target_p = ptr->data;
+
+               if(irccmp(name, target_p->name) == 0)
+                       return target_p;
+       }
+
+       return NULL;
+}
+
+/* find_named_client()
+ *
+ * finds a client/server entry from the client hash table
+ */
+struct Client *
+find_named_client(const char *name)
+{
+       struct Client *target_p;
+       dlink_node *ptr;
+       unsigned int hashv;
+
+       s_assert(name != NULL);
+       if(EmptyString(name))
+               return NULL;
+
+       hashv = hash_nick(name);
+
+       DLINK_FOREACH(ptr, clientTable[hashv].head)
+       {
+               target_p = ptr->data;
+
+               if(irccmp(name, target_p->name) == 0)
+                       return target_p;
+       }
+
+       return NULL;
+}
+
+/* find_server()
+ *
+ * finds a server from the client hash table
+ */
+struct Client *
+find_server(struct Client *source_p, const char *name)
+{
+       struct Client *target_p;
+       dlink_node *ptr;
+       unsigned int hashv;
+  
+       if(EmptyString(name))
+               return NULL;
+
+       if((source_p == NULL || !MyClient(source_p)) && 
+          IsDigit(*name) && strlen(name) == 3)
+       {
+               target_p = find_id(name);
+               return(target_p);
+       }
+
+       hashv = hash_nick(name);
+
+       DLINK_FOREACH(ptr, clientTable[hashv].head)
+       {
+               target_p = ptr->data;
+
+               if((IsServer(target_p) || IsMe(target_p)) &&
+                  irccmp(name, target_p->name) == 0)
+                               return target_p;
+       }
+
+       /* wasnt found, look for a masked server */
+       return hash_find_masked_server(source_p, name);
+}
+
+/* find_hostname()
+ *
+ * finds a hostname dlink list from the hostname hash table.
+ * we return the full dlink list, because you can have multiple
+ * entries with the same hostname
+ */
+dlink_node *
+find_hostname(const char *hostname)
+{
+       unsigned int hashv;
+
+       if(EmptyString(hostname))
+               return NULL;
+
+       hashv = hash_hostname(hostname);
+
+       return hostTable[hashv].head;
+}
+
+/* find_channel()
+ *
+ * finds a channel from the channel hash table
+ */
+struct Channel *
+find_channel(const char *name)
+{
+       struct Channel *chptr;
+       dlink_node *ptr;
+       unsigned int hashv;
+
+       s_assert(name != NULL);
+       if(EmptyString(name))
+               return NULL;
+
+       hashv = hash_channel(name);
+
+       DLINK_FOREACH(ptr, channelTable[hashv].head)
+       {
+               chptr = ptr->data;
+
+               if(irccmp(name, chptr->chname) == 0)
+                       return chptr;
+       }
+
+       return NULL;
+}
+
+/*
+ * get_or_create_channel
+ * inputs       - client pointer
+ *              - channel name
+ *              - pointer to int flag whether channel was newly created or not
+ * output       - returns channel block or NULL if illegal name
+ *             - also modifies *isnew
+ *
+ *  Get Channel block for chname (and allocate a new channel
+ *  block, if it didn't exist before).
+ */
+struct Channel *
+get_or_create_channel(struct Client *client_p, const char *chname, int *isnew)
+{
+       struct Channel *chptr;
+       dlink_node *ptr;
+       unsigned int hashv;
+       int len;
+       const char *s = chname;
+
+       if(EmptyString(s))
+               return NULL;
+
+       len = strlen(s);
+       if(len > CHANNELLEN)
+       {
+               char *t;
+               if(IsServer(client_p))
+               {
+                       sendto_realops_snomask(SNO_DEBUG, L_ALL,
+                                            "*** Long channel name from %s (%d > %d): %s",
+                                            client_p->name, len, CHANNELLEN, s);
+               }
+               len = CHANNELLEN;
+               t = LOCAL_COPY(s);
+               *(t + CHANNELLEN) = '\0';
+               s = t;
+       }
+
+       hashv = hash_channel(s);
+
+       DLINK_FOREACH(ptr, channelTable[hashv].head)
+       {
+               chptr = ptr->data;
+
+               if(irccmp(s, chptr->chname) == 0)
+               {
+                       if(isnew != NULL)
+                               *isnew = 0;
+                       return chptr;
+               }
+       }
+
+       if(isnew != NULL)
+               *isnew = 1;
+
+       chptr = allocate_channel(s);
+
+       dlinkAdd(chptr, &chptr->node, &global_channel_list);
+
+       chptr->channelts = CurrentTime; /* doesn't hurt to set it here */
+
+       dlinkAddAlloc(chptr, &channelTable[hashv]);
+
+       return chptr;
+}
+
+/* hash_find_resv()
+ *
+ * hunts for a resv entry in the resv hash table
+ */
+struct ConfItem *
+hash_find_resv(const char *name)
+{
+       struct ConfItem *aconf;
+       dlink_node *ptr;
+       unsigned int hashv;
+
+       s_assert(name != NULL);
+       if(EmptyString(name))
+               return NULL;
+
+       hashv = hash_resv(name);
+
+       DLINK_FOREACH(ptr, resvTable[hashv].head)
+       {
+               aconf = ptr->data;
+
+               if(!irccmp(name, aconf->name))
+               {
+                       aconf->port++;
+                       return aconf;
+               }
+       }
+
+       return NULL;
+}
+
+struct cachefile *
+hash_find_help(const char *name, int flags)
+{
+       struct cachefile *hptr;
+       dlink_node *ptr;
+       unsigned int hashv;
+
+       if(EmptyString(name))
+               return NULL;
+
+       hashv = hash_help(name);
+
+       DLINK_FOREACH(ptr, helpTable[hashv].head)
+       {
+               hptr = ptr->data;
+
+               if((irccmp(name, hptr->name) == 0) &&
+                  (hptr->flags & flags))
+                       return hptr;
+       }
+
+       return NULL;
+}
+
+void
+clear_resv_hash(void)
+{
+       struct ConfItem *aconf;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+       int i;
+
+       HASH_WALK_SAFE(i, R_MAX, ptr, next_ptr, resvTable)
+       {
+               aconf = ptr->data;
+
+               /* skip temp resvs */
+               if(aconf->hold)
+                       continue;
+
+               free_conf(ptr->data);
+               dlinkDestroy(ptr, &resvTable[i]);
+       }
+       HASH_WALK_END
+}
+
+struct nd_entry *
+hash_find_nd(const char *name)
+{
+       struct nd_entry *nd;
+       dlink_node *ptr;
+       unsigned int hashv;
+
+       if(EmptyString(name))
+               return NULL;
+
+       hashv = hash_nick(name);
+
+       DLINK_FOREACH(ptr, ndTable[hashv].head)
+       {
+               nd = ptr->data;
+
+               if(!irccmp(name, nd->name))
+                       return nd;
+       }
+
+       return NULL;
+}
+
+static void
+output_hash(struct Client *source_p, const char *name, int length, int *counts, int deepest)
+{
+       unsigned long total = 0;
+       int i;
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                       "B :%s Hash Statistics", name);
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                       "B :Size: %d Empty: %d (%.3f%%)",
+                       length, counts[0], 
+                       (float) ((counts[0]*100) / (float) length));
+
+       for(i = 1; i < 11; i++)
+       {
+               total += (counts[i] * i);
+       }
+
+       /* dont want to divide by 0! --fl */
+       if(counts[0] != length)
+               sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                               "B :Average depth: %.3f/%.3f Highest depth: %d",
+                               (float) (total / (length - counts[0])),
+                               (float) (total / length), deepest);
+
+       for(i = 0; i < 11; i++)
+       {
+               sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                               "B :Nodes with %d entries: %d",
+                               i, counts[i]);
+       }
+}
+       
+
+static void
+count_hash(struct Client *source_p, dlink_list *table, int length, const char *name)
+{
+       int counts[11];
+       int deepest = 0;
+       int i;
+
+       memset(counts, 0, sizeof(counts));
+       
+       for(i = 0; i < length; i++)
+       {
+               if(dlink_list_length(&table[i]) >= 10)
+                       counts[10]++;
+               else
+                       counts[dlink_list_length(&table[i])]++;
+
+               if(dlink_list_length(&table[i]) > deepest)
+                       deepest = dlink_list_length(&table[i]);
+       }
+
+       output_hash(source_p, name, length, counts, deepest);
+}
+
+void
+hash_stats(struct Client *source_p)
+{
+       count_hash(source_p, channelTable, CH_MAX, "Channel");
+       sendto_one_numeric(source_p, RPL_STATSDEBUG, "B :--");
+       count_hash(source_p, clientTable, U_MAX, "Client");
+       sendto_one_numeric(source_p, RPL_STATSDEBUG, "B :--");
+       count_hash(source_p, idTable, U_MAX, "ID");
+       sendto_one_numeric(source_p, RPL_STATSDEBUG, "B :--");
+       count_hash(source_p, hostTable, HOST_MAX, "Hostname");
+}      
diff --git a/src/hook.c b/src/hook.c
new file mode 100644 (file)
index 0000000..508f2d4
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * ircd-ratbox: an advanced Internet Relay Chat Daemon(ircd).
+ * hook.c - code for dealing with the hook system
+ *
+ * This code is basically a slow leaking array.  Events are simply just a
+ * position in this array.  When hooks are added, events will be created if
+ * they dont exist - this means modules with hooks can be loaded in any
+ * order, and events are preserved through module reloads.
+ *
+ * Copyright (C) 2004-2005 Lee Hardy <lee -at- leeh.co.uk>
+ * Copyright (C) 2004-2005 ircd-ratbox development team
+ *
+ * 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.The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: hook.c 712 2006-02-06 04:42:14Z gxti $
+ */
+#include "stdinc.h"
+#include "memory.h"
+#include "tools.h"
+#include "hook.h"
+#include "irc_string.h"
+
+hook *hooks;
+
+#define HOOK_INCREMENT 1000
+
+int num_hooks = 0;
+int last_hook = 0;
+int max_hooks = HOOK_INCREMENT;
+
+#ifdef USE_IODEBUG_HOOKS
+int h_iosend_id;
+int h_iorecv_id;
+int h_iorecvctrl_id;
+#endif
+int h_burst_client;
+int h_burst_channel;
+int h_burst_finished;
+int h_server_introduced;
+int h_server_eob;
+int h_client_exit;
+int h_new_local_user;
+int h_new_remote_user;
+int h_introduce_client;
+
+void
+init_hook(void)
+{
+       hooks = MyMalloc(sizeof(hook) * HOOK_INCREMENT);
+
+#ifdef USE_IODEBUG_HOOKS
+       h_iosend_id = register_hook("iosend");
+       h_iorecv_id = register_hook("iorecv");
+       h_iorecvctrl_id = register_hook("iorecvctrl");
+#endif
+
+       h_burst_client = register_hook("burst_client");
+       h_burst_channel = register_hook("burst_channel");
+       h_burst_finished = register_hook("burst_finished");
+       h_server_introduced = register_hook("server_introduced");
+       h_server_eob = register_hook("server_eob");
+       h_client_exit = register_hook("client_exit");
+       h_umode_changed = register_hook("umode_changed");
+       h_new_local_user = register_hook("new_local_user");
+       h_new_remote_user = register_hook("new_remote_user");
+       h_introduce_client = register_hook("introduce_client");
+}
+
+/* grow_hooktable()
+ *   Enlarges the hook table by HOOK_INCREMENT
+ */
+static void
+grow_hooktable(void)
+{
+       hook *newhooks;
+
+       newhooks = MyMalloc(sizeof(hook) * (max_hooks + HOOK_INCREMENT));
+       memcpy(newhooks, hooks, sizeof(hook) * num_hooks);
+
+       MyFree(hooks);
+       hooks = newhooks;
+       max_hooks += HOOK_INCREMENT;
+}
+
+/* find_freehookslot()
+ *   Finds the next free slot in the hook table, given by an entry with
+ *   h->name being NULL.
+ */
+static int
+find_freehookslot(void)
+{
+       int i;
+
+       if((num_hooks + 1) > max_hooks)
+               grow_hooktable();
+
+       for(i = 0; i < max_hooks; i++)
+       {
+               if(!hooks[i].name)
+                       return i;
+       }
+
+       /* shouldnt ever get here */
+       return(max_hooks - 1);
+}
+
+/* find_hook()
+ *   Finds an event in the hook table.
+ */
+static int
+find_hook(const char *name)
+{
+       int i;
+
+       for(i = 0; i < max_hooks; i++)
+       {
+               if(!hooks[i].name)
+                       continue;
+
+               if(!irccmp(hooks[i].name, name))
+                       return i;
+       }
+
+       return -1;
+}
+
+/* register_hook()
+ *   Finds an events position in the hook table, creating it if it doesnt
+ *   exist.
+ */
+int
+register_hook(const char *name)
+{
+       int i;
+
+       if((i = find_hook(name)) < 0)
+       {
+               i = find_freehookslot();
+               DupString(hooks[i].name, name);
+               num_hooks++;
+       }
+
+       return i;
+}
+
+/* add_hook()
+ *   Adds a hook to an event in the hook table, creating event first if
+ *   needed.
+ */
+void
+add_hook(const char *name, hookfn fn)
+{
+       int i;
+
+       i = register_hook(name);
+
+       dlinkAddAlloc(fn, &hooks[i].hooks);
+}
+
+/* remove_hook()
+ *   Removes a hook from an event in the hook table.
+ */
+void
+remove_hook(const char *name, hookfn fn)
+{
+       int i;
+
+       if((i = find_hook(name)) < 0)
+               return;
+
+       dlinkFindDestroy(fn, &hooks[i].hooks);
+}
+
+/* call_hook()
+ *   Calls functions from a given event in the hook table.
+ */
+void
+call_hook(int id, void *arg)
+{
+       hookfn fn;
+       dlink_node *ptr;
+
+       /* The ID we were passed is the position in the hook table of this
+        * hook
+        */
+       DLINK_FOREACH(ptr, hooks[id].hooks.head)
+       {
+               fn = ptr->data;
+               fn(arg);
+       }
+}
+
diff --git a/src/hostmask.c b/src/hostmask.c
new file mode 100644 (file)
index 0000000..334be58
--- /dev/null
@@ -0,0 +1,715 @@
+/*
+ *  charybdis: an advanced internet relay chat daemon (ircd).
+ *  hostmask.c: Code to efficiently find IP & hostmask based configs.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development team
+ *  Copyright (C) 2005-2006 charybdis development 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: hostmask.c 2757 2006-11-10 22:58:15Z jilles $
+ */
+
+#include "stdinc.h"
+#include "memory.h"
+#include "ircd_defs.h"
+#include "s_conf.h"
+#include "hostmask.h"
+#include "numeric.h"
+#include "send.h"
+#include "irc_string.h"
+
+#ifdef IPV6
+static unsigned long hash_ipv6(struct sockaddr *, int);
+#endif
+static unsigned long hash_ipv4(struct sockaddr *, int);
+
+
+/* int parse_netmask(const char *, struct irc_sockaddr_storage *, int *);
+ * Input: A hostmask, or an IPV4/6 address.
+ * Output: An integer describing whether it is an IPV4, IPV6 address or a
+ *         hostmask, an address(if it is an IP mask),
+ *         a bitlength(if it is IP mask).
+ * Side effects: None
+ */
+int
+parse_netmask(const char *text, struct sockaddr  *naddr, int *nb)
+{
+       char *ip = LOCAL_COPY(text);
+       char *ptr;
+       struct irc_sockaddr_storage *addr, xaddr;
+       int *b, xb;
+       if(nb == NULL)
+               b = &xb;
+       else
+               b = nb;
+       
+       if(naddr == NULL)
+               addr = (struct irc_sockaddr_storage *)&xaddr;
+       else
+               addr = (struct irc_sockaddr_storage *)naddr;
+       
+#ifdef IPV6
+       if(strchr(ip, ':'))
+       {       
+               if((ptr = strchr(ip, '/')))
+               {
+                       *ptr = '\0';
+                       ptr++;
+                       *b = atoi(ptr);
+                       if(*b > 128)
+                               *b = 128;
+               } else
+                       *b = 128;
+               if(inetpton_sock(ip, (struct sockaddr *)addr) > 0)
+                       return HM_IPV6;
+               else
+                       return HM_HOST;
+       } else
+#endif
+       if(strchr(text, '.'))
+       {
+               if((ptr = strchr(ip, '/')))
+               {
+                       *ptr = '\0';
+                       ptr++;
+                       *b = atoi(ptr);
+                       if(*b > 32)
+                               *b = 32;
+               } else
+                       *b = 32;
+               if(inetpton_sock(ip, (struct sockaddr *)addr) > 0)
+                       return HM_IPV4;
+               else
+                       return HM_HOST;
+       }
+       return HM_HOST;
+}
+
+/* Hashtable stuff...now external as its used in m_stats.c */
+struct AddressRec *atable[ATABLE_SIZE];
+
+void
+init_host_hash(void)
+{
+       memset(&atable, 0, sizeof(atable));
+}
+
+/* unsigned long hash_ipv4(struct irc_sockaddr_storage*)
+ * Input: An IP address.
+ * Output: A hash value of the IP address.
+ * Side effects: None
+ */
+static unsigned long
+hash_ipv4(struct sockaddr *saddr, int bits)
+{
+       struct sockaddr_in *addr = (struct sockaddr_in *) saddr;
+       
+       if(bits != 0)
+       {
+               unsigned long av = ntohl(addr->sin_addr.s_addr) & ~((1 << (32 - bits)) - 1);
+               return (av ^ (av >> 12) ^ (av >> 24)) & (ATABLE_SIZE - 1);
+       }
+
+       return 0;
+}
+
+/* unsigned long hash_ipv6(struct irc_sockaddr_storage*)
+ * Input: An IP address.
+ * Output: A hash value of the IP address.
+ * Side effects: None
+ */
+#ifdef IPV6
+static unsigned long
+hash_ipv6(struct sockaddr *saddr, int bits)
+{
+       struct sockaddr_in6 *addr = (struct sockaddr_in6 *) saddr;
+       unsigned long v = 0, n;
+       for (n = 0; n < 16; n++)
+       {
+               if(bits >= 8)
+               {
+                       v ^= addr->sin6_addr.s6_addr[n];
+                       bits -= 8;
+               }
+               else if(bits)
+               {
+                       v ^= addr->sin6_addr.s6_addr[n] & ~((1 << (8 - bits)) - 1);
+                       return v & (ATABLE_SIZE - 1);
+               }
+               else
+                       return v & (ATABLE_SIZE - 1);
+       }
+       return v & (ATABLE_SIZE - 1);
+}
+#endif
+
+/* int hash_text(const char *start)
+ * Input: The start of the text to hash.
+ * Output: The hash of the string between 1 and (TH_MAX-1)
+ * Side-effects: None.
+ */
+static int
+hash_text(const char *start)
+{
+       const char *p = start;
+       unsigned long h = 0;
+
+       while(*p)
+       {
+               h = (h << 4) - (h + (unsigned char) ToLower(*p++));
+       }
+
+       return (h & (ATABLE_SIZE - 1));
+}
+
+/* unsigned long get_hash_mask(const char *)
+ * Input: The text to hash.
+ * Output: The hash of the string right of the first '.' past the last
+ *         wildcard in the string.
+ * Side-effects: None.
+ */
+static unsigned long
+get_mask_hash(const char *text)
+{
+       const char *hp = "", *p;
+
+       for (p = text + strlen(text) - 1; p >= text; p--)
+               if(*p == '*' || *p == '?')
+                       return hash_text(hp);
+               else if(*p == '.')
+                       hp = p + 1;
+       return hash_text(text);
+}
+
+/* struct ConfItem* find_conf_by_address(const char*, struct irc_sockaddr_storage*,
+ *         int type, int fam, const char *username)
+ * Input: The hostname, the address, the type of mask to find, the address
+ *        family, the username.
+ * Output: The matching value with the highest precedence.
+ * Side-effects: None
+ * Note: Setting bit 0 of the type means that the username is ignored.
+ */
+struct ConfItem *
+find_conf_by_address(const char *name, const char *sockhost,
+                       const char *orighost,
+                       struct sockaddr *addr, int type, int fam, 
+                       const char *username)
+{
+       unsigned long hprecv = 0;
+       struct ConfItem *hprec = NULL;
+       struct AddressRec *arec;
+       int b;
+
+       if(username == NULL)
+               username = "";
+
+       if(addr)
+       {
+               /* Check for IPV6 matches... */
+#ifdef IPV6
+               if(fam == AF_INET6)
+               {
+
+                       for (b = 128; b >= 0; b -= 16)
+                       {
+                               for (arec = atable[hash_ipv6(addr, b)]; arec; arec = arec->next)
+                                       if(arec->type == (type & ~0x1) &&
+                                          arec->masktype == HM_IPV6 &&
+                                          comp_with_mask_sock(addr, (struct sockaddr *)&arec->Mask.ipa.addr,
+                                                              arec->Mask.ipa.bits) && (type & 0x1
+                                                                                       ||
+                                                                                       match(arec->
+                                                                                             username,
+                                                                                             username))
+                                          && arec->precedence > hprecv)
+                                       {
+                                               hprecv = arec->precedence;
+                                               hprec = arec->aconf;
+                                       }
+                       }
+               }
+               else
+#endif
+               if(fam == AF_INET)
+               {
+                       for (b = 32; b >= 0; b -= 8)
+                       {
+                               for (arec = atable[hash_ipv4(addr, b)]; arec; arec = arec->next)
+                                       if(arec->type == (type & ~0x1) &&
+                                          arec->masktype == HM_IPV4 &&
+                                          arec->precedence > hprecv && 
+                                          comp_with_mask_sock(addr, (struct sockaddr *)&arec->Mask.ipa.addr,
+                                                              arec->Mask.ipa.bits) && 
+                                          (type & 0x1 || match(arec->username, username)))
+                                       {
+                                               hprecv = arec->precedence;
+                                               hprec = arec->aconf;
+                                       }
+                       }
+               }
+       }
+
+       if(orighost != NULL)
+       {
+               const char *p;
+
+               for (p = orighost; p != NULL;)
+               {
+                       for (arec = atable[hash_text(p)]; arec; arec = arec->next)
+                               
+                               if((arec->type == (type & ~0x1)) &&
+                                  (arec->masktype == HM_HOST) &&
+                                  arec->precedence > hprecv &&
+                                  match(arec->Mask.hostname, orighost) &&
+                                  (type & 0x1 || match(arec->username, username)))
+                               {
+                                       hprecv = arec->precedence;
+                                       hprec = arec->aconf;
+                               }
+                       p = strchr(p, '.');
+                       if(p != NULL)
+                               p++;
+                       else
+                               break;
+               }
+               for (arec = atable[0]; arec; arec = arec->next)
+               {
+                       if(arec->type == (type & ~0x1) &&
+                          arec->masktype == HM_HOST &&
+                          arec->precedence > hprecv && 
+                          (match(arec->Mask.hostname, orighost) ||
+                           (sockhost && match(arec->Mask.hostname, sockhost))) &&
+                          (type & 0x1 || match(arec->username, username)))
+                       {
+                               hprecv = arec->precedence;
+                               hprec = arec->aconf;
+                       }
+               }
+       }
+
+       if(name != NULL)
+       {
+               const char *p;
+               /* And yes - we have to check p after strchr and p after increment for
+                * NULL -kre */
+               for (p = name; p != NULL;)
+               {
+                       for (arec = atable[hash_text(p)]; arec; arec = arec->next)
+                               if((arec->type == (type & ~0x1)) &&
+                                  (arec->masktype == HM_HOST) &&
+                                  arec->precedence > hprecv &&
+                                  match(arec->Mask.hostname, name) &&
+                                  (type & 0x1 || match(arec->username, username)))
+                               {
+                                       hprecv = arec->precedence;
+                                       hprec = arec->aconf;
+                               }
+                       p = strchr(p, '.');
+                       if(p != NULL)
+                               p++;
+                       else
+                               break;
+               }
+               for (arec = atable[0]; arec; arec = arec->next)
+               {
+                       if(arec->type == (type & ~0x1) &&
+                          arec->masktype == HM_HOST &&
+                          arec->precedence > hprecv && 
+                          (match(arec->Mask.hostname, name) ||
+                           (sockhost && match(arec->Mask.hostname, sockhost))) &&
+                          (type & 0x1 || match(arec->username, username)))
+                       {
+                               hprecv = arec->precedence;
+                               hprec = arec->aconf;
+                       }
+               }
+       }
+       return hprec;
+}
+
+/* struct ConfItem* find_address_conf(const char*, const char*,
+ *                                    struct irc_sockaddr_storage*, int);
+ * Input: The hostname, username, address, address family.
+ * Output: The applicable ConfItem.
+ * Side-effects: None
+ */
+struct ConfItem *
+find_address_conf(const char *host, const char *sockhost, const char *user, 
+               const char *notildeuser, struct sockaddr *ip, int aftype)
+{
+       struct ConfItem *iconf, *kconf;
+       const char *vuser;
+
+       /* Find the best I-line... If none, return NULL -A1kmm */
+       if(!(iconf = find_conf_by_address(host, sockhost, NULL, ip, CONF_CLIENT, aftype, user)))
+               return NULL;
+       /* Find what their visible username will be.
+        * Note that the username without tilde may contain one char more.
+        * -- jilles */
+       vuser = IsNoTilde(iconf) ? notildeuser : user;
+
+       /* If they are exempt from K-lines, return the best I-line. -A1kmm */
+       if(IsConfExemptKline(iconf))
+               return iconf;
+
+       /* Find the best K-line... -A1kmm */
+       kconf = find_conf_by_address(host, sockhost, NULL, ip, CONF_KILL, aftype, user);
+
+       /* If they are K-lined, return the K-line */
+       if(kconf)
+               return kconf;
+
+       /* if theres a spoof, check it against klines.. */
+       if(IsConfDoSpoofIp(iconf))
+       {
+               char *p = strchr(iconf->name, '@');
+
+               /* note, we dont need to pass sockhost here, as its
+                * guaranteed to not match by whats above.. --anfl
+                */
+               if(p)
+               {
+                       *p = '\0';
+                       kconf = find_conf_by_address(p+1, NULL, NULL, ip, CONF_KILL, aftype, iconf->name);
+                       *p = '@';
+               }
+               else
+                       kconf = find_conf_by_address(iconf->name, NULL, NULL, ip, CONF_KILL, aftype, vuser);
+
+               if(kconf)
+                       return kconf;
+       }
+
+       /* if no_tilde, check the username without tilde against klines too
+        * -- jilles */
+       if(user != vuser)
+       {
+               kconf = find_conf_by_address(host, sockhost, NULL, ip, CONF_KILL, aftype, vuser);
+               if(kconf)
+                       return kconf;
+       }
+
+       /* hunt for a gline */
+       if(ConfigFileEntry.glines)
+       {
+               kconf = find_conf_by_address(host, sockhost, NULL, ip, CONF_GLINE, aftype, user);
+
+               if((kconf != NULL) && !IsConfExemptGline(iconf))
+                       return kconf;
+       }
+
+       return iconf;
+}
+
+/* struct ConfItem* find_dline(struct irc_sockaddr_storage*, int)
+ * Input: An address, an address family.
+ * Output: The best matching D-line or exempt line.
+ * Side effects: None.
+ */
+struct ConfItem *
+find_dline(struct sockaddr *addr, int aftype)
+{
+       struct ConfItem *eline;
+       eline = find_conf_by_address(NULL, NULL, NULL, addr, CONF_EXEMPTDLINE | 1, aftype, NULL);
+       if(eline)
+               return eline;
+       return find_conf_by_address(NULL, NULL, NULL, addr, CONF_DLINE | 1, aftype, NULL);
+}
+
+/* void add_conf_by_address(const char*, int, const char *,
+ *         struct ConfItem *aconf)
+ * Input: 
+ * Output: None
+ * Side-effects: Adds this entry to the hash table.
+ */
+void
+add_conf_by_address(const char *address, int type, const char *username, struct ConfItem *aconf)
+{
+       static unsigned long prec_value = 0xFFFFFFFF;
+       int masktype, bits;
+       unsigned long hv;
+       struct AddressRec *arec;
+
+       if(address == NULL)
+               address = "/NOMATCH!/";
+       arec = MyMalloc(sizeof(struct AddressRec));
+       masktype = parse_netmask(address, (struct sockaddr *)&arec->Mask.ipa.addr, &bits);
+       arec->Mask.ipa.bits = bits;
+       arec->masktype = masktype;
+#ifdef IPV6
+       if(masktype == HM_IPV6)
+       {
+               /* We have to do this, since we do not re-hash for every bit -A1kmm. */
+               bits -= bits % 16;
+               arec->next = atable[(hv = hash_ipv6((struct sockaddr *)&arec->Mask.ipa.addr, bits))];
+               atable[hv] = arec;
+       }
+       else
+#endif
+       if(masktype == HM_IPV4)
+       {
+               /* We have to do this, since we do not re-hash for every bit -A1kmm. */
+               bits -= bits % 8;
+               arec->next = atable[(hv = hash_ipv4((struct sockaddr *)&arec->Mask.ipa.addr, bits))];
+               atable[hv] = arec;
+       }
+       else
+       {
+               arec->Mask.hostname = address;
+               arec->next = atable[(hv = get_mask_hash(address))];
+               atable[hv] = arec;
+       }
+       arec->username = username;
+       arec->aconf = aconf;
+       arec->precedence = prec_value--;
+       arec->type = type;
+}
+
+/* void delete_one_address(const char*, struct ConfItem*)
+ * Input: An address string, the associated ConfItem.
+ * Output: None
+ * Side effects: Deletes an address record. Frees the ConfItem if there
+ *               is nothing referencing it, sets it as illegal otherwise.
+ */
+void
+delete_one_address_conf(const char *address, struct ConfItem *aconf)
+{
+       int masktype, bits;
+       unsigned long hv;
+       struct AddressRec *arec, *arecl = NULL;
+       struct irc_sockaddr_storage addr;
+       masktype = parse_netmask(address, (struct sockaddr *)&addr, &bits);
+#ifdef IPV6
+       if(masktype == HM_IPV6)
+       {
+               /* We have to do this, since we do not re-hash for every bit -A1kmm. */
+               bits -= bits % 16;
+               hv = hash_ipv6((struct sockaddr *)&addr, bits);
+       }
+       else
+#endif
+       if(masktype == HM_IPV4)
+       {
+               /* We have to do this, since we do not re-hash for every bit -A1kmm. */
+               bits -= bits % 8;
+               hv = hash_ipv4((struct sockaddr *)&addr, bits);
+       }
+       else
+               hv = get_mask_hash(address);
+       for (arec = atable[hv]; arec; arec = arec->next)
+       {
+               if(arec->aconf == aconf)
+               {
+                       if(arecl)
+                               arecl->next = arec->next;
+                       else
+                               atable[hv] = arec->next;
+                       aconf->status |= CONF_ILLEGAL;
+                       if(!aconf->clients)
+                               free_conf(aconf);
+                       MyFree(arec);
+                       return;
+               }
+               arecl = arec;
+       }
+}
+
+/* void clear_out_address_conf(void)
+ * Input: None
+ * Output: None
+ * Side effects: Clears out all address records in the hash table,
+ *               frees them, and frees the ConfItems if nothing references
+ *               them, otherwise sets them as illegal.
+ */
+void
+clear_out_address_conf(void)
+{
+       int i;
+       struct AddressRec **store_next;
+       struct AddressRec *arec, *arecn;
+
+       for (i = 0; i < ATABLE_SIZE; i++)
+       {
+               store_next = &atable[i];
+               for (arec = atable[i]; arec; arec = arecn)
+               {
+                       arecn = arec->next;
+                       /* We keep the temporary K-lines and destroy the
+                        * permanent ones, just to be confusing :) -A1kmm */
+                       if(arec->aconf->flags & CONF_FLAGS_TEMPORARY ||
+                          (arec->type != CONF_CLIENT && arec->type != CONF_EXEMPTDLINE))
+                       {
+                               *store_next = arec;
+                               store_next = &arec->next;
+                       }
+                       else
+                       {
+                               arec->aconf->status |= CONF_ILLEGAL;
+                               if(!arec->aconf->clients)
+                                       free_conf(arec->aconf);
+                               MyFree(arec);
+                       }
+               }
+               *store_next = NULL;
+       }
+}
+
+void
+clear_out_address_conf_bans(void)
+{
+       int i;
+       struct AddressRec **store_next;
+       struct AddressRec *arec, *arecn;
+
+       for (i = 0; i < ATABLE_SIZE; i++)
+       {
+               store_next = &atable[i];
+               for (arec = atable[i]; arec; arec = arecn)
+               {
+                       arecn = arec->next;
+                       /* We keep the temporary K-lines and destroy the
+                        * permanent ones, just to be confusing :) -A1kmm */
+                       if(arec->aconf->flags & CONF_FLAGS_TEMPORARY ||
+                          (arec->type == CONF_CLIENT || arec->type == CONF_EXEMPTDLINE))
+                       {
+                               *store_next = arec;
+                               store_next = &arec->next;
+                       }
+                       else
+                       {
+                               arec->aconf->status |= CONF_ILLEGAL;
+                               if(!arec->aconf->clients)
+                                       free_conf(arec->aconf);
+                               MyFree(arec);
+                       }
+               }
+               *store_next = NULL;
+       }
+}
+
+
+/*
+ * show_iline_prefix()
+ *
+ * inputs       - pointer to struct Client requesting output
+ *              - pointer to struct ConfItem 
+ *              - name to which iline prefix will be prefixed to
+ * output       - pointer to static string with prefixes listed in ascii form
+ * side effects - NONE
+ */
+char *
+show_iline_prefix(struct Client *sptr, struct ConfItem *aconf, char *name)
+{
+       static char prefix_of_host[USERLEN + 15];
+       char *prefix_ptr;
+
+       prefix_ptr = prefix_of_host;
+       if(IsNoTilde(aconf))
+               *prefix_ptr++ = '-';
+       if(IsLimitIp(aconf))
+               *prefix_ptr++ = '!';
+       if(IsNeedIdentd(aconf))
+               *prefix_ptr++ = '+';
+       if(IsPassIdentd(aconf))
+               *prefix_ptr++ = '$';
+       if(IsNoMatchIp(aconf))
+               *prefix_ptr++ = '%';
+       if(IsConfDoSpoofIp(aconf))
+               *prefix_ptr++ = '=';
+       if(MyOper(sptr) && IsConfExemptKline(aconf))
+               *prefix_ptr++ = '^';
+       if(MyOper(sptr) && IsConfExemptLimits(aconf))
+               *prefix_ptr++ = '>';
+       if(MyOper(sptr) && IsConfIdlelined(aconf))
+               *prefix_ptr++ = '<';
+       *prefix_ptr = '\0';
+       strncpy(prefix_ptr, name, USERLEN);
+       return (prefix_of_host);
+}
+
+/* report_auth()
+ *
+ * Inputs: pointer to client to report to
+ * Output: None
+ * Side effects: Reports configured auth{} blocks to client_p
+ */
+void
+report_auth(struct Client *client_p)
+{
+       char *name, *host, *pass, *user, *classname;
+       struct AddressRec *arec;
+       struct ConfItem *aconf;
+       int i, port;
+
+       for (i = 0; i < ATABLE_SIZE; i++)
+               for (arec = atable[i]; arec; arec = arec->next)
+                       if(arec->type == CONF_CLIENT)
+                       {
+                               aconf = arec->aconf;
+
+                               if(!MyOper(client_p) && IsConfDoSpoofIp(aconf))
+                                       continue;
+
+                               get_printable_conf(aconf, &name, &host, &pass, &user, &port,
+                                                  &classname);
+
+                               sendto_one_numeric(client_p, RPL_STATSILINE, 
+                                                  form_str(RPL_STATSILINE),
+                                                  name, show_iline_prefix(client_p, aconf, user),
+                                                  show_ip_conf(aconf, client_p) ? host : "255.255.255.255",
+                                                  port, classname);
+                       }
+}
+
+/* report_Klines()
+ * 
+ * inputs       - Client to report to, mask 
+ * outputs      -
+ * side effects - Reports configured K-lines to client_p.
+ */
+void
+report_Klines(struct Client *source_p)
+{
+       char *host, *pass, *user, *oper_reason;
+       struct AddressRec *arec;
+       struct ConfItem *aconf = NULL;
+       int i;
+
+       for (i = 0; i < ATABLE_SIZE; i++)
+       {
+               for (arec = atable[i]; arec; arec = arec->next)
+               {
+                       if(arec->type == CONF_KILL)
+                       {
+                               aconf = arec->aconf;
+
+                               /* its a tempkline, theyre reported elsewhere */
+                               if(aconf->flags & CONF_FLAGS_TEMPORARY)
+                                       continue;
+
+                               get_printable_kline(source_p, aconf, &host, &pass, &user, &oper_reason);
+                               sendto_one_numeric(source_p, RPL_STATSKLINE,
+                                                  form_str(RPL_STATSKLINE),
+                                                  'K', host, user, pass,
+                                                  oper_reason ? "|" : "",
+                                                  oper_reason ? oper_reason : "");
+                       }
+               }
+       }
+}
diff --git a/src/irc_string.c b/src/irc_string.c
new file mode 100644 (file)
index 0000000..26dbfca
--- /dev/null
@@ -0,0 +1,962 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  irc_string.c: IRC string functions.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: irc_string.c 678 2006-02-03 20:25:01Z jilles $
+ */
+
+#include "stdinc.h"
+#include "sprintf_irc.h"
+#include "tools.h"
+#include "irc_string.h"
+#include "client.h"
+#include "memory.h"
+#include "setup.h"
+
+#ifndef INADDRSZ
+#define INADDRSZ 4
+#endif
+
+#ifdef IPV6
+#ifndef IN6ADDRSZ
+#define IN6ADDRSZ 16
+#endif
+#endif
+
+#ifndef INT16SZ
+#define INT16SZ 2
+#endif
+/*
+ * myctime - This is like standard ctime()-function, but it zaps away
+ *   the newline from the end of that string. Also, it takes
+ *   the time value as parameter, instead of pointer to it.
+ *   Note that it is necessary to copy the string to alternate
+ *   buffer (who knows how ctime() implements it, maybe it statically
+ *   has newline there and never 'refreshes' it -- zapping that
+ *   might break things in other places...)
+ *
+ *
+ * Thu Nov 24 18:22:48 1986 
+ */
+const char *
+myctime(time_t value)
+{
+       static char buf[32];
+       char *p;
+
+       strcpy(buf, ctime(&value));
+       if((p = strchr(buf, '\n')) != NULL)
+               *p = '\0';
+       return buf;
+}
+
+
+/*
+ * clean_string - clean up a string possibly containing garbage
+ *
+ * *sigh* Before the kiddies find this new and exciting way of 
+ * annoying opers, lets clean up what is sent to local opers
+ * -Dianora
+ */
+char *
+clean_string(char *dest, const unsigned char *src, size_t len)
+{
+       char *d = dest;
+       s_assert(0 != dest);
+       s_assert(0 != src);
+
+       if(dest == NULL || src == NULL)
+               return NULL;
+
+       len -= 3;               /* allow for worst case, '^A\0' */
+
+       while(*src && (len > 0))
+       {
+               if(*src & 0x80) /* if high bit is set */
+               {
+                       *d++ = '.';
+                       --len;
+               }
+               else if(!IsPrint(*src)) /* if NOT printable */
+               {
+                       *d++ = '^';
+                       --len;
+                       *d++ = 0x40 + *src;     /* turn it into a printable */
+               }
+               else
+                       *d++ = *src;
+               ++src;
+               --len;
+       }
+       *d = '\0';
+       return dest;
+}
+
+/*
+ * strip_tabs(dst, src, length)
+ *
+ *   Copies src to dst, while converting all \t (tabs) into spaces.
+ *
+ * NOTE: jdc: I have a gut feeling there's a faster way to do this.
+ */
+char *
+strip_tabs(char *dest, const unsigned char *src, size_t len)
+{
+       char *d = dest;
+       /* Sanity check; we don't want anything nasty... */
+       s_assert(0 != dest);
+       s_assert(0 != src);
+
+       if(dest == NULL || src == NULL)
+               return NULL;
+
+       while(*src && (len > 0))
+       {
+               if(*src == '\t')
+               {
+                       *d++ = ' ';     /* Translate the tab into a space */
+               }
+               else
+               {
+                       *d++ = *src;    /* Copy src to dst */
+               }
+               ++src;
+               --len;
+       }
+       *d = '\0';              /* Null terminate, thanks and goodbye */
+       return dest;
+}
+
+/*
+ * strtoken - walk through a string of tokens, using a set of separators
+ *   argv 9/90
+ *
+ */
+char *
+strtoken(char **save, char *str, const 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;
+}
+
+static const char base64_table[] =
+       { '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', '+', '/', '\0'
+       };
+
+static const char base64_pad = '=';
+
+static const short base64_reverse_table[256] = {
+       -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, 62, -1, -1, -1, 63,
+       52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
+       -1,  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, -1, -1, -1, -1, -1,
+       -1, 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, -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
+};
+
+unsigned char *
+ircd_base64_encode(const unsigned char *str, int length)
+{
+       const unsigned char *current = str;
+       unsigned char *p;
+       unsigned char *result;
+
+       if ((length + 2) < 0 || ((length + 2) / 3) >= (1 << (sizeof(int) * 8 - 2))) {
+               return NULL;
+       }
+
+       result = MyMalloc(((length + 2) / 3) * 5);
+       p = result;
+
+       while (length > 2) 
+       { 
+               *p++ = base64_table[current[0] >> 2];
+               *p++ = base64_table[((current[0] & 0x03) << 4) + (current[1] >> 4)];
+               *p++ = base64_table[((current[1] & 0x0f) << 2) + (current[2] >> 6)];
+               *p++ = base64_table[current[2] & 0x3f];
+
+               current += 3;
+               length -= 3; 
+       }
+
+       if (length != 0) {
+               *p++ = base64_table[current[0] >> 2];
+               if (length > 1) {
+                       *p++ = base64_table[((current[0] & 0x03) << 4) + (current[1] >> 4)];
+                       *p++ = base64_table[(current[1] & 0x0f) << 2];
+                       *p++ = base64_pad;
+               } else {
+                       *p++ = base64_table[(current[0] & 0x03) << 4];
+                       *p++ = base64_pad;
+                       *p++ = base64_pad;
+               }
+       }
+       *p = '\0';
+       return result;
+}
+
+unsigned char *
+ircd_base64_decode(const unsigned char *str, int length, int *ret)
+{
+       const unsigned char *current = str;
+       int ch, i = 0, j = 0, k;
+       unsigned char *result;
+       
+       result = MyMalloc(length + 1);
+
+       while ((ch = *current++) != '\0' && length-- > 0) {
+               if (ch == base64_pad) break;
+
+               ch = base64_reverse_table[ch];
+               if (ch < 0) continue;
+
+               switch(i % 4) {
+               case 0:
+                       result[j] = ch << 2;
+                       break;
+               case 1:
+                       result[j++] |= ch >> 4;
+                       result[j] = (ch & 0x0f) << 4;
+                       break;
+               case 2:
+                       result[j++] |= ch >>2;
+                       result[j] = (ch & 0x03) << 6;
+                       break;
+               case 3:
+                       result[j++] |= ch;
+                       break;
+               }
+               i++;
+       }
+
+       k = j;
+
+       if (ch == base64_pad) {
+               switch(i % 4) {
+               case 1:
+                       free(result);
+                       return NULL;
+               case 2:
+                       k++;
+               case 3:
+                       result[k++] = 0;
+               }
+       }
+       result[j] = '\0';
+
+       if(ret)
+               *ret = j;
+
+       return result;
+}
+
+/* 
+ * From: Thomas Helvey <tomh@inxpress.net>
+ */
+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"
+};
+
+/*
+ * inetntoa - in_addr to string
+ *      changed name to remove collision possibility and
+ *      so behaviour is guaranteed to take a pointer arg.
+ *      -avalon 23/11/92
+ *  inet_ntoa --  returned the dotted notation of a given
+ *      internet number
+ *      argv 11/90).
+ *  inet_ntoa --  its broken on some Ultrix/Dynix too. -avalon
+ */
+
+const char *
+inetntoa(const char *in)
+{
+       static char buf[16];
+       char *bufptr = buf;
+       const unsigned char *a = (const unsigned char *) in;
+       const char *n;
+
+       n = IpQuadTab[*a++];
+       while(*n)
+               *bufptr++ = *n++;
+       *bufptr++ = '.';
+       n = IpQuadTab[*a++];
+       while(*n)
+               *bufptr++ = *n++;
+       *bufptr++ = '.';
+       n = IpQuadTab[*a++];
+       while(*n)
+               *bufptr++ = *n++;
+       *bufptr++ = '.';
+       n = IpQuadTab[*a];
+       while(*n)
+               *bufptr++ = *n++;
+       *bufptr = '\0';
+       return buf;
+}
+
+/*
+ * 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.
+ */
+
+#define SPRINTF(x) ((size_t)ircsprintf x)
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static const char *inet_ntop4(const u_char * src, char *dst, unsigned int size);
+#ifdef IPV6
+static const char *inet_ntop6(const u_char * src, char *dst, unsigned int size);
+#endif
+
+/* const char *
+ * inet_ntop4(src, dst, size)
+ *     format an IPv4 address
+ * return:
+ *     `dst' (as a const)
+ * notes:
+ *     (1) uses no statics
+ *     (2) takes a u_char* not an in_addr as input
+ * author:
+ *     Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop4(const unsigned char *src, char *dst, unsigned int size)
+{
+       if(size < 16)
+               return NULL;
+       return strcpy(dst, inetntoa((const char *) src));
+}
+
+/* const char *
+ * inet_ntop6(src, dst, size)
+ *     convert IPv6 binary address into presentation (printable) format
+ * author:
+ *     Paul Vixie, 1996.
+ */
+#ifdef IPV6
+static const char *
+inet_ntop6(const unsigned char *src, char *dst, unsigned int size)
+{
+       /*
+        * Note that int32_t and int16_t need only be "at least" large enough
+        * to contain a value of the specified size.  On some systems, like
+        * Crays, there is no such thing as an integer variable with 16 bits.
+        * Keep this in mind if you think this function should have been coded
+        * to use pointer overlays.  All the world's not a VAX.
+        */
+       char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
+       struct
+       {
+               int base, len;
+       }
+       best, cur;
+       u_int words[IN6ADDRSZ / INT16SZ];
+       int i;
+
+       /*
+        * Preprocess:
+        *      Copy the input (bytewise) array into a wordwise array.
+        *      Find the longest run of 0x00's in src[] for :: shorthanding.
+        */
+       memset(words, '\0', sizeof words);
+       for(i = 0; i < IN6ADDRSZ; i += 2)
+               words[i / 2] = (src[i] << 8) | src[i + 1];
+       best.base = -1;
+       cur.base = -1;
+       for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
+       {
+               if(words[i] == 0)
+               {
+                       if(cur.base == -1)
+                               cur.base = i, cur.len = 1;
+                       else
+                               cur.len++;
+               }
+               else
+               {
+                       if(cur.base != -1)
+                       {
+                               if(best.base == -1 || cur.len > best.len)
+                                       best = cur;
+                               cur.base = -1;
+                       }
+               }
+       }
+       if(cur.base != -1)
+       {
+               if(best.base == -1 || cur.len > best.len)
+                       best = cur;
+       }
+       if(best.base != -1 && best.len < 2)
+               best.base = -1;
+
+       /*
+        * Format the result.
+        */
+       tp = tmp;
+       for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
+       {
+               /* Are we inside the best run of 0x00's? */
+               if(best.base != -1 && i >= best.base && i < (best.base + best.len))
+               {
+                       if(i == best.base)
+                       {
+                               if(i == 0)
+                                       *tp++ = '0';
+                               *tp++ = ':';
+                       }
+                       continue;
+               }
+               /* Are we following an initial run of 0x00s or any real hex? */
+               if(i != 0)
+                       *tp++ = ':';
+               /* Is this address an encapsulated IPv4? */
+               if(i == 6 && best.base == 0 &&
+                  (best.len == 6 || (best.len == 5 && words[5] == 0xffff)))
+               {
+                       if(!inet_ntop4(src + 12, tp, sizeof tmp - (tp - tmp)))
+                               return (NULL);
+                       tp += strlen(tp);
+                       break;
+               }
+               tp += SPRINTF((tp, "%x", words[i]));
+       }
+       /* Was it a trailing run of 0x00's? */
+       if(best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
+               *tp++ = ':';
+       *tp++ = '\0';
+
+       /*
+        * Check for overflow, copy, and we're done.
+        */
+
+       if((unsigned int) (tp - tmp) > size)
+       {
+               return (NULL);
+       }
+       return strcpy(dst, tmp);
+}
+#endif
+
+int
+inetpton_sock(const char *src, struct sockaddr *dst)
+{
+       if(inetpton(AF_INET, src, &((struct sockaddr_in *) dst)->sin_addr))
+       {
+               ((struct sockaddr_in *) dst)->sin_port = 0;
+               ((struct sockaddr_in *) dst)->sin_family = AF_INET;
+               SET_SS_LEN(*((struct irc_sockaddr_storage *) dst), sizeof(struct sockaddr_in));
+               return 1;
+       }
+#ifdef IPV6
+       else if(inetpton(AF_INET6, src, &((struct sockaddr_in6 *) dst)->sin6_addr))
+       {
+               ((struct sockaddr_in6 *) dst)->sin6_port = 0;
+               ((struct sockaddr_in6 *) dst)->sin6_family = AF_INET6;
+               SET_SS_LEN(*((struct irc_sockaddr_storage *) dst), sizeof(struct sockaddr_in6));
+               return 1;
+       }
+#endif
+       return 0;
+}
+
+const char *
+inetntop_sock(struct sockaddr *src, char *dst, unsigned int size)
+{
+       switch (src->sa_family)
+       {
+       case AF_INET:
+               return (inetntop(AF_INET, &((struct sockaddr_in *) src)->sin_addr, dst, size));
+               break;
+#ifdef IPV6
+       case AF_INET6:
+               return (inetntop(AF_INET6, &((struct sockaddr_in6 *) src)->sin6_addr, dst, size));
+               break;
+#endif
+       default:
+               return NULL;
+               break;
+       }
+}
+
+/* char *
+ * inetntop(af, src, dst, size)
+ *     convert a network format address to presentation format.
+ * return:
+ *     pointer to presentation format address (`dst'), or NULL (see errno).
+ * author:
+ *     Paul Vixie, 1996.
+ */
+const char *
+inetntop(int af, const void *src, char *dst, unsigned int size)
+{
+       switch (af)
+       {
+       case AF_INET:
+               return (inet_ntop4(src, dst, size));
+#ifdef IPV6
+       case AF_INET6:
+               if(IN6_IS_ADDR_V4MAPPED((const struct in6_addr *) src) ||
+                  IN6_IS_ADDR_V4COMPAT((const struct in6_addr *) src))
+                       return (inet_ntop4
+                               ((const unsigned char *)
+                                &((const struct in6_addr *) src)->s6_addr[12], dst, size));
+               else
+                       return (inet_ntop6(src, dst, size));
+
+
+#endif
+       default:
+               return (NULL);
+       }
+       /* NOTREACHED */
+}
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+/* int
+ * inetpton(af, src, dst)
+ *     convert from presentation format (which usually means ASCII printable)
+ *     to network format (which is usually some kind of binary format).
+ * return:
+ *     1 if the address was valid for the specified address family
+ *     0 if the address wasn't valid (`dst' is untouched in this case)
+ *     -1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ *     Paul Vixie, 1996.
+ */
+
+/* int
+ * inet_pton4(src, dst)
+ *     like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ *     1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ *     does not touch `dst' unless it's returning 1.
+ * author:
+ *     Paul Vixie, 1996.
+ */
+static int
+inet_pton4(src, dst)
+     const char *src;
+     u_char *dst;
+{
+       int saw_digit, octets, ch;
+       u_char tmp[INADDRSZ], *tp;
+
+       saw_digit = 0;
+       octets = 0;
+       *(tp = tmp) = 0;
+       while((ch = *src++) != '\0')
+       {
+
+               if(ch >= '0' && ch <= '9')
+               {
+                       u_int new = *tp * 10 + (ch - '0');
+
+                       if(new > 255)
+                               return (0);
+                       *tp = new;
+                       if(!saw_digit)
+                       {
+                               if(++octets > 4)
+                                       return (0);
+                               saw_digit = 1;
+                       }
+               }
+               else if(ch == '.' && saw_digit)
+               {
+                       if(octets == 4)
+                               return (0);
+                       *++tp = 0;
+                       saw_digit = 0;
+               }
+               else
+                       return (0);
+       }
+       if(octets < 4)
+               return (0);
+       memcpy(dst, tmp, INADDRSZ);
+       return (1);
+}
+
+#ifdef IPV6
+/* int
+ * inet_pton6(src, dst)
+ *     convert presentation level address to network order binary form.
+ * return:
+ *     1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ *     (1) does not touch `dst' unless it's returning 1.
+ *     (2) :: in a full address is silently ignored.
+ * credit:
+ *     inspired by Mark Andrews.
+ * author:
+ *     Paul Vixie, 1996.
+ */
+
+static int
+inet_pton6(src, dst)
+     const char *src;
+     u_char *dst;
+{
+       static const char xdigits[] = "0123456789abcdef";
+       u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
+       const char *curtok;
+       int ch, saw_xdigit;
+       u_int val;
+
+       tp = memset(tmp, '\0', IN6ADDRSZ);
+       endp = tp + IN6ADDRSZ;
+       colonp = NULL;
+       /* Leading :: requires some special handling. */
+       if(*src == ':')
+               if(*++src != ':')
+                       return (0);
+       curtok = src;
+       saw_xdigit = 0;
+       val = 0;
+       while((ch = tolower(*src++)) != '\0')
+       {
+               const char *pch;
+
+               pch = strchr(xdigits, ch);
+               if(pch != NULL)
+               {
+                       val <<= 4;
+                       val |= (pch - xdigits);
+                       if(val > 0xffff)
+                               return (0);
+                       saw_xdigit = 1;
+                       continue;
+               }
+               if(ch == ':')
+               {
+                       curtok = src;
+                       if(!saw_xdigit)
+                       {
+                               if(colonp)
+                                       return (0);
+                               colonp = tp;
+                               continue;
+                       }
+                       else if(*src == '\0')
+                       {
+                               return (0);
+                       }
+                       if(tp + INT16SZ > endp)
+                               return (0);
+                       *tp++ = (u_char) (val >> 8) & 0xff;
+                       *tp++ = (u_char) val & 0xff;
+                       saw_xdigit = 0;
+                       val = 0;
+                       continue;
+               }
+               if(*src != '\0' && ch == '.')
+               {
+                       if(((tp + INADDRSZ) <= endp) && inet_pton4(curtok, tp) > 0)
+                       {
+                               tp += INADDRSZ;
+                               saw_xdigit = 0;
+                               break;  /* '\0' was seen by inet_pton4(). */
+                       }
+               }
+               else
+                       continue;
+               return (0);
+       }
+       if(saw_xdigit)
+       {
+               if(tp + INT16SZ > endp)
+                       return (0);
+               *tp++ = (u_char) (val >> 8) & 0xff;
+               *tp++ = (u_char) val & 0xff;
+       }
+       if(colonp != NULL)
+       {
+               /*
+                * Since some memmove()'s erroneously fail to handle
+                * overlapping regions, we'll do the shift by hand.
+                */
+               const int n = tp - colonp;
+               int i;
+
+               if(tp == endp)
+                       return (0);
+               for(i = 1; i <= n; i++)
+               {
+                       endp[-i] = colonp[n - i];
+                       colonp[n - i] = 0;
+               }
+               tp = endp;
+       }
+       if(tp != endp)
+               return (0);
+       memcpy(dst, tmp, IN6ADDRSZ);
+       return (1);
+}
+#endif
+int
+inetpton(af, src, dst)
+     int af;
+     const char *src;
+     void *dst;
+{
+       switch (af)
+       {
+       case AF_INET:
+               return (inet_pton4(src, dst));
+#ifdef IPV6
+       case AF_INET6:
+               /* Somebody might have passed as an IPv4 address this is sick but it works */
+               if(inet_pton4(src, dst))
+               {
+                       char tmp[HOSTIPLEN];
+                       ircsprintf(tmp, "::ffff:%s", src);
+                       return (inet_pton6(tmp, dst));
+               }
+               else
+                       return (inet_pton6(src, dst));
+#endif
+       default:
+               return (-1);
+       }
+       /* NOTREACHED */
+}
+
+/*
+ * strlcat and strlcpy were ripped from openssh 2.5.1p2
+ * They had the following Copyright info: 
+ *
+ *
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED `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 AUTHOR 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.
+ */
+
+
+
+#ifndef HAVE_STRLCAT
+size_t
+strlcat(char *dst, const char *src, size_t siz)
+{
+       char *d = dst;
+       const char *s = src;
+       size_t n = siz, dlen;
+
+       while(n-- != 0 && *d != '\0')
+               d++;
+       dlen = d - dst;
+       n = siz - dlen;
+
+       if(n == 0)
+               return (dlen + strlen(s));
+       while(*s != '\0')
+       {
+               if(n != 1)
+               {
+                       *d++ = *s;
+                       n--;
+               }
+               s++;
+       }
+       *d = '\0';
+       return (dlen + (s - src));      /* count does not include NUL */
+}
+#endif
+
+#ifndef HAVE_STRLCPY
+size_t
+strlcpy(char *dst, const char *src, size_t siz)
+{
+       char *d = dst;
+       const char *s = src;
+       size_t n = siz;
+       /* Copy as many bytes as will fit */
+       if(n != 0 && --n != 0)
+       {
+               do
+               {
+                       if((*d++ = *s++) == 0)
+                               break;
+               }
+               while(--n != 0);
+       }
+       /* Not enough room in dst, add NUL and traverse rest of src */
+       if(n == 0)
+       {
+               if(siz != 0)
+                       *d = '\0';      /* NUL-terminate dst */
+               while(*s++)
+                       ;
+       }
+
+       return (s - src - 1);   /* count does not include NUL */
+}
+#endif
+
+char *
+strip_colour(char *string)
+{
+       char *c = string;
+       char *c2 = string;
+       char *last_non_space = NULL;
+       /* c is source, c2 is target */
+       for(; c && *c; c++)
+               switch (*c)
+               {
+               case 3:
+                       if(isdigit(c[1]))
+                       {
+                               c++;
+                               if(isdigit(c[1]))
+                                       c++;
+                               if(c[1] == ',' && isdigit(c[2]))
+                               {
+                                       c += 2;
+                                       if(isdigit(c[1]))
+                                               c++;
+                               }
+                       }
+                       break;
+               case 2:
+               case 6:
+               case 7:
+               case 22:
+               case 23:
+               case 27:
+               case 31:
+                       break;
+               case 32:
+                       *c2++ = *c;
+                       break;
+               default:
+                       *c2++ = *c;
+                       last_non_space = c2;
+                       break;
+               }
+       *c2 = '\0';
+       if(last_non_space)
+               *last_non_space = '\0';
+       return string;
+}
diff --git a/src/ircd.c b/src/ircd.c
new file mode 100644 (file)
index 0000000..8188068
--- /dev/null
@@ -0,0 +1,731 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  ircd.c: Starts up and runs the ircd.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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.c 3047 2006-12-26 23:18:05Z jilles $
+ */
+
+#include "stdinc.h"
+#include "setup.h"
+#include "config.h"
+
+#include "tools.h"
+#include "ircd.h"
+#include "channel.h"
+#include "class.h"
+#include "client.h"
+#include "common.h"
+#include "event.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd_signal.h"
+#include "sprintf_irc.h"
+#include "s_gline.h"
+#include "msg.h"               /* msgtab */
+#include "hostmask.h"
+#include "numeric.h"
+#include "parse.h"
+#include "res.h"
+#include "restart.h"
+#include "s_auth.h"
+#include "commio.h"
+#include "s_conf.h"
+#include "s_log.h"
+#include "s_serv.h"            /* try_connections */
+#include "s_user.h"
+#include "s_stats.h"
+#include "scache.h"
+#include "send.h"
+#include "supported.h"
+#include "whowas.h"
+#include "modules.h"
+#include "memory.h"
+#include "hook.h"
+#include "ircd_getopt.h"
+#include "balloc.h"
+#include "newconf.h"
+#include "patricia.h"
+#include "reject.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "cache.h"
+#include "monitor.h"
+#include "libcharybdis.h"
+#include "patchlevel.h"
+#include "serno.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.
+ */
+int _charybdis_data_version = CHARYBDIS_DV;
+
+extern int ServerRunning, initialVMTop;
+extern struct LocalUser meLocalUser;
+extern char **myargv;
+
+/*
+ * get_vm_top - get the operating systems notion of the resident set size
+ */
+static unsigned long
+get_vm_top(void)
+{
+       /*
+        * NOTE: sbrk is not part of the ANSI C library or the POSIX.1 standard
+        * however it seems that everyone defines it. Calling sbrk with a 0
+        * argument will return a pointer to the top of the process virtual
+        * memory without changing the process size, so this call should be
+        * reasonably safe (sbrk returns the new value for the top of memory).
+        * This code relies on the notion that the address returned will be an 
+        * offset from 0 (NULL), so the result of sbrk is cast to a size_t and 
+        * returned. We really shouldn't be using it here but...
+        */
+       void *vptr = sbrk(0);
+       return (unsigned long) vptr;
+}
+
+/*
+ * get_maxrss - get the operating systems notion of the resident set size
+ */
+unsigned long
+get_maxrss(void)
+{
+       return get_vm_top() - initialVMTop;
+}
+
+/*
+ * print_startup - print startup information
+ */
+static void
+print_startup(int pid)
+{
+       inotice("now running in %s mode from %s as pid %d ...",
+              !server_state_foreground ? "background" : "foreground",
+               ConfigFileEntry.dpath, pid);
+
+       /* let the parent process know the initialization was successful
+        * -- jilles */
+       if (!server_state_foreground)
+               write(0, ".", 1);
+       fclose(stdin);
+       fclose(stdout);
+       fclose(stderr);
+       open("/dev/null", O_RDWR);
+       dup2(0, 1);
+       dup2(0, 2);
+}
+
+static void
+ircd_log_cb(const char *str)
+{
+       ilog(L_MAIN, "%s", str);
+}
+
+/*
+ * Why EXIT_FAILURE here?
+ * Because if ircd_die_cb() is called it's because of a fatal
+ * error inside libcharybdis, and we don't know how to handle the
+ * exception, so it is logical to return a FAILURE exit code here.
+ *    --nenolod
+ */
+static void
+ircd_die_cb(const char *str)
+{
+       /* Try to get the message out to currently logged in operators. */
+       sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Server panic! %s", str);
+       inotice("server panic: %s", str);
+
+       unlink(pidFileName);
+       exit(EXIT_FAILURE);
+}
+
+/*
+ * init_sys
+ *
+ * inputs      - boot_daemon flag
+ * output      - none
+ * side effects        - if boot_daemon flag is not set, don't daemonize
+ */
+static void
+init_sys(void)
+{
+#if defined(RLIMIT_FD_MAX) && defined(HAVE_SYS_RLIMIT_H)
+       struct rlimit limit;
+
+       if(!getrlimit(RLIMIT_FD_MAX, &limit))
+       {
+
+               if(limit.rlim_max < MAXCONNECTIONS)
+               {
+                       fprintf(stderr, "ircd fd table too big\n");
+                       fprintf(stderr, "Hard Limit: %ld IRC max: %d\n",
+                               (long) limit.rlim_max, MAXCONNECTIONS);
+                       fprintf(stderr, "Fix MAXCONNECTIONS\n");
+                       exit(-1);
+               }
+
+               limit.rlim_cur = limit.rlim_max;        /* make soft limit the max */
+               if(setrlimit(RLIMIT_FD_MAX, &limit) == -1)
+               {
+                       fprintf(stderr, "error setting max fd's to %ld\n", (long) limit.rlim_cur);
+                       exit(EXIT_FAILURE);
+               }
+       }
+#endif /* RLIMIT_FD_MAX */
+}
+
+static int
+make_daemon(void)
+{
+       int pid;
+       int pip[2];
+       char c;
+
+       if (pipe(pip) < 0)
+       {
+               perror("pipe");
+               exit(EXIT_FAILURE);
+       }
+       dup2(pip[1], 0);
+       close(pip[1]);
+       if((pid = fork()) < 0)
+       {
+               perror("fork");
+               exit(EXIT_FAILURE);
+       }
+       else if(pid > 0)
+       {
+               close(0);
+               /* Wait for initialization to finish, successfully or
+                * unsuccessfully. Until this point the child may still
+                * write to stdout/stderr.
+                * -- jilles */
+               if (read(pip[0], &c, 1) > 0)
+                       exit(EXIT_SUCCESS);
+               else
+                       exit(EXIT_FAILURE);
+       }
+
+       close(pip[0]);
+       setsid();
+/*     fclose(stdin);
+       fclose(stdout);
+       fclose(stderr); */
+
+       return 0;
+}
+
+static int printVersion = 0;
+
+struct lgetopt myopts[] = {
+       {"dlinefile", &ConfigFileEntry.dlinefile,
+        STRING, "File to use for dlines.conf"},
+       {"configfile", &ConfigFileEntry.configfile,
+        STRING, "File to use for ircd.conf"},
+       {"klinefile", &ConfigFileEntry.klinefile,
+        STRING, "File to use for kline.conf"},
+       {"xlinefile", &ConfigFileEntry.xlinefile,
+        STRING, "File to use for xline.conf"},
+       {"resvfile", &ConfigFileEntry.resvfile,
+        STRING, "File to use for resv.conf"},
+       {"logfile", &logFileName,
+        STRING, "File to use for ircd.log"},
+       {"pidfile", &pidFileName,
+        STRING, "File to use for process ID"},
+       {"foreground", &server_state_foreground,
+        YESNO, "Run in foreground (don't detach)"},
+       {"version", &printVersion,
+        YESNO, "Print version and exit"},
+       {"conftest", &testing_conf,
+        YESNO, "Test the configuration files and exit"},
+       {"help", NULL, USAGE, "Print this text"},
+       {NULL, NULL, STRING, NULL},
+};
+
+void
+set_time(void)
+{
+       struct timeval newtime;
+       newtime.tv_sec = 0;
+       newtime.tv_usec = 0;
+#ifdef HAVE_GETTIMEOFDAY
+       if(gettimeofday(&newtime, NULL) == -1)
+       {
+               ilog(L_MAIN, "Clock Failure (%d)", errno);
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Clock Failure (%d), TS can be corrupted", errno);
+
+               restart("Clock Failure");
+       }
+#else
+       newtime.tv_sec = time(NULL);
+       
+#endif
+       if(newtime.tv_sec < CurrentTime)
+               set_back_events(CurrentTime - newtime.tv_sec);
+
+       SystemTime.tv_sec = newtime.tv_sec;
+       SystemTime.tv_usec = newtime.tv_usec;
+}
+
+static void
+check_rehash(void *unused)
+{
+       /*
+        * Check to see whether we have to rehash the configuration ..
+        */
+       if(dorehash)
+       {
+               rehash(1);
+               dorehash = 0;
+       }
+
+       if(dorehashbans)
+       {
+               rehash_bans(1);
+               dorehashbans = 0;
+       }
+
+       if(doremotd)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Got signal SIGUSR1, reloading ircd motd file");
+               free_cachefile(user_motd);
+               user_motd = cache_file(MPATH, "ircd.motd", 0);
+               doremotd = 0;
+       }
+}
+
+void
+charybdis_io_loop(void)
+{
+       time_t delay;
+
+       while (ServerRunning)
+       {
+               /* Run pending events, then get the number of seconds to the next
+                * event
+                */
+
+               delay = eventNextTime();
+               if(delay <= CurrentTime)
+                       eventRun();
+
+
+               comm_select(250);
+       }
+}
+
+/*
+ * initalialize_global_set_options
+ *
+ * inputs       - none
+ * output       - none
+ * side effects - This sets all global set options needed 
+ */
+static void
+initialize_global_set_options(void)
+{
+       memset(&GlobalSetOptions, 0, sizeof(GlobalSetOptions));
+       /* memset( &ConfigFileEntry, 0, sizeof(ConfigFileEntry)); */
+
+       GlobalSetOptions.maxclients = MAX_CLIENTS;
+       GlobalSetOptions.autoconn = 1;
+
+       GlobalSetOptions.spam_time = MIN_JOIN_LEAVE_TIME;
+       GlobalSetOptions.spam_num = MAX_JOIN_LEAVE_COUNT;
+
+       if(ConfigFileEntry.default_floodcount)
+               GlobalSetOptions.floodcount = ConfigFileEntry.default_floodcount;
+       else
+               GlobalSetOptions.floodcount = 10;
+
+       split_servers = ConfigChannel.default_split_server_count;
+       split_users = ConfigChannel.default_split_user_count;
+
+       if(split_users && split_servers
+          && (ConfigChannel.no_create_on_split || ConfigChannel.no_join_on_split))
+       {
+               splitmode = 1;
+               splitchecking = 1;
+       }
+
+       GlobalSetOptions.ident_timeout = IDENT_TIMEOUT;
+
+       strlcpy(GlobalSetOptions.operstring,
+               ConfigFileEntry.default_operstring,
+               sizeof(GlobalSetOptions.operstring));
+       strlcpy(GlobalSetOptions.adminstring,
+               ConfigFileEntry.default_adminstring,
+               sizeof(GlobalSetOptions.adminstring));
+
+       /* memset( &ConfigChannel, 0, sizeof(ConfigChannel)); */
+
+       /* End of global set options */
+
+}
+
+/*
+ * initialize_server_capabs
+ *
+ * inputs       - none
+ * output       - none
+ */
+static void
+initialize_server_capabs(void)
+{
+       default_server_capabs &= ~CAP_ZIP;
+}
+
+
+/*
+ * write_pidfile
+ *
+ * inputs       - filename+path of pid file
+ * output       - none
+ * side effects - write the pid of the ircd to filename
+ */
+static void
+write_pidfile(const char *filename)
+{
+       FILE *fb;
+       char buff[32];
+       if((fb = fopen(filename, "w")))
+       {
+               unsigned int pid = (unsigned int) getpid();
+
+               ircsnprintf(buff, sizeof(buff), "%u\n", pid);
+               if((fputs(buff, fb) == -1))
+               {
+                       ilog(L_MAIN, "Error writing %u to pid file %s (%s)",
+                            pid, filename, strerror(errno));
+               }
+               fclose(fb);
+               return;
+       }
+       else
+       {
+               ilog(L_MAIN, "Error opening pid file %s", filename);
+       }
+}
+
+/*
+ * check_pidfile
+ *
+ * inputs       - filename+path of pid file
+ * output       - none
+ * side effects - reads pid from pidfile and checks if ircd is in process
+ *                list. if it is, gracefully exits
+ * -kre
+ */
+static void
+check_pidfile(const char *filename)
+{
+       FILE *fb;
+       char buff[32];
+       pid_t pidfromfile;
+
+       /* Don't do logging here, since we don't have log() initialised */
+       if((fb = fopen(filename, "r")))
+       {
+               if(fgets(buff, 20, fb) != NULL)
+               {
+                       pidfromfile = atoi(buff);
+                       if(!kill(pidfromfile, 0))
+                       {
+                               printf("ircd: daemon is already running\n");
+                               exit(-1);
+                       }
+               }
+               fclose(fb);
+       }
+}
+
+/*
+ * setup_corefile
+ *
+ * inputs       - nothing
+ * output       - nothing
+ * side effects - setups corefile to system limits.
+ * -kre
+ */
+static void
+setup_corefile(void)
+{
+#ifdef HAVE_SYS_RESOURCE_H
+       struct rlimit rlim;     /* resource limits */
+
+       /* Set corefilesize to maximum */
+       if(!getrlimit(RLIMIT_CORE, &rlim))
+       {
+               rlim.rlim_cur = rlim.rlim_max;
+               setrlimit(RLIMIT_CORE, &rlim);
+       }
+#endif
+}
+
+/*
+ * main
+ *
+ * Initializes the IRCd.
+ *
+ * Inputs       - number of commandline args, args themselves
+ * Outputs      - none
+ * Side Effects - this is where the ircd gets going right now
+ */
+int
+main(int argc, char *argv[])
+{
+       int fd;
+
+       /* Check to see if the user is running us as root, which is a nono */
+       if(geteuid() == 0)
+       {
+               fprintf(stderr, "Don't run ircd as root!!!\n");
+               return -1;
+       }
+
+       /*
+        * save server boot time right away, so getrusage works correctly
+        */
+       set_time();
+       /*
+        * Setup corefile size immediately after boot -kre
+        */
+       setup_corefile();
+
+       /*
+        * set initialVMTop before we allocate any memory
+        */
+       initialVMTop = get_vm_top();
+
+       ServerRunning = 0;
+       /* It ain't random, but it ought to be a little harder to guess */
+       srand(SystemTime.tv_sec ^ (SystemTime.tv_usec | (getpid() << 20)));
+       memset(&me, 0, sizeof(me));
+       memset(&meLocalUser, 0, sizeof(meLocalUser));
+       me.localClient = &meLocalUser;
+
+       /* Make sure all lists are zeroed */
+       memset(&unknown_list, 0, sizeof(unknown_list));
+       memset(&lclient_list, 0, sizeof(lclient_list));
+       memset(&serv_list, 0, sizeof(serv_list));
+       memset(&global_serv_list, 0, sizeof(global_serv_list));
+       memset(&local_oper_list, 0, sizeof(local_oper_list));
+       memset(&oper_list, 0, sizeof(oper_list));
+
+       dlinkAddTail(&me, &me.node, &global_client_list);
+
+       memset((void *) &Count, 0, sizeof(Count));
+       memset((void *) &ServerInfo, 0, sizeof(ServerInfo));
+       memset((void *) &AdminInfo, 0, sizeof(AdminInfo));
+
+       /* Initialise the channel capability usage counts... */
+       init_chcap_usage_counts();
+
+       ConfigFileEntry.dpath = DPATH;
+       ConfigFileEntry.configfile = CPATH;     /* Server configuration file */
+       ConfigFileEntry.klinefile = KPATH;      /* Server kline file */
+       ConfigFileEntry.dlinefile = DLPATH;     /* dline file */
+       ConfigFileEntry.xlinefile = XPATH;
+       ConfigFileEntry.resvfile = RESVPATH;
+       ConfigFileEntry.connect_timeout = 30;   /* Default to 30 */
+       myargv = argv;
+       umask(077);             /* better safe than sorry --SRB */
+
+       parseargs(&argc, &argv, myopts);
+
+       if(printVersion)
+       {
+               printf("ircd: version %s\n", ircd_version);
+               exit(EXIT_SUCCESS);
+       }
+
+       if(chdir(ConfigFileEntry.dpath))
+       {
+               fprintf(stderr, "Unable to chdir to %s: %s\n", ConfigFileEntry.dpath, strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+
+       setup_signals();
+
+#ifdef __CYGWIN__
+       server_state_foreground = 1;
+#endif
+
+       if (testing_conf)
+               server_state_foreground = 1;
+
+       /* Make sure fd 0, 1 and 2 are in use -- jilles */
+       do
+       {
+               fd = open("/dev/null", O_RDWR);
+       } while (fd < 2 && fd != -1);
+       if (fd > 2)
+               close(fd);
+       else if (fd == -1)
+               exit(1);
+
+       /* Check if there is pidfile and daemon already running */
+       if(!testing_conf)
+       {
+               check_pidfile(pidFileName);
+
+               if(!server_state_foreground)
+                       make_daemon();
+               inotice("starting %s ...", ircd_version);
+       }
+
+       /* Init the event subsystem */
+       libcharybdis_init(ircd_log_cb, restart, ircd_die_cb);
+       init_sys();
+
+       fdlist_init();
+       if(!server_state_foreground)
+       {
+               comm_close_all();
+       }
+
+       init_main_logfile();
+       init_patricia();
+       newconf_init();
+       init_s_conf();
+       init_s_newconf();
+       init_hash();
+       clear_scache_hash_table();      /* server cache name table */
+       init_host_hash();
+       clear_hash_parse();
+       init_client();
+       initUser();
+       init_hook();
+       init_channels();
+       initclass();
+       initwhowas();
+       init_stats();
+       init_reject();
+       init_cache();
+       init_monitor();
+       init_isupport();
+       load_all_modules(1);
+#ifndef STATIC_MODULES
+       load_core_modules(1);
+#endif
+       init_auth();            /* Initialise the auth code */
+       init_resolver();        /* Needs to be setup before the io loop */
+
+       if (testing_conf)
+               fprintf(stderr, "\nBeginning config test\n");
+       read_conf_files(YES);   /* cold start init conf files */
+       rehash_bans(0);
+#ifndef STATIC_MODULES
+
+       mod_add_path(MODULE_DIR); 
+       mod_add_path(MODULE_DIR "/autoload"); 
+#endif
+
+       initialize_server_capabs();     /* Set up default_server_capabs */
+       initialize_global_set_options();
+
+       if(ServerInfo.name == NULL)
+       {
+               ierror("no server name specified in serverinfo block.");
+               return -1;
+       }
+       strlcpy(me.name, ServerInfo.name, sizeof(me.name));
+
+       if(ServerInfo.sid[0] == '\0')
+       {
+               ierror("no server sid specified in serverinfo block.");
+               return -2;
+       }
+       strcpy(me.id, ServerInfo.sid);
+       init_uid();
+
+       /* serverinfo{} description must exist.  If not, error out. */
+       if(ServerInfo.description == NULL)
+       {
+               ierror("no server description specified in serverinfo block.");
+               return -3;
+       }
+       strlcpy(me.info, ServerInfo.description, sizeof(me.info));
+
+       if (testing_conf)
+       {
+               fprintf(stderr, "\nConfig testing complete.\n");
+               fflush(stderr);
+               return 0;       /* Why? We want the launcher to exit out. */
+       }
+
+       me.from = &me;
+       me.servptr = &me;
+       SetMe(&me);
+       make_server(&me);
+       me.serv->up = me.name;
+       startup_time = CurrentTime;
+       add_to_client_hash(me.name, &me);
+       add_to_id_hash(me.id, &me);
+
+       dlinkAddAlloc(&me, &global_serv_list);
+
+       construct_umodebuf();
+
+       check_class();
+       write_pidfile(pidFileName);
+       load_help();
+       open_logfiles();
+
+       ilog(L_MAIN, "Server Ready");
+
+       eventAddIsh("cleanup_glines", cleanup_glines, NULL, CLEANUP_GLINES_TIME);
+
+       /* We want try_connections to be called as soon as possible now! -- adrian */
+       /* No, 'cause after a restart it would cause all sorts of nick collides */
+       /* um.  by waiting even longer, that just means we have even *more*
+        * nick collisions.  what a stupid idea. set an event for the IO loop --fl
+        */
+       eventAddIsh("try_connections", try_connections, NULL, STARTUP_CONNECTIONS_TIME);
+       eventAddOnce("try_connections_startup", try_connections, NULL, 0);
+
+       eventAddIsh("collect_zipstats", collect_zipstats, NULL, ZIPSTATS_TIME);
+
+       /* Setup the timeout check. I'll shift it later :)  -- adrian */
+       eventAddIsh("comm_checktimeouts", comm_checktimeouts, NULL, 1);
+
+       eventAdd("check_rehash", check_rehash, NULL, 1);
+
+       if(ConfigServerHide.links_delay > 0)
+               eventAdd("cache_links", cache_links, NULL,
+                           ConfigServerHide.links_delay);
+       else
+               ConfigServerHide.links_disabled = 1;
+
+       if(splitmode)
+               eventAdd("check_splitmode", check_splitmode, NULL, 2);
+
+       ServerRunning = 1;
+
+       print_startup(getpid());
+
+       charybdis_io_loop();
+
+       return 0;
+}
diff --git a/src/ircd_lexer.l b/src/ircd_lexer.l
new file mode 100644 (file)
index 0000000..bec3bc7
--- /dev/null
@@ -0,0 +1,273 @@
+/* src/ircd_lexer.l
+ *
+ *  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 6 2005-09-10 01:02:21Z nenolod $
+ */
+
+%option case-insensitive
+%option noyywrap
+%option nounput
+
+%{
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <netinet/in.h>
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+
+#define WE_ARE_MEMORY_C
+
+#include "stdinc.h"
+#include "ircd_defs.h"
+#include "common.h"
+#include "config.h"
+#include "s_log.h"
+#include "s_conf.h"
+#include "newconf.h"
+
+#include "y.tab.h"
+
+int yylex(void);
+
+/* here to fixup gcc 3.3 errors */
+int yyget_lineno(void);
+FILE *yyget_in(void);
+FILE *yyget_out(void);
+int yyget_leng(void);
+char *yyget_text(void);
+void yyset_lineno(int  line_number);
+void yyset_in(FILE *  in_str);
+void yyset_out(FILE *  out_str);
+int yyget_debug(void);
+void yyset_debug(int  bdebug);
+int yylex_destroy(void);
+
+
+#define MAX_INCLUDE_DEPTH 10
+
+YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
+int include_stack_ptr=0;
+int lineno = 1;
+void ccomment(void);
+void cinclude(void);
+void hashcomment(void);
+int ieof(void);
+int lineno_stack[MAX_INCLUDE_DEPTH];
+char conffile_stack[MAX_INCLUDE_DEPTH][IRCD_BUFSIZE];
+char conffilebuf[IRCD_BUFSIZE+1];
+char *current_file = conffilebuf;
+
+FILE *inc_fbfile_in[MAX_INCLUDE_DEPTH];
+
+char linebuf[512];
+
+#undef YY_INPUT
+
+#define YY_FATAL_ERROR(msg) conf_yy_fatal_error(msg)
+
+#define YY_INPUT(buf,result,max_size) \
+  if (!(result = conf_fgets(buf, max_size, conf_fbfile_in))) \
+    YY_FATAL_ERROR("input in flex scanner failed"); 
+%}
+
+ws        [ \t]*
+digit     [0-9]
+comment   #.*
+qstring   \"[^\"\n]*[\"\n]
+string    [a-zA-Z_\~][a-zA-Z0-9_]*
+include   \.include{ws}(\<.*\>|\".*\")
+
+%%
+{include}       { cinclude(); }
+"/*"            { ccomment(); }
+\n.*            { strcpy(linebuf, yytext+1); lineno++; yyless(1); }
+
+{ws}            ;
+{comment}       { hashcomment(); }
+
+{digit}+        { yylval.number = atoi(yytext); return NUMBER; }
+
+{qstring}      {
+                  if(yytext[yyleng-2] == '\\')
+                    {
+                      yyless(yyleng-1); /* return last quote */
+                      yymore();         /* append next string */
+                    }
+                  else
+                    {
+                      strcpy(yylval.string, yytext + 1);
+                      if(yylval.string[yyleng-2] != '"')
+                        ilog(L_MAIN, "Unterminated character string");
+                      else
+                        {
+                          int i,j;
+                          yylval.string[yyleng-2] = '\0'; /* remove close
+                                                           *  quote 
+                                                           */
+                          
+                          for (j=i=0 ;yylval.string[i] != '\0'; i++,j++)
+                            {
+                              if (yylval.string[i] != '\\')
+                                {
+                                  yylval.string[j] = yylval.string[i];
+                                }
+                              else
+                                {
+                                  i++;
+                                  if (yylval.string[i] == '\0') /* XXX 
+                                                                 * should not
+                                                                 * happen
+                                                                 */
+                                    {
+                                      ilog(L_MAIN,
+                                           "Unterminated character string");
+                                      break;
+                                    }
+                                  yylval.string[j] = yylval.string[i];
+                                }
+                            }
+                          yylval.string[j] = '\0';
+                          return QSTRING;
+                        }
+                    }
+                }
+
+
+loadmodule     { return LOADMODULE; }
+{string}        { 
+                 strcpy(yylval.string, yytext);
+                  yylval.string[yyleng] = '\0';
+                  return STRING;
+                }
+
+\.\.           { return TWODOTS; }
+.               { return yytext[0]; }
+<<EOF>>         { if (ieof()) yyterminate(); }
+%%
+
+/* C-comment ignoring routine -kre*/
+void ccomment()
+{
+  int c;
+  
+  /* log(L_NOTICE, "got comment"); */
+  while (1)
+    {
+      while ((c = input()) != '*' && c != EOF)
+        if (c == '\n') ++lineno;
+      if (c == '*')
+        {
+          while ((c = input()) == '*');
+          if (c == '/') 
+            break;
+        }
+      if (c == EOF)
+        {
+          YY_FATAL_ERROR("EOF in comment");
+          /* XXX hack alert this disables
+           * the stupid unused function warning
+           * gcc generates
+           */
+          yy_fatal_error("EOF in comment");
+          break;
+        }
+    }
+}
+
+void cinclude(void)
+{
+  char *c;
+  if ((c = strchr(yytext, '<')) == NULL)
+    *strchr(c = strchr(yytext, '"') + 1, '"') = 0;
+  else
+    *strchr(++c, '>') = 0;
+
+  /* do stacking and co. */ 
+  if (include_stack_ptr >= MAX_INCLUDE_DEPTH)
+    conf_report_error("Includes nested too deep (max is %d)", MAX_INCLUDE_DEPTH);
+  else
+  {
+    FILE *tmp_fbfile_in;
+    
+    tmp_fbfile_in = fopen(c, "r");
+    
+    if (tmp_fbfile_in == NULL)
+    {
+      /* if its not found in PREFIX, look in ETCPATH */
+      char fnamebuf[IRCD_BUFSIZE];
+
+      snprintf(fnamebuf, sizeof(fnamebuf), "%s/%s", ETCPATH, c);
+      tmp_fbfile_in = fopen(fnamebuf, "r");
+
+      /* wasnt found there either.. error. */
+      if(tmp_fbfile_in == NULL)
+      {
+        conf_report_error("Include %s: %s.", c, strerror(errno));
+        return;
+      }
+    }
+    lineno_stack[include_stack_ptr] = lineno;
+    lineno = 1;
+    inc_fbfile_in[include_stack_ptr] = conf_fbfile_in;
+    strcpy(conffile_stack[include_stack_ptr], c);
+    current_file = conffile_stack[include_stack_ptr];
+    include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER;
+    conf_fbfile_in = tmp_fbfile_in;
+    yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+  }
+}
+
+int ieof(void)
+{
+  if (include_stack_ptr)
+    fclose(conf_fbfile_in);
+  if (--include_stack_ptr < 0)
+  {
+    /* We will now exit the lexer - restore init values if we get /rehash
+     * later and reenter lexer -kre */
+    include_stack_ptr = 0;
+    lineno = 1;
+    return 1;
+  }
+  /* switch buffer */
+  yy_delete_buffer(YY_CURRENT_BUFFER);
+  lineno = lineno_stack[include_stack_ptr];
+  conf_fbfile_in = inc_fbfile_in[include_stack_ptr];
+
+  if(include_stack_ptr)
+    current_file = conffile_stack[include_stack_ptr];
+  else
+    current_file = conffilebuf;
+
+  yy_switch_to_buffer(include_stack[include_stack_ptr]);
+  return 0;
+}
+
+/* #-comment style, look for #include */
+#define INCLUDE "#include"
+
+void hashcomment(void)
+{
+  if (strlen(yytext) < sizeof(INCLUDE) - 1)
+    return;
+
+  if (!strncasecmp(yytext, INCLUDE, sizeof(INCLUDE) - 1))
+      yyerror("You probably meant '.include', skipping");
+}
diff --git a/src/ircd_parser.y b/src/ircd_parser.y
new file mode 100644 (file)
index 0000000..153dcfb
--- /dev/null
@@ -0,0 +1,332 @@
+/* This code is in the public domain.
+ * $Nightmare: nightmare/src/main/parser.y,v 1.2.2.1.2.1 2002/07/02 03:42:10 ejb Exp $
+ * $Id: ircd_parser.y 871 2006-02-18 21:56:00Z nenolod $
+ */
+
+%{
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <netinet/in.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#define WE_ARE_MEMORY_C
+#include "stdinc.h"
+#include "setup.h"
+#include "common.h"
+#include "ircd_defs.h"
+#include "config.h"
+#include "client.h"
+#include "modules.h"
+#include "newconf.h"
+
+#define YY_NO_UNPUT
+
+int yyparse();
+int yyerror(const char *);
+int yylex();
+
+static time_t conf_find_time(char*);
+
+static struct {
+       const char *    name;
+       const char *    plural;
+       time_t  val;
+} ircd_times[] = {
+       {"second",     "seconds",    1},
+       {"minute",     "minutes",    60},
+       {"hour",       "hours",      60 * 60},
+       {"day",        "days",       60 * 60 * 24},
+       {"week",       "weeks",      60 * 60 * 24 * 7},
+       {"fortnight",  "fortnights", 60 * 60 * 24 * 14},
+       {"month",      "months",     60 * 60 * 24 * 7 * 4},
+       {"year",       "years",      60 * 60 * 24 * 365},
+       /* ok-- we now do sizes here too. they aren't times, but 
+          it's close enough */
+       {"byte",        "bytes",        1},
+       {"kb",          NULL,           1024},
+       {"kbyte",       "kbytes",       1024},
+       {"kilobyte",    "kilebytes",    1024},
+       {"mb",          NULL,           1024 * 1024},
+       {"mbyte",       "mbytes",       1024 * 1024},
+       {"megabyte",    "megabytes",    1024 * 1024},
+       {NULL, NULL, 0},
+};
+
+time_t conf_find_time(char *name)
+{
+  int i;
+
+  for (i = 0; ircd_times[i].name; i++)
+    {
+      if (strcasecmp(ircd_times[i].name, name) == 0 ||
+         (ircd_times[i].plural && strcasecmp(ircd_times[i].plural, name) == 0))
+       return ircd_times[i].val;
+    }
+
+  return 0;
+}
+
+static struct
+{
+       const char *word;
+       int yesno;
+} yesno[] = {
+       {"yes",         1},
+       {"no",          0},
+       {"true",        1},
+       {"false",       0},
+       {"on",          1},
+       {"off",         0},
+       {NULL,          0}
+};
+
+static int     conf_get_yesno_value(char *str)
+{
+       int i;
+
+       for (i = 0; yesno[i].word; i++)
+       {
+               if (strcasecmp(str, yesno[i].word) == 0)
+               {
+                       return yesno[i].yesno;
+               }
+       }
+
+       return -1;
+}
+
+static void    free_cur_list(conf_parm_t* list)
+{
+       switch (list->type & CF_MTYPE)
+       {
+               case CF_STRING:
+               case CF_QSTRING:
+                       MyFree(list->v.string);
+                       break;
+               case CF_LIST:
+                       free_cur_list(list->v.list);
+                       break;
+               default: break;
+       }
+
+       if (list->next)
+               free_cur_list(list->next);
+}
+
+               
+conf_parm_t *  cur_list = NULL;
+
+static void    add_cur_list_cpt(conf_parm_t *new)
+{
+       if (cur_list == NULL)
+       {
+               cur_list = MyMalloc(sizeof(conf_parm_t));
+               cur_list->type |= CF_FLIST;
+               cur_list->v.list = new;
+       }
+       else
+       {
+               new->next = cur_list->v.list;
+               cur_list->v.list = new;
+       }
+}
+
+static void    add_cur_list(int type, char *str, int number)
+{
+       conf_parm_t *new;
+
+       new = MyMalloc(sizeof(conf_parm_t));
+       new->next = NULL;
+       new->type = type;
+
+       switch(type)
+       {
+       case CF_INT:
+       case CF_TIME:
+       case CF_YESNO:
+               new->v.number = number;
+               break;
+       case CF_STRING:
+       case CF_QSTRING:
+               DupString(new->v.string, str);
+               break;
+       }
+
+       add_cur_list_cpt(new);
+}
+
+
+%}
+
+%union {
+       int             number;
+       char            string[IRCD_BUFSIZE + 1];
+       conf_parm_t *   conf_parm;
+}
+
+%token LOADMODULE TWODOTS
+
+%token <string> QSTRING STRING
+%token <number> NUMBER
+
+%type <string> qstring string
+%type <number> number timespec 
+%type <conf_parm> oneitem single itemlist
+
+%start conf
+
+%%
+
+conf: 
+       | conf conf_item 
+       | error
+       ;
+
+conf_item: block
+        | loadmodule
+         ;
+
+block: string 
+         { 
+           conf_start_block($1, NULL);
+         }
+       '{' block_items '}' ';' 
+         {
+          if (conf_cur_block)
+               conf_end_block(conf_cur_block);
+         }
+     | string qstring 
+         { 
+           conf_start_block($1, $2);
+         }
+       '{' block_items '}' ';'
+         {
+          if (conf_cur_block)
+               conf_end_block(conf_cur_block);
+         }
+     ;
+
+block_items: block_items block_item 
+           | block_item 
+           ;
+
+block_item:    string '=' itemlist ';'
+               {
+                       conf_call_set(conf_cur_block, $1, cur_list, CF_LIST);
+                       free_cur_list(cur_list);
+                       cur_list = NULL;
+               }
+               ;
+
+itemlist: itemlist ',' single
+       | single
+       ;
+
+single: oneitem
+       {
+               add_cur_list_cpt($1);
+       }
+       | oneitem TWODOTS oneitem
+       {
+               /* "1 .. 5" meaning 1,2,3,4,5 - only valid for integers */
+               if (($1->type & CF_MTYPE) != CF_INT ||
+                   ($3->type & CF_MTYPE) != CF_INT)
+               {
+                       conf_report_error("Both arguments in '..' notation must be integers.");
+                       break;
+               }
+               else
+               {
+                       int i;
+
+                       for (i = $1->v.number; i <= $3->v.number; i++)
+                       {
+                               add_cur_list(CF_INT, 0, i);
+                       }
+               }
+       }
+       ;
+
+oneitem: qstring
+            {
+               $$ = MyMalloc(sizeof(conf_parm_t));
+               $$->type = CF_QSTRING;
+               DupString($$->v.string, $1);
+           }
+          | timespec
+            {
+               $$ = MyMalloc(sizeof(conf_parm_t));
+               $$->type = CF_TIME;
+               $$->v.number = $1;
+           }
+          | number
+            {
+               $$ = MyMalloc(sizeof(conf_parm_t));
+               $$->type = CF_INT;
+               $$->v.number = $1;
+           }
+          | string
+            {
+               /* a 'string' could also be a yes/no value .. 
+                  so pass it as that, if so */
+               int val = conf_get_yesno_value($1);
+
+               $$ = MyMalloc(sizeof(conf_parm_t));
+
+               if (val != -1)
+               {
+                       $$->type = CF_YESNO;
+                       $$->v.number = val;
+               }
+               else
+               {
+                       $$->type = CF_STRING;
+                       DupString($$->v.string, $1);
+               }
+            }
+          ;
+
+loadmodule:
+         LOADMODULE QSTRING
+            {
+#ifndef STATIC_MODULES
+              char *m_bn;
+
+              m_bn = irc_basename((char *) $2);
+
+              if (findmodule_byname(m_bn) == -1)
+                 load_one_module($2, 0);
+#endif
+           }
+         ';'
+          ;
+
+qstring: QSTRING { strcpy($$, $1); } ;
+string: STRING { strcpy($$, $1); } ;
+number: NUMBER { $$ = $1; } ;
+
+timespec:      number string
+               {
+                       time_t t;
+
+                       if ((t = conf_find_time($2)) == 0)
+                       {
+                               conf_report_error("Unrecognised time type/size '%s'", $2);
+                               t = 1;
+                       }
+           
+                       $$ = $1 * t;
+               }
+               | timespec timespec
+               {
+                       $$ = $1 + $2;
+               }
+               | timespec number
+               {
+                       $$ = $1 + $2;
+               }
+               ;
diff --git a/src/ircd_signal.c b/src/ircd_signal.c
new file mode 100644 (file)
index 0000000..e910505
--- /dev/null
@@ -0,0 +1,167 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, src/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.
+ *
+ * $Id: ircd_signal.c 6 2005-09-10 01:02:21Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "ircd_signal.h"
+#include "ircd.h"              /* dorehash */
+#include "restart.h"           /* server_reboot */
+#include "s_log.h"
+#include "memory.h"
+#include "commio.h"
+#include "s_conf.h"
+#include "client.h"
+#include "send.h"
+
+/*
+ * dummy_handler - don't know if this is really needed but if alarm is still
+ * being used we probably will
+ */
+static void
+dummy_handler(int sig)
+{
+       /* Empty */
+}
+
+
+static void
+sigchld_handler(int sig)
+{
+       int status;
+       waitpid(-1, &status, WNOHANG);
+}
+/*
+ * sigterm_handler - exit the server
+ */
+static void
+sigterm_handler(int sig)
+{
+       /* XXX we had a flush_connections() here - we should close all the
+        * connections and flush data. read server_reboot() for my explanation.
+        *     -- adrian
+        */
+       ilog(L_MAIN, "Server killed By SIGTERM");
+       exit(-1);
+}
+
+/* 
+ * sighup_handler - reread the server configuration
+ */
+static void
+sighup_handler(int sig)
+{
+       dorehash = 1;
+}
+
+/*
+ * sigusr1_handler - reread the motd file
+ */
+static void
+sigusr1_handler(int sig)
+{
+       doremotd = 1;
+}
+
+static void
+sigusr2_handler(int sig)
+{
+       dorehashbans = 1;
+}
+
+/*
+ * sigint_handler - restart the server
+ */
+static void
+sigint_handler(int sig)
+{
+       static int restarting = 0;
+
+       if(server_state_foreground)
+       {
+               ilog(L_MAIN, "Server exiting on SIGINT");
+               exit(0);
+       }
+       else
+       {
+               ilog(L_MAIN, "Server Restarting on SIGINT");
+               if(restarting == 0)
+               {
+                       restarting = 1;
+                       server_reboot();
+               }
+       }
+}
+
+/*
+ * setup_signals - initialize signal handlers for server
+ */
+void
+setup_signals()
+{
+       struct sigaction act;
+
+       act.sa_flags = 0;
+       act.sa_handler = SIG_IGN;
+       sigemptyset(&act.sa_mask);
+       sigaddset(&act.sa_mask, SIGPIPE);
+       sigaddset(&act.sa_mask, SIGALRM);
+#ifdef SIGTRAP
+       sigaddset(&act.sa_mask, SIGTRAP);
+#endif
+
+# ifdef SIGWINCH
+       sigaddset(&act.sa_mask, SIGWINCH);
+       sigaction(SIGWINCH, &act, 0);
+# endif
+       sigaction(SIGPIPE, &act, 0);
+#ifdef SIGTRAP
+       sigaction(SIGTRAP, &act, 0);
+#endif
+
+       act.sa_handler = dummy_handler;
+       sigaction(SIGALRM, &act, 0);
+
+       act.sa_handler = sighup_handler;
+       sigemptyset(&act.sa_mask);
+       sigaddset(&act.sa_mask, SIGHUP);
+       sigaction(SIGHUP, &act, 0);
+
+       act.sa_handler = sigint_handler;
+       sigaddset(&act.sa_mask, SIGINT);
+       sigaction(SIGINT, &act, 0);
+
+       act.sa_handler = sigterm_handler;
+       sigaddset(&act.sa_mask, SIGTERM);
+       sigaction(SIGTERM, &act, 0);
+
+       act.sa_handler = sigusr1_handler;
+       sigaddset(&act.sa_mask, SIGUSR1);
+       sigaction(SIGUSR1, &act, 0);
+
+       act.sa_handler = sigusr2_handler;
+       sigaddset(&act.sa_mask, SIGUSR2);
+       sigaction(SIGUSR2, &act, 0);
+
+       act.sa_handler = sigchld_handler;
+       sigaddset(&act.sa_mask, SIGCHLD);
+       sigaction(SIGCHLD, &act, 0);
+
+}
diff --git a/src/ircd_state.c b/src/ircd_state.c
new file mode 100644 (file)
index 0000000..d424e94
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * charybdis: An advanced ircd.
+ * ircd_state.c: Functions for backing up and synchronizing IRCd's state
+ *
+ * Copyright (c) 2006 William Pitcock <nenolod@nenolod.net>
+ *
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: main.c 867 2006-02-16 14:25:09Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "setup.h"
+#include "config.h"
+
+#include "client.h"
+#include "tools.h"
+#include "tools.h"
+#include "ircd.h"
+#include "channel.h"
+#include "class.h"
+#include "client.h"
+#include "common.h"
+#include "event.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd_signal.h"
+#include "sprintf_irc.h"
+#include "s_gline.h"
+#include "msg.h"                /* msgtab */
+#include "hostmask.h"
+#include "numeric.h"
+#include "parse.h"
+#include "res.h"
+#include "restart.h"
+#include "s_auth.h"
+#include "commio.h"
+#include "s_conf.h"
+#include "s_log.h"
+#include "s_serv.h"             /* try_connections */
+#include "s_user.h"
+#include "s_stats.h"
+#include "scache.h"
+#include "send.h"
+#include "whowas.h"
+#include "modules.h"
+#include "memory.h"
+#include "hook.h"
+#include "ircd_getopt.h"
+#include "balloc.h"
+#include "newconf.h"
+#include "patricia.h"
+#include "reject.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "cache.h"
+#include "monitor.h"
+#include "libcharybdis.h"
+#include "patchlevel.h"
+#include "serno.h"
+
+dlink_list lclient_list = { NULL, NULL, 0 };
+dlink_list global_client_list = { NULL, NULL, 0 };
+dlink_list global_channel_list = { NULL, NULL, 0 };
+
+dlink_list unknown_list;        /* unknown clients ON this server only */
+dlink_list serv_list;           /* local servers to this server ONLY */
+dlink_list global_serv_list;    /* global servers on the network */
+dlink_list local_oper_list;     /* our opers, duplicated in lclient_list */
+dlink_list oper_list;           /* network opers */
+
+/* /quote set variables */
+struct SetOptions GlobalSetOptions;
+
+/* configuration set from ircd.conf */
+struct config_file_entry ConfigFileEntry;
+/* server info set from ircd.conf */
+struct server_info ServerInfo;
+/* admin info set from ircd.conf */
+struct admin_info AdminInfo;
+
+struct Counter Count;
+
+struct timeval SystemTime;
+int ServerRunning;              /* GLOBAL - server execution state */
+struct Client me;               /* That's me */
+struct LocalUser meLocalUser;   /* That's also part of me */
+
+time_t startup_time;
+
+int default_server_capabs = CAP_MASK;
+
+int splitmode;
+int splitchecking;
+int split_users;
+int split_servers;
+int eob_count;
+
+unsigned long initialVMTop = 0;  /* top of virtual memory at init */
+const char *logFileName = LPATH;
+const char *pidFileName = PPATH;
+
+char **myargv;
+int dorehash = 0;
+int dorehashbans = 0;
+int doremotd = 0;
+int kline_queued = 0;
+int server_state_foreground = 0;
+int opers_see_all_users = 0;
+
+int testing_conf = 0;
+
+struct config_channel_entry ConfigChannel;
+BlockHeap *channel_heap;
+BlockHeap *ban_heap;
+BlockHeap *topic_heap;
+BlockHeap *member_heap;
+
+BlockHeap *client_heap = NULL;
+BlockHeap *lclient_heap = NULL;
+BlockHeap *pclient_heap = NULL;
+
+char current_uid[IDLEN];
+
+/* patricia */
+BlockHeap *prefix_heap;
+BlockHeap *node_heap;
+BlockHeap *patricia_heap;
+
+BlockHeap *linebuf_heap;
+
+BlockHeap *dnode_heap;
+
+#ifdef NOTYET
+
+void charybdis_initstate(struct IRCdState *self)
+{
+
+}
+
+#endif
diff --git a/src/kdparse.c b/src/kdparse.c
new file mode 100644 (file)
index 0000000..258b666
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  kdparse.c: Parses K and D lines.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: kdparse.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "s_log.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "hostmask.h"
+#include "client.h"
+#include "irc_string.h"
+#include "memory.h"
+#include "hash.h"
+
+/* conf_add_fields()
+ * 
+ * inputs       - pointer to config item, host/pass/user/operreason fields
+ * output       - NONE
+ * side effects - update respective fields with pointers
+ */
+static void
+conf_add_fields(struct ConfItem *aconf,        const char *host_field,
+               const char *pass_field, const char *user_field,
+               const char *operreason_field)
+{
+       if(host_field != NULL)
+               DupString(aconf->host, host_field);
+       if(pass_field != NULL)
+               DupString(aconf->passwd, pass_field);
+       if(user_field != NULL)
+               DupString(aconf->user, user_field);
+       if(operreason_field != NULL)
+               DupString(aconf->spasswd, operreason_field);
+}
+
+/*
+ * parse_k_file
+ * Inputs       - pointer to line to parse
+ * Output       - NONE
+ * Side Effects - Parse one new style K line
+ */
+
+void
+parse_k_file(FILE * file)
+{
+       struct ConfItem *aconf;
+       char *user_field = NULL;
+       char *reason_field = NULL;
+       char *operreason_field = NULL;
+       char *host_field = NULL;
+       char line[BUFSIZE];
+       char *p;
+
+       while (fgets(line, sizeof(line), file))
+       {
+               if((p = strchr(line, '\n')) != NULL)
+                       *p = '\0';
+
+               if((*line == '\0') || (*line == '#'))
+                       continue;
+
+               user_field = getfield(line);
+               if(EmptyString(user_field))
+                       continue;
+
+               host_field = getfield(NULL);
+               if(EmptyString(host_field))
+                       continue;
+
+               reason_field = getfield(NULL);
+               if(EmptyString(reason_field))
+                       continue;
+
+               operreason_field = getfield(NULL);
+
+               aconf = make_conf();
+               aconf->status = CONF_KILL;
+               conf_add_fields(aconf, host_field, reason_field,
+                               user_field, operreason_field);
+
+               if(aconf->host != NULL)
+                       add_conf_by_address(aconf->host, CONF_KILL, aconf->user, aconf);
+       }
+}
+
+/*
+ * parse_d_file
+ * Inputs       - pointer to line to parse
+ * Output       - NONE
+ * Side Effects - Parse one new style D line
+ */
+
+void
+parse_d_file(FILE * file)
+{
+       struct ConfItem *aconf;
+       char *reason_field = NULL;
+       char *host_field = NULL;
+       char *operreason_field = NULL;
+       char line[BUFSIZE];
+       char *p;
+
+       while (fgets(line, sizeof(line), file))
+       {
+               if((p = strchr(line, '\n')))
+                       *p = '\0';
+
+               if((*line == '\0') || (line[0] == '#'))
+                       continue;
+
+               host_field = getfield(line);
+               if(EmptyString(host_field))
+                       continue;
+
+               reason_field = getfield(NULL);
+               if(EmptyString(reason_field))
+                       continue;
+
+               operreason_field = getfield(NULL);
+
+               aconf = make_conf();
+               aconf->status = CONF_DLINE;
+               conf_add_fields(aconf, host_field, reason_field, "", operreason_field);
+               conf_add_d_conf(aconf);
+       }
+}
+
+void
+parse_x_file(FILE * file)
+{
+       struct ConfItem *aconf;
+       char *gecos_field = NULL;
+       char *reason_field = NULL;
+       char line[BUFSIZE];
+       char *p;
+
+       while (fgets(line, sizeof(line), file))
+       {
+               if((p = strchr(line, '\n')))
+                       *p = '\0';
+
+               if((*line == '\0') || (line[0] == '#'))
+                       continue;
+
+               gecos_field = getfield(line);
+               if(EmptyString(gecos_field))
+                       continue;
+
+               /* field for xline types, which no longer exist */
+               getfield(NULL);
+
+               reason_field = getfield(NULL);
+               if(EmptyString(reason_field))
+                       continue;
+
+               /* sanity checking */
+               if((find_xline(gecos_field, 0) != NULL) ||
+                  (strchr(reason_field, ':') != NULL))
+                       continue;
+
+               aconf = make_conf();
+               aconf->status = CONF_XLINE;
+
+               DupString(aconf->name, gecos_field);
+               DupString(aconf->passwd, reason_field);
+
+               dlinkAddAlloc(aconf, &xline_conf_list);
+       }
+}
+
+void
+parse_resv_file(FILE * file)
+{
+       struct ConfItem *aconf;
+       char *reason_field;
+       char *host_field;
+       char line[BUFSIZE];
+       char *p;
+
+       while (fgets(line, sizeof(line), file))
+       {
+               if((p = strchr(line, '\n')))
+                       *p = '\0';
+
+               if((*line == '\0') || (line[0] == '#'))
+                       continue;
+
+               host_field = getfield(line);
+               if(EmptyString(host_field))
+                       continue;
+
+               reason_field = getfield(NULL);
+               if(EmptyString(reason_field))
+                       continue;
+
+               if(IsChannelName(host_field))
+               {
+                       if(hash_find_resv(host_field))
+                               continue;
+
+                       aconf = make_conf();
+                       aconf->status = CONF_RESV_CHANNEL;
+                       aconf->port = 0;
+
+                       DupString(aconf->name, host_field);
+                       DupString(aconf->passwd, reason_field);
+                       add_to_resv_hash(aconf->name, aconf);
+               }
+               else if(clean_resv_nick(host_field))
+               {
+                       if(find_nick_resv(host_field))
+                               continue;
+
+                       aconf = make_conf();
+                       aconf->status = CONF_RESV_NICK;
+                       aconf->port = 0;
+
+                       DupString(aconf->name, host_field);
+                       DupString(aconf->passwd, reason_field);
+                       dlinkAddAlloc(aconf, &resv_conf_list);
+               }
+       }
+}
+
+/*
+ * getfield
+ *
+ * inputs      - input buffer
+ * output      - next field
+ * side effects        - field breakup for ircd.conf file.
+ */
+char *
+getfield(char *newline)
+{
+       static char *line = NULL;
+       char *end, *field;
+
+       if(newline != NULL)
+               line = newline;
+
+       if(line == NULL)
+               return (NULL);
+
+       field = line;
+
+       /* XXX make this skip to first " if present */
+       if(*field == '"')
+               field++;
+       else
+               return (NULL);  /* mal-formed field */
+
+       end = strchr(line, ',');
+
+       while(1)
+       {
+               /* no trailing , - last field */
+               if(end == NULL)
+               {
+                       end = line + strlen(line);
+                       line = NULL;
+
+                       if(*end == '"')
+                       {
+                               *end = '\0';
+                               return field;
+                       }
+                       else
+                               return NULL;
+               }
+               else
+               {
+                       /* look for a ", to mark the end of a field.. */
+                       if(*(end - 1) == '"')
+                       {
+                               line = end + 1;
+                               end--;
+                               *end = '\0';
+                               return field;
+                       }
+
+                       /* search for the next ',' */
+                       end++;
+                       end = strchr(end, ',');
+               }
+       }
+
+       return NULL;
+}
diff --git a/src/listener.c b/src/listener.c
new file mode 100644 (file)
index 0000000..7ed9a69
--- /dev/null
@@ -0,0 +1,584 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  listener.c: Listens on a port.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: listener.c 1675 2006-06-15 22:32:23Z jilles $
+ */
+
+#include "stdinc.h"
+#include "setup.h"
+#include "listener.h"
+#include "client.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "ircd_defs.h"
+#include "numeric.h"
+#include "commio.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "s_stats.h"
+#include "send.h"
+#include "memory.h"
+#include "s_auth.h"
+#include "reject.h"
+
+#ifndef INADDR_NONE
+#define INADDR_NONE ((unsigned int) 0xffffffff)
+#endif
+
+#if defined(NO_IN6ADDR_ANY) && defined(IPV6)
+static const struct in6_addr in6addr_any =
+{ { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } };
+#endif 
+
+static PF accept_connection;
+
+static listener_t *ListenerPollList = NULL;
+
+static listener_t *
+make_listener(struct irc_sockaddr_storage *addr)
+{
+       listener_t *listener = (listener_t *) MyMalloc(sizeof(listener_t));
+       s_assert(0 != listener);
+
+       listener->name = me.name;
+       listener->fd = -1;
+       memcpy(&listener->addr, addr, sizeof(struct irc_sockaddr_storage));
+       listener->next = NULL;
+       return listener;
+}
+
+void
+free_listener(listener_t *listener)
+{
+       s_assert(NULL != listener);
+       if(listener == NULL)
+               return;
+       /*
+        * remove from listener list
+        */
+       if(listener == ListenerPollList)
+               ListenerPollList = listener->next;
+       else
+       {
+               listener_t *prev = ListenerPollList;
+               for (; prev; prev = prev->next)
+               {
+                       if(listener == prev->next)
+                       {
+                               prev->next = listener->next;
+                               break;
+                       }
+               }
+       }
+
+       /* free */
+       MyFree(listener);
+}
+
+#define PORTNAMELEN 6          /* ":31337" */
+
+/*
+ * get_listener_name - return displayable listener name and port
+ * returns "host.foo.org:6667" for a given listener
+ */
+const char *
+get_listener_name(const listener_t *listener)
+{
+       static char buf[HOSTLEN + HOSTLEN + PORTNAMELEN + 4];
+       int port = 0;
+
+       s_assert(NULL != listener);
+       if(listener == NULL)
+               return NULL;
+
+#ifdef IPV6
+       if(listener->addr.ss_family == AF_INET6)
+               port = ntohs(((const struct sockaddr_in6 *)&listener->addr)->sin6_port);
+       else
+#endif
+               port = ntohs(((const struct sockaddr_in *)&listener->addr)->sin_port);  
+
+       ircsnprintf(buf, sizeof(buf), "%s[%s/%u]", me.name, listener->name, port);
+       return buf;
+}
+
+/*
+ * show_ports - send port listing to a client
+ * inputs       - pointer to client to show ports to
+ * output       - none
+ * side effects - show ports
+ */
+void
+show_ports(struct Client *source_p)
+{
+       listener_t *listener = 0;
+
+       for (listener = ListenerPollList; listener; listener = listener->next)
+       {
+               sendto_one_numeric(source_p, RPL_STATSPLINE, 
+                                  form_str(RPL_STATSPLINE), 'P',
+#ifdef IPV6
+                          ntohs(listener->addr.ss_family == AF_INET ? ((struct sockaddr_in *)&listener->addr)->sin_port :
+                                ((struct sockaddr_in6 *)&listener->addr)->sin6_port),
+#else
+                          ntohs(((struct sockaddr_in *)&listener->addr)->sin_port),
+#endif
+                          IsOperAdmin(source_p) ? listener->name : me.name,
+                          listener->ref_count, (listener->active) ? "active" : "disabled");
+       }
+}
+
+/*
+ * inetport - create a listener socket in the AF_INET or AF_INET6 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 RATBOX_SOMAXCONN
+ */
+#ifdef SOMAXCONN
+#undef RATBOX_SOMAXCONN
+#define RATBOX_SOMAXCONN SOMAXCONN
+#endif
+
+static int
+inetport(listener_t *listener)
+{
+       int fd;
+       int opt = 1;
+
+       /*
+        * At first, open a new socket
+        */
+       
+       fd = comm_socket(listener->addr.ss_family, SOCK_STREAM, 0, "Listener socket");
+
+#ifdef IPV6
+       if(listener->addr.ss_family == AF_INET6)
+       {
+               struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&listener->addr;
+               if(!IN6_ARE_ADDR_EQUAL(&in6->sin6_addr, &in6addr_any))
+               {
+                       inetntop(AF_INET6, &in6->sin6_addr, listener->vhost, sizeof(listener->vhost));
+                       listener->name = listener->vhost;
+               }
+       } else
+#endif
+       {
+               struct sockaddr_in *in = (struct sockaddr_in *)&listener->addr;
+               if(in->sin_addr.s_addr != INADDR_ANY)
+               {
+                       inetntop(AF_INET, &in->sin_addr, listener->vhost, sizeof(listener->vhost));
+                       listener->name = listener->vhost;
+               }       
+       }
+
+
+       if(fd == -1)
+       {
+               report_error("opening listener socket %s:%s",
+                            get_listener_name(listener), 
+                            get_listener_name(listener), errno);
+               return 0;
+       }
+       else if((HARD_FDLIMIT - 10) < fd)
+       {
+               report_error("no more connections left for listener %s:%s",
+                            get_listener_name(listener), 
+                            get_listener_name(listener), errno);
+               comm_close(fd);
+               return 0;
+       }
+       /*
+        * XXX - we don't want to do all this crap for a listener
+        * set_sock_opts(listener);
+        */
+       if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof(opt)))
+       {
+               report_error("setting SO_REUSEADDR for listener %s:%s",
+                            get_listener_name(listener), 
+                            get_listener_name(listener), errno);
+               comm_close(fd);
+               return 0;
+       }
+
+       /*
+        * Bind a port to listen for new connections if port is non-null,
+        * else assume it is already open and try get something from it.
+        */
+
+       if(bind(fd, (struct sockaddr *) &listener->addr, GET_SS_LEN(listener->addr)))
+       {
+               report_error("binding listener socket %s:%s",
+                            get_listener_name(listener), 
+                            get_listener_name(listener), errno);
+               comm_close(fd);
+               return 0;
+       }
+
+       if(listen(fd, RATBOX_SOMAXCONN))
+       {
+               report_error("listen failed for %s:%s", 
+                            get_listener_name(listener), 
+                            get_listener_name(listener), errno);
+               comm_close(fd);
+               return 0;
+       }
+
+       listener->fd = fd;
+
+       /* Listen completion events are READ events .. */
+
+       accept_connection(fd, listener);
+       return 1;
+}
+
+static listener_t *
+find_listener(struct irc_sockaddr_storage *addr)
+{
+       listener_t *listener = NULL;
+       listener_t *last_closed = NULL;
+
+       for (listener = ListenerPollList; listener; listener = listener->next)
+       {
+               if(addr->ss_family != listener->addr.ss_family)
+                       continue;
+               
+               switch(addr->ss_family)
+               {
+                       case AF_INET:
+                       {
+                               struct sockaddr_in *in4 = (struct sockaddr_in *)addr;
+                               struct sockaddr_in *lin4 = (struct sockaddr_in *)&listener->addr;
+                               if(in4->sin_addr.s_addr == lin4->sin_addr.s_addr && 
+                                       in4->sin_port == lin4->sin_port )
+                               {
+                                       if(listener->fd == -1)
+                                               last_closed = listener;
+                                       else
+                                               return(listener);
+                               }
+                               break;
+                       }
+#ifdef IPV6
+                       case AF_INET6:
+                       {
+                               struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr;
+                               struct sockaddr_in6 *lin6 =(struct sockaddr_in6 *)&listener->addr;
+                               if(IN6_ARE_ADDR_EQUAL(&in6->sin6_addr, &lin6->sin6_addr) &&
+                                 in6->sin6_port == lin6->sin6_port)
+                               {
+                                       if(listener->fd == -1)
+                                               last_closed = listener;
+                                       else
+                                               return(listener);
+                               }
+                               break;
+                               
+                       }
+#endif
+
+                       default:
+                               break;
+               }
+       }
+       return last_closed;
+}
+
+
+/*
+ * add_listener- create a new listener
+ * port - the port number to listen on
+ * vhost_ip - if non-null must contain a valid IP address string in
+ * the format "255.255.255.255"
+ */
+void
+add_listener(int port, const char *vhost_ip, int family)
+{
+       listener_t *listener;
+       struct irc_sockaddr_storage vaddr;
+
+       /*
+        * if no port in conf line, don't bother
+        */
+       if(port == 0)
+               return;
+       memset(&vaddr, 0, sizeof(vaddr));
+       vaddr.ss_family = family;
+
+       if(vhost_ip != NULL)
+       {
+               if(family == AF_INET)
+               {
+                       if(inetpton(family, vhost_ip, &((struct sockaddr_in *)&vaddr)->sin_addr) <= 0)
+                               return;
+               } 
+#ifdef IPV6
+               else
+               {
+                       if(inetpton(family, vhost_ip, &((struct sockaddr_in6 *)&vaddr)->sin6_addr) <= 0)
+                               return;
+               
+               }
+#endif
+       } else
+       {
+               switch(family)
+               {
+                       case AF_INET:
+                               ((struct sockaddr_in *)&vaddr)->sin_addr.s_addr = INADDR_ANY;
+                               break;
+#ifdef IPV6
+                       case AF_INET6:
+                               memcpy(&((struct sockaddr_in6 *)&vaddr)->sin6_addr, &in6addr_any, sizeof(struct in6_addr));
+                               break;
+                       default:
+                               return;
+#endif
+               } 
+       }
+       switch(family)
+       {
+               case AF_INET:
+                       SET_SS_LEN(vaddr, sizeof(struct sockaddr_in));
+                       ((struct sockaddr_in *)&vaddr)->sin_port = htons(port);
+                       break;
+#ifdef IPV6
+               case AF_INET6:
+                       SET_SS_LEN(vaddr, sizeof(struct sockaddr_in6));
+                       ((struct sockaddr_in6 *)&vaddr)->sin6_port = htons(port);
+                       break;
+#endif
+               default:
+                       break;
+       }
+       if((listener = find_listener(&vaddr)))
+       {
+               if(listener->fd > -1)
+                       return;
+       }
+       else
+       {
+               listener = make_listener(&vaddr);
+               listener->next = ListenerPollList;
+               ListenerPollList = listener;
+       }
+
+       listener->fd = -1;
+
+       if(inetport(listener))
+               listener->active = 1;
+       else
+               close_listener(listener);
+}
+
+/*
+ * close_listener - close a single listener
+ */
+void
+close_listener(listener_t *listener)
+{
+       s_assert(listener != NULL);
+       if(listener == NULL)
+               return;
+       if(listener->fd >= 0)
+       {
+               comm_close(listener->fd);
+               listener->fd = -1;
+       }
+
+       listener->active = 0;
+
+       if(listener->ref_count)
+               return;
+
+       free_listener(listener);
+}
+
+/*
+ * close_listeners - close and free all listeners that are not being used
+ */
+void
+close_listeners()
+{
+       listener_t *listener;
+       listener_t *listener_next = 0;
+       /*
+        * close all 'extra' listening ports we have
+        */
+       for (listener = ListenerPollList; listener; listener = listener_next)
+       {
+               listener_next = listener->next;
+               close_listener(listener);
+       }
+}
+
+#define DLINE_WARNING "ERROR :You have been D-lined.\r\n"
+
+/*
+ * add_connection - 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 sent to the auth module for verification, and not put in
+ * any client list yet.
+ */
+static void
+add_connection(listener_t *listener, int fd, struct sockaddr *sai)
+{
+       struct Client *new_client;
+       s_assert(NULL != listener);
+
+       /* 
+        * get the client socket name from the socket
+        * the client has already been checked out in accept_connection
+        */
+       new_client = make_client(NULL);
+
+       memcpy(&new_client->localClient->ip, sai, sizeof(struct irc_sockaddr_storage));
+
+       /* 
+        * copy address to 'sockhost' as a string, copy it to host too
+        * so we have something valid to put into error messages...
+        */
+       inetntop_sock((struct sockaddr *)&new_client->localClient->ip, new_client->sockhost, 
+               sizeof(new_client->sockhost));
+
+
+       strlcpy(new_client->host, new_client->sockhost, sizeof(new_client->host));
+
+#ifdef IPV6
+       if(new_client->localClient->ip.ss_family == AF_INET6 && ConfigFileEntry.dot_in_ip6_addr == 1)
+       {
+               strlcat(new_client->host, ".", sizeof(new_client->host));
+       }
+#endif
+
+       new_client->localClient->fd = fd;
+
+       new_client->localClient->listener = listener;
+       ++listener->ref_count;
+
+       if(check_reject(new_client))
+               return; 
+       start_auth(new_client);
+}
+
+
+static void
+accept_connection(int pfd, void *data)
+{
+       static time_t last_oper_notice = 0;
+
+       struct irc_sockaddr_storage sai;
+       socklen_t addrlen = sizeof(sai);
+       int fd;
+       listener_t *listener = data;
+    struct ConfItem *aconf;
+    char buf[BUFSIZE];
+    
+       s_assert(listener != NULL);
+       if(listener == NULL)
+               return;
+       /*
+        * 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.
+        */
+
+       fd = comm_accept(listener->fd, (struct sockaddr *)&sai, &addrlen);
+       if(fd < 0)
+       {
+               /* Re-register a new IO request for the next accept .. */
+               comm_setselect(listener->fd, FDLIST_SERVICE,
+                              COMM_SELECT_READ, accept_connection, listener, 0);
+               return;
+       }
+
+       /* This needs to be done here, otherwise we break dlines */
+       mangle_mapped_sockaddr((struct sockaddr *)&sai);
+
+       /*
+        * check for connection limit
+        */
+       if((MAXCONNECTIONS - 10) < fd)
+       {
+               ++ServerStats->is_ref;
+               /*
+                * slow down the whining to opers bit
+                */
+               if((last_oper_notice + 20) <= CurrentTime)
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "All connections in use. (%s)",
+                                            get_listener_name(listener));
+                       last_oper_notice = CurrentTime;
+               }
+
+               write(fd, "ERROR :All connections in use\r\n", 32);
+               comm_close(fd);
+               /* Re-register a new IO request for the next accept .. */
+               comm_setselect(listener->fd, FDLIST_SERVICE,
+                              COMM_SELECT_READ, accept_connection, listener, 0);
+               return;
+       }
+
+       /* Do an initial check we aren't connecting too fast or with too many
+        * from this IP... */
+       if((aconf = conf_connect_allowed((struct sockaddr *)&sai, sai.ss_family)) != NULL)
+       {
+               ServerStats->is_ref++;
+
+        if(ConfigFileEntry.dline_with_reason)
+        {
+            if (ircsnprintf(buf, sizeof(buf), "ERROR :*** Banned: %s\r\n", aconf->passwd) >= (sizeof(buf)-1))
+            {
+                buf[sizeof(buf) - 3] = '\r';
+                buf[sizeof(buf) - 2] = '\n';
+                buf[sizeof(buf) - 1] = '\0';
+            }
+        }
+        else
+           ircsprintf(buf, "ERROR :You have been D-lined.\r\n");
+        
+        write(fd, buf, strlen(buf));
+               comm_close(fd);
+
+               /* Re-register a new IO request for the next accept .. */
+               comm_setselect(listener->fd, FDLIST_SERVICE,
+                              COMM_SELECT_READ, accept_connection, listener, 0);
+               return;
+       }
+
+       ServerStats->is_ac++;
+       add_connection(listener, fd, (struct sockaddr *)&sai);
+
+       /* Re-register a new IO request for the next accept .. */
+       comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ,
+                      accept_connection, listener, 0);
+}
diff --git a/src/match.c b/src/match.c
new file mode 100644 (file)
index 0000000..6b13f82
--- /dev/null
@@ -0,0 +1,816 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, src/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.
+ *
+ * $Id: match.c 708 2006-02-05 22:44:03Z jilles $
+ *
+ */
+#include "stdinc.h"
+#include "config.h"
+#include "client.h"
+#include "ircd.h"
+#include "irc_string.h"
+
+/*
+ * 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  1, if match
+ *         0, 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.
+ *
+ * @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;
+
+       s_assert(mask != NULL);
+       s_assert(name != NULL);
+
+       for (;;)
+       {
+               switch (*m)
+               {
+                 case '\0':
+                         if (!*n)
+                                 return 1;
+                 backtrack:
+                         if (m_tmp == mask)
+                                 return 0;
+                         m = m_tmp;
+                         n = ++n_tmp;
+                         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 1;
+                                 else
+                                 {
+                                         m_tmp = m;
+                                         for (n_tmp = n; *n && ToLower(*n) != ToLower(*m); n++);
+                                 }
+                         }
+                         /* and fall through */
+                 default:
+                         if (!*n)
+                                 return (*m != '\0' ? 0 : 1);
+                         if (ToLower(*m) != ToLower(*n))
+                                 goto backtrack;
+                         m++;
+                         n++;
+                         break;
+               }
+       }
+}
+
+/** 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; '#' means match exactly one character
+ * that is a number.
+ *
+ * This function supports escaping, 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_esc(const char *mask, const char *name)
+{
+       const char *m = mask, *n = name;
+       const char *m_tmp = mask, *n_tmp = name;
+       int star_p;
+
+       s_assert(mask != NULL);
+       s_assert(name != NULL);
+
+       for (;;)
+       {
+               switch (*m)
+               {
+                 case '\0':
+                         if (!*n)
+                                 return 1;
+                 backtrack:
+                         if (m_tmp == mask)
+                                 return 0;
+                         m = m_tmp;
+                         n = ++n_tmp;
+                         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 1;
+                                 else if (*m == '\\')
+                                 {
+                                         m_tmp = ++m;
+                                         if (!*m)
+                                                 return 0;
+                                         for (n_tmp = n; *n && *n != *m; n++);
+                                 }
+                                 else if (*m == '#')
+                                 {
+                                         m_tmp = m;
+                                         for (n_tmp = n; *n && !IsDigit(*n); n++);
+                                 }
+                                 else if (*m == '@')
+                                 {
+                                         m_tmp = m;
+                                         for (n_tmp = n; *n && !IsLetter(*n); n++);
+                                 }
+                                 else
+                                 {
+                                         m_tmp = m;
+                                         for (n_tmp = n; *n && ToLower(*n) != ToLower(*m); n++);
+                                 }
+                         }
+                         /* and fall through */
+                 default:
+                         if (!*n)
+                                 return (*m != '\0' ? 0 : 1);
+                         if (*m == '#')
+                         {
+                                 if (!IsDigit(*n))
+                                       goto backtrack;
+                         }
+                         else if (*m == '@')
+                         {
+                                 if (!IsLetter(*n))
+                                       goto backtrack;
+                         }
+                         else if (ToLower(*m) != ToLower(*n))
+                                 goto backtrack;
+                         m++;
+                         n++;
+                         break;
+               }
+       }
+}
+
+int comp_with_mask(void *addr, void *dest, u_int mask)
+{
+       if (memcmp(addr, dest, mask / 8) == 0)
+       {
+               int n = mask / 8;
+               int m = ((-1) << (8 - (mask % 8)));
+               if (mask % 8 == 0 || (((u_char *) addr)[n] & m) == (((u_char *) dest)[n] & m))
+               {
+                       return (1);
+               }
+       }
+       return (0);
+}
+
+int comp_with_mask_sock(struct sockaddr *addr, struct sockaddr *dest, u_int mask)
+{
+       void *iaddr = NULL;
+       void *idest = NULL;
+
+       if (addr->sa_family == AF_INET)
+       {
+               iaddr = &((struct sockaddr_in *)addr)->sin_addr;
+               idest = &((struct sockaddr_in *)dest)->sin_addr;
+       }
+#ifdef IPV6
+       else
+       {
+               iaddr = &((struct sockaddr_in6 *)addr)->sin6_addr;
+               idest = &((struct sockaddr_in6 *)dest)->sin6_addr;
+
+       }
+#endif
+
+       return (comp_with_mask(iaddr, idest, mask));
+}
+
+/*
+ * match_ips()
+ *
+ * Input - cidr ip mask, address
+ */
+int match_ips(const char *s1, const char *s2)
+{
+       struct irc_sockaddr_storage ipaddr, maskaddr;
+       char mask[BUFSIZE];
+       char address[HOSTLEN + 1];
+       char *len;
+       void *ipptr, *maskptr;
+       int cidrlen, aftype;
+
+       strcpy(mask, s1);
+       strcpy(address, s2);
+
+       len = strrchr(mask, '/');
+       if (len == NULL)
+               return 0;
+
+       *len++ = '\0';
+
+       cidrlen = atoi(len);
+       if (cidrlen == 0)
+               return 0;
+
+#ifdef IPV6
+       if (strchr(mask, ':') && strchr(address, ':'))
+       {
+               aftype = AF_INET6;
+               ipptr = &((struct sockaddr_in6 *)&ipaddr)->sin6_addr;
+               maskptr = &((struct sockaddr_in6 *)&maskaddr)->sin6_addr;
+       }
+       else
+#endif
+       if (!strchr(mask, ':') && !strchr(address, ':'))
+       {
+               aftype = AF_INET;
+               ipptr = &((struct sockaddr_in *)&ipaddr)->sin_addr;
+               maskptr = &((struct sockaddr_in *)&maskaddr)->sin_addr;
+       }
+       else
+               return 0;
+
+       inetpton(aftype, address, ipptr);
+       inetpton(aftype, mask, maskptr);
+       if (comp_with_mask(ipptr, maskptr, cidrlen))
+               return 1;
+       else
+               return 0;
+}
+
+/* match_cidr()
+ *
+ * Input - mask, address
+ * Ouput - 1 = Matched 0 = Did not match
+ */
+
+int match_cidr(const char *s1, const char *s2)
+{
+       struct irc_sockaddr_storage ipaddr, maskaddr;
+       char mask[BUFSIZE];
+       char address[NICKLEN + USERLEN + HOSTLEN + 6];
+       char *ipmask;
+       char *ip;
+       char *len;
+       void *ipptr, *maskptr;
+       int cidrlen, aftype;
+
+       strcpy(mask, s1);
+       strcpy(address, s2);
+
+       ipmask = strrchr(mask, '@');
+       if (ipmask == NULL)
+               return 0;
+
+       *ipmask++ = '\0';
+
+       ip = strrchr(address, '@');
+       if (ip == NULL)
+               return 0;
+       *ip++ = '\0';
+
+
+       len = strrchr(ipmask, '/');
+       if (len == NULL)
+               return 0;
+
+       *len++ = '\0';
+
+       cidrlen = atoi(len);
+       if (cidrlen == 0)
+               return 0;
+
+#ifdef IPV6
+       if (strchr(ip, ':') && strchr(ipmask, ':'))
+       {
+               aftype = AF_INET6;
+               ipptr = &((struct sockaddr_in6 *)&ipaddr)->sin6_addr;
+               maskptr = &((struct sockaddr_in6 *)&maskaddr)->sin6_addr;
+       }
+       else
+#endif
+       if (!strchr(ip, ':') && !strchr(ipmask, ':'))
+       {
+               aftype = AF_INET;
+               ipptr = &((struct sockaddr_in *)&ipaddr)->sin_addr;
+               maskptr = &((struct sockaddr_in *)&maskaddr)->sin_addr;
+       }
+       else
+               return 0;
+
+       inetpton(aftype, ip, ipptr);
+       inetpton(aftype, ipmask, maskptr);
+       if (comp_with_mask(ipptr, maskptr, cidrlen) && match(mask, address))
+               return 1;
+       else
+               return 0;
+}
+
+/* collapse()
+ *
+ * collapses a string containing multiple *'s.
+ */
+char *collapse(char *pattern)
+{
+       char *p = pattern, *po = pattern;
+       char c;
+       int f = 0;
+
+       if (p == NULL)
+               return NULL;
+
+       while ((c = *p++))
+       {
+               if (c == '*')
+               {
+                       if (!(f & 1))
+                               *po++ = '*';
+                       f |= 1;
+               }
+               else
+               {
+                       *po++ = c;
+                       f &= ~1;
+               }
+       }
+       *po++ = 0;
+
+       return pattern;
+}
+
+/* collapse_esc()
+ *
+ * The collapse() function with support for escaping characters
+ */
+char *collapse_esc(char *pattern)
+{
+       char *p = pattern, *po = pattern;
+       char c;
+       int f = 0;
+
+       if (p == NULL)
+               return NULL;
+
+       while ((c = *p++))
+       {
+               if (!(f & 2) && c == '*')
+               {
+                       if (!(f & 1))
+                               *po++ = '*';
+                       f |= 1;
+               }
+               else if (!(f & 2) && c == '\\')
+               {
+                       *po++ = '\\';
+                       f |= 2;
+               }
+               else
+               {
+                       *po++ = c;
+                       f &= ~3;
+               }
+       }
+       *po++ = 0;
+       return pattern;
+}
+
+/*
+ * irccmp - case insensitive comparison of two 0 terminated strings.
+ *
+ *      returns  0, if s1 equal to s2
+ *              <0, if s1 lexicographically less than s2
+ *              >0, if s1 lexicographically greater than s2
+ */
+int irccmp(const char *s1, const char *s2)
+{
+       const unsigned char *str1 = (const unsigned char *)s1;
+       const unsigned char *str2 = (const unsigned char *)s2;
+       int res;
+
+       s_assert(s1 != NULL);
+       s_assert(s2 != NULL);
+
+       while ((res = ToUpper(*str1) - ToUpper(*str2)) == 0)
+       {
+               if (*str1 == '\0')
+                       return 0;
+               str1++;
+               str2++;
+       }
+       return (res);
+}
+
+int ircncmp(const char *s1, const char *s2, int n)
+{
+       const unsigned char *str1 = (const unsigned char *)s1;
+       const unsigned char *str2 = (const unsigned char *)s2;
+       int res;
+       s_assert(s1 != NULL);
+       s_assert(s2 != NULL);
+
+       while ((res = ToUpper(*str1) - ToUpper(*str2)) == 0)
+       {
+               str1++;
+               str2++;
+               n--;
+               if (n == 0 || (*str1 == '\0' && *str2 == '\0'))
+                       return 0;
+       }
+       return (res);
+}
+
+const unsigned char ToLowerTab[] = {
+       0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
+       0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,
+       0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+       0x1e, 0x1f,
+       ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')',
+       '*', '+', ',', '-', '.', '/',
+       '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+       ':', ';', '<', '=', '>', '?',
+       '@', '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', '{', '|', '}', '~',
+       0x7f,
+       0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+       0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+       0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+       0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+       0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
+       0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+       0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
+       0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+       0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
+       0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+       0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
+       0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+       0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+       0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+       0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
+       0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+const unsigned char ToUpperTab[] = {
+       0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
+       0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,
+       0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+       0x1e, 0x1f,
+       ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')',
+       '*', '+', ',', '-', '.', '/',
+       '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+       ':', ';', '<', '=', '>', '?',
+       '@', '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', '[', '\\', ']', '^',
+       0x5f,
+       '`', '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', '[', '\\', ']', '^',
+       0x7f,
+       0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+       0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+       0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+       0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+       0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
+       0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+       0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
+       0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+       0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
+       0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+       0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
+       0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+       0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+       0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+       0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
+       0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+/*
+ * CharAttrs table
+ *
+ * NOTE: RFC 1459 sez: anything but a ^G, comma, or space is allowed
+ * for channel names
+ */
+const unsigned int CharAttrs[] = {
+/* 0  */ CNTRL_C,
+/* 1  */ CNTRL_C | CHAN_C | NONEOS_C,
+/* 2  */ CNTRL_C | CHAN_C | FCHAN_C | NONEOS_C,
+/* 3  */ CNTRL_C | CHAN_C | FCHAN_C | NONEOS_C,
+/* 4  */ CNTRL_C | CHAN_C | NONEOS_C,
+/* 5  */ CNTRL_C | CHAN_C | NONEOS_C,
+/* 6  */ CNTRL_C | CHAN_C | NONEOS_C,
+/* 7 BEL */ CNTRL_C | NONEOS_C,
+/* 8  \b */ CNTRL_C | CHAN_C | NONEOS_C,
+/* 9  \t */ CNTRL_C | SPACE_C | CHAN_C | NONEOS_C,
+/* 10 \n */ CNTRL_C | SPACE_C | CHAN_C | NONEOS_C | EOL_C,
+/* 11 \v */ CNTRL_C | SPACE_C | CHAN_C | NONEOS_C,
+/* 12 \f */ CNTRL_C | SPACE_C | CHAN_C | NONEOS_C,
+/* 13 \r */ CNTRL_C | SPACE_C | CHAN_C | NONEOS_C | EOL_C,
+/* 14 */ CNTRL_C | CHAN_C | NONEOS_C,
+/* 15 */ CNTRL_C | CHAN_C | NONEOS_C,
+/* 16 */ CNTRL_C | CHAN_C | NONEOS_C,
+/* 17 */ CNTRL_C | CHAN_C | NONEOS_C,
+/* 18 */ CNTRL_C | CHAN_C | NONEOS_C,
+/* 19 */ CNTRL_C | CHAN_C | NONEOS_C,
+/* 20 */ CNTRL_C | CHAN_C | NONEOS_C,
+/* 21 */ CNTRL_C | CHAN_C | NONEOS_C,
+/* 22 */ CNTRL_C | CHAN_C | FCHAN_C | NONEOS_C,
+/* 23 */ CNTRL_C | CHAN_C | NONEOS_C,
+/* 24 */ CNTRL_C | CHAN_C | NONEOS_C,
+/* 25 */ CNTRL_C | CHAN_C | NONEOS_C,
+/* 26 */ CNTRL_C | CHAN_C | NONEOS_C,
+/* 27 */ CNTRL_C | CHAN_C | NONEOS_C,
+/* 28 */ CNTRL_C | CHAN_C | NONEOS_C,
+/* 29 */ CNTRL_C | CHAN_C | NONEOS_C,
+/* 30 */ CNTRL_C | CHAN_C | NONEOS_C,
+/* 31 */ CNTRL_C | CHAN_C | FCHAN_C | NONEOS_C,
+/* SP */ PRINT_C | SPACE_C,
+/* ! */ PRINT_C | KWILD_C | CHAN_C | NONEOS_C,
+/* " */ PRINT_C | CHAN_C | NONEOS_C,
+/* # */ PRINT_C | MWILD_C | CHANPFX_C | CHAN_C | NONEOS_C,
+/* $ */ PRINT_C | CHAN_C | NONEOS_C | USER_C,
+/* % */ PRINT_C | CHAN_C | NONEOS_C,
+/* & */ PRINT_C | CHANPFX_C | CHAN_C | NONEOS_C,
+/* ' */ PRINT_C | CHAN_C | NONEOS_C,
+/* ( */ PRINT_C | CHAN_C | NONEOS_C,
+/* ) */ PRINT_C | CHAN_C | NONEOS_C,
+/* * */ PRINT_C | KWILD_C | MWILD_C | CHAN_C | NONEOS_C | SERV_C,
+/* + */ PRINT_C | CHAN_C | NONEOS_C,
+/* , */ PRINT_C | NONEOS_C,
+/* - */ PRINT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* . */ PRINT_C | KWILD_C | CHAN_C | NONEOS_C | USER_C | HOST_C | SERV_C,
+/* / */ PRINT_C | CHAN_C | NONEOS_C,
+/* 0 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* 1 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* 2 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* 3 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* 4 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* 5 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* 6 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* 7 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* 8 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* 9 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* : */ PRINT_C | CHAN_C | NONEOS_C | HOST_C,
+/* ; */ PRINT_C | CHAN_C | NONEOS_C,
+/* < */ PRINT_C | CHAN_C | NONEOS_C,
+/* = */ PRINT_C | CHAN_C | NONEOS_C,
+/* > */ PRINT_C | CHAN_C | NONEOS_C,
+/* ? */ PRINT_C | KWILD_C | MWILD_C | CHAN_C | NONEOS_C,
+/* @ */ PRINT_C | KWILD_C | MWILD_C | CHAN_C | NONEOS_C,
+/* A */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* B */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* C */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* D */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* E */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* F */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* G */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* H */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* I */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* J */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* K */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* L */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* M */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* N */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* O */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* P */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* Q */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* R */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* S */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* T */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* U */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* V */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* W */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* X */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* Y */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* Z */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* [ */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
+/* \ */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
+/* ] */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
+/* ^ */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
+/* _ */ PRINT_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
+/* ` */ PRINT_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
+/* a */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* b */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* c */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* d */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* e */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* f */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* g */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* h */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* i */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* j */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* k */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* l */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* m */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* n */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* o */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* p */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* q */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* r */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* s */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* t */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* u */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* v */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* w */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* x */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* y */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* z */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
+/* { */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
+/* | */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
+/* } */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
+/* ~ */ PRINT_C | ALPHA_C | CHAN_C | NONEOS_C | USER_C,
+/* del  */ CHAN_C | NONEOS_C,
+/* 0x80 */ CHAN_C | NONEOS_C,
+/* 0x81 */ CHAN_C | NONEOS_C,
+/* 0x82 */ CHAN_C | NONEOS_C,
+/* 0x83 */ CHAN_C | NONEOS_C,
+/* 0x84 */ CHAN_C | NONEOS_C,
+/* 0x85 */ CHAN_C | NONEOS_C,
+/* 0x86 */ CHAN_C | NONEOS_C,
+/* 0x87 */ CHAN_C | NONEOS_C,
+/* 0x88 */ CHAN_C | NONEOS_C,
+/* 0x89 */ CHAN_C | NONEOS_C,
+/* 0x8A */ CHAN_C | NONEOS_C,
+/* 0x8B */ CHAN_C | NONEOS_C,
+/* 0x8C */ CHAN_C | NONEOS_C,
+/* 0x8D */ CHAN_C | NONEOS_C,
+/* 0x8E */ CHAN_C | NONEOS_C,
+/* 0x8F */ CHAN_C | NONEOS_C,
+/* 0x90 */ CHAN_C | NONEOS_C,
+/* 0x91 */ CHAN_C | NONEOS_C,
+/* 0x92 */ CHAN_C | NONEOS_C,
+/* 0x93 */ CHAN_C | NONEOS_C,
+/* 0x94 */ CHAN_C | NONEOS_C,
+/* 0x95 */ CHAN_C | NONEOS_C,
+/* 0x96 */ CHAN_C | NONEOS_C,
+/* 0x97 */ CHAN_C | NONEOS_C,
+/* 0x98 */ CHAN_C | NONEOS_C,
+/* 0x99 */ CHAN_C | NONEOS_C,
+/* 0x9A */ CHAN_C | NONEOS_C,
+/* 0x9B */ CHAN_C | NONEOS_C,
+/* 0x9C */ CHAN_C | NONEOS_C,
+/* 0x9D */ CHAN_C | NONEOS_C,
+/* 0x9E */ CHAN_C | NONEOS_C,
+/* 0x9F */ CHAN_C | NONEOS_C,
+/* 0xA0 */ CHAN_C | FCHAN_C | NONEOS_C,
+/* 0xA1 */ CHAN_C | NONEOS_C,
+/* 0xA2 */ CHAN_C | NONEOS_C,
+/* 0xA3 */ CHAN_C | NONEOS_C,
+/* 0xA4 */ CHAN_C | NONEOS_C,
+/* 0xA5 */ CHAN_C | NONEOS_C,
+/* 0xA6 */ CHAN_C | NONEOS_C,
+/* 0xA7 */ CHAN_C | NONEOS_C,
+/* 0xA8 */ CHAN_C | NONEOS_C,
+/* 0xA9 */ CHAN_C | NONEOS_C,
+/* 0xAA */ CHAN_C | NONEOS_C,
+/* 0xAB */ CHAN_C | NONEOS_C,
+/* 0xAC */ CHAN_C | NONEOS_C,
+/* 0xAD */ CHAN_C | NONEOS_C,
+/* 0xAE */ CHAN_C | NONEOS_C,
+/* 0xAF */ CHAN_C | NONEOS_C,
+/* 0xB0 */ CHAN_C | NONEOS_C,
+/* 0xB1 */ CHAN_C | NONEOS_C,
+/* 0xB2 */ CHAN_C | NONEOS_C,
+/* 0xB3 */ CHAN_C | NONEOS_C,
+/* 0xB4 */ CHAN_C | NONEOS_C,
+/* 0xB5 */ CHAN_C | NONEOS_C,
+/* 0xB6 */ CHAN_C | NONEOS_C,
+/* 0xB7 */ CHAN_C | NONEOS_C,
+/* 0xB8 */ CHAN_C | NONEOS_C,
+/* 0xB9 */ CHAN_C | NONEOS_C,
+/* 0xBA */ CHAN_C | NONEOS_C,
+/* 0xBB */ CHAN_C | NONEOS_C,
+/* 0xBC */ CHAN_C | NONEOS_C,
+/* 0xBD */ CHAN_C | NONEOS_C,
+/* 0xBE */ CHAN_C | NONEOS_C,
+/* 0xBF */ CHAN_C | NONEOS_C,
+/* 0xC0 */ CHAN_C | NONEOS_C,
+/* 0xC1 */ CHAN_C | NONEOS_C,
+/* 0xC2 */ CHAN_C | NONEOS_C,
+/* 0xC3 */ CHAN_C | NONEOS_C,
+/* 0xC4 */ CHAN_C | NONEOS_C,
+/* 0xC5 */ CHAN_C | NONEOS_C,
+/* 0xC6 */ CHAN_C | NONEOS_C,
+/* 0xC7 */ CHAN_C | NONEOS_C,
+/* 0xC8 */ CHAN_C | NONEOS_C,
+/* 0xC9 */ CHAN_C | NONEOS_C,
+/* 0xCA */ CHAN_C | NONEOS_C,
+/* 0xCB */ CHAN_C | NONEOS_C,
+/* 0xCC */ CHAN_C | NONEOS_C,
+/* 0xCD */ CHAN_C | NONEOS_C,
+/* 0xCE */ CHAN_C | NONEOS_C,
+/* 0xCF */ CHAN_C | NONEOS_C,
+/* 0xD0 */ CHAN_C | NONEOS_C,
+/* 0xD1 */ CHAN_C | NONEOS_C,
+/* 0xD2 */ CHAN_C | NONEOS_C,
+/* 0xD3 */ CHAN_C | NONEOS_C,
+/* 0xD4 */ CHAN_C | NONEOS_C,
+/* 0xD5 */ CHAN_C | NONEOS_C,
+/* 0xD6 */ CHAN_C | NONEOS_C,
+/* 0xD7 */ CHAN_C | NONEOS_C,
+/* 0xD8 */ CHAN_C | NONEOS_C,
+/* 0xD9 */ CHAN_C | NONEOS_C,
+/* 0xDA */ CHAN_C | NONEOS_C,
+/* 0xDB */ CHAN_C | NONEOS_C,
+/* 0xDC */ CHAN_C | NONEOS_C,
+/* 0xDD */ CHAN_C | NONEOS_C,
+/* 0xDE */ CHAN_C | NONEOS_C,
+/* 0xDF */ CHAN_C | NONEOS_C,
+/* 0xE0 */ CHAN_C | NONEOS_C,
+/* 0xE1 */ CHAN_C | NONEOS_C,
+/* 0xE2 */ CHAN_C | NONEOS_C,
+/* 0xE3 */ CHAN_C | NONEOS_C,
+/* 0xE4 */ CHAN_C | NONEOS_C,
+/* 0xE5 */ CHAN_C | NONEOS_C,
+/* 0xE6 */ CHAN_C | NONEOS_C,
+/* 0xE7 */ CHAN_C | NONEOS_C,
+/* 0xE8 */ CHAN_C | NONEOS_C,
+/* 0xE9 */ CHAN_C | NONEOS_C,
+/* 0xEA */ CHAN_C | NONEOS_C,
+/* 0xEB */ CHAN_C | NONEOS_C,
+/* 0xEC */ CHAN_C | NONEOS_C,
+/* 0xED */ CHAN_C | NONEOS_C,
+/* 0xEE */ CHAN_C | NONEOS_C,
+/* 0xEF */ CHAN_C | NONEOS_C,
+/* 0xF0 */ CHAN_C | NONEOS_C,
+/* 0xF1 */ CHAN_C | NONEOS_C,
+/* 0xF2 */ CHAN_C | NONEOS_C,
+/* 0xF3 */ CHAN_C | NONEOS_C,
+/* 0xF4 */ CHAN_C | NONEOS_C,
+/* 0xF5 */ CHAN_C | NONEOS_C,
+/* 0xF6 */ CHAN_C | NONEOS_C,
+/* 0xF7 */ CHAN_C | NONEOS_C,
+/* 0xF8 */ CHAN_C | NONEOS_C,
+/* 0xF9 */ CHAN_C | NONEOS_C,
+/* 0xFA */ CHAN_C | NONEOS_C,
+/* 0xFB */ CHAN_C | NONEOS_C,
+/* 0xFC */ CHAN_C | NONEOS_C,
+/* 0xFD */ CHAN_C | NONEOS_C,
+/* 0xFE */ CHAN_C | NONEOS_C,
+/* 0xFF */ CHAN_C | NONEOS_C
+};
diff --git a/src/messages.tab b/src/messages.tab
new file mode 100644 (file)
index 0000000..6bb0230
--- /dev/null
@@ -0,0 +1,1025 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, src/messages.tab
+ *   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.
+ *
+ *   $Id: messages.tab 2731 2006-11-09 23:53:43Z jilles $
+ */
+
+static  const char *  replies[] = {
+/* 000 */       NULL,
+/* 001  RPL_WELCOME, */ ":%s 001 %s :Welcome to the %s Internet Relay Chat Network %s",
+/* 002  RPL_YOURHOST,*/ ":%s 002 %s :Your host is %s, running version %s",
+/* 003  RPL_CREATED, */ ":%s 003 %s :This server was created %s",
+/* 004  RPL_MYINFO, */ ":%s 004 %s %s %s %s biklmnopstveqrcgzjfILPQF bkloveqjfI",
+/* 005  RPL_ISUPPORT, */ "%s :are supported by this server",
+/* 006 */       NULL,
+/* 007 */       NULL,
+/* 008  RPL_SNOMASK */  ":%s 008 %s %s :Server notice mask",
+/* 009 */       NULL,
+/* 010  RPL_REDIR, */ ":%s 010 %s %s %d :Please use this Server/Port instead",
+/* 011 */       NULL,
+/* 012 */       NULL,
+/* 013 */       NULL,
+/* 014 */       NULL,
+/* 015 RPL_MAP */    ":%s 015 %s :%s",
+/* 016 */       NULL,
+/* 017 RPL_MAPEND */ ":%s 017 %s :End of /MAP",
+/* 018 */       NULL,
+/* 019 */       NULL,
+/* 020 */      NULL,
+/* 021 */       NULL,
+/* 022 */       NULL,
+/* 023 */       NULL,
+/* 024 */       NULL,
+/* 025 */       NULL,
+/* 026 */       NULL,
+/* 027 */       NULL,
+/* 028 */       NULL,
+/* 029 */       NULL,
+/* 030 */       NULL,
+/* 031 */       NULL,
+/* 032 */       NULL,
+/* 033 */       NULL,
+/* 034 */       NULL,
+/* 035 */       NULL,
+/* 036 */       NULL,
+/* 037 */       NULL,
+/* 038 */       NULL,
+/* 039 */       NULL,
+/* 040 */       NULL,
+/* 041 */       NULL,
+/* 042 */       NULL,
+/* 043 RPL_SAVENICK */       "%s :Nick collision, forcing nick change to your unique ID",
+/* 044 */       NULL,
+/* 045 */       NULL,
+/* 046 */       NULL,
+/* 047 */       NULL,
+/* 048 */       NULL,
+/* 049 */       NULL,
+/* 050 */       NULL,
+/* 051 */       NULL,
+/* 052 */       NULL,
+/* 053 */       NULL,
+/* 054 */       NULL,
+/* 055 */       NULL,
+/* 056 */       NULL,
+/* 057 */       NULL,
+/* 058 */       NULL,
+/* 059 */       NULL,
+/* 060 */       NULL,
+/* 061 */       NULL,
+/* 062 */       NULL,
+/* 063 */       NULL,
+/* 064 */       NULL,
+/* 065 */       NULL,
+/* 066 */       NULL,
+/* 067 */       NULL,
+/* 068 */       NULL,
+/* 069 */       NULL,
+/* 070 */       NULL,
+/* 071 */       NULL,
+/* 072 */       NULL,
+/* 073 */       NULL,
+/* 074 */       NULL,
+/* 075 */       NULL,
+/* 076 */       NULL,
+/* 077 */       NULL,
+/* 078 */       NULL,
+/* 079 */       NULL,
+/* 080 */       NULL,
+/* 081 */       NULL,
+/* 082 */       NULL,
+/* 083 */       NULL,
+/* 084 */       NULL,
+/* 085 */       NULL,
+/* 086 */       NULL,
+/* 087 */       NULL,
+/* 088 */       NULL,
+/* 089 */       NULL,
+/* 090 */       NULL,
+/* 091 */       NULL,
+/* 092 */       NULL,
+/* 093 */       NULL,
+/* 094 */       NULL,
+/* 095 */       NULL,
+/* 096 */       NULL,
+/* 097 */       NULL,
+/* 098 */       NULL,
+/* 099 */       NULL,
+/* 100 */       NULL,
+/* 101 */       NULL,
+/* 102 */       NULL,
+/* 103 */       NULL,
+/* 104 */       NULL,
+/* 105 */       NULL,
+/* 106 */       NULL,
+/* 107 */       NULL,
+/* 108 */       NULL,
+/* 109 */       NULL,
+/* 110 */       NULL,
+/* 111 */       NULL,
+/* 112 */       NULL,
+/* 113 */       NULL,
+/* 114 */       NULL,
+/* 115 */       NULL,
+/* 116 */       NULL,
+/* 117 */       NULL,
+/* 118 */       NULL,
+/* 119 */       NULL,
+/* 120 */       NULL,
+/* 121 */       NULL,
+/* 122 */       NULL,
+/* 123 */       NULL,
+/* 124 */       NULL,
+/* 125 */       NULL,
+/* 126 */       NULL,
+/* 127 */       NULL,
+/* 128 */       NULL,
+/* 129 */       NULL,
+/* 130 */       NULL,
+/* 131 */       NULL,
+/* 132 */       NULL,
+/* 133 */       NULL,
+/* 134 */       NULL,
+/* 135 */       NULL,
+/* 136 */       NULL,
+/* 137 */       NULL,
+/* 138 */       NULL,
+/* 139 */       NULL,
+/* 140 */       NULL,
+/* 141 */       NULL,
+/* 142 */       NULL,
+/* 143 */       NULL,
+/* 144 */       NULL,
+/* 145 */       NULL,
+/* 146 */       NULL,
+/* 147 */       NULL,
+/* 148 */       NULL,
+/* 149 */       NULL,
+/* 150 */       NULL,
+/* 151 */       NULL,
+/* 152 */       NULL,
+/* 153 */       NULL,
+/* 154 */       NULL,
+/* 155 */       NULL,
+/* 156 */       NULL,
+/* 157 */       NULL,
+/* 158 */       NULL,
+/* 159 */       NULL,
+/* 160 */       NULL,
+/* 161 */       NULL,
+/* 162 */       NULL,
+/* 163 */       NULL,
+/* 164 */       NULL,
+/* 165 */       NULL,
+/* 166 */       NULL,
+/* 167 */       NULL,
+/* 168 */       NULL,
+/* 169 */       NULL,
+/* 170 */       NULL,
+/* 171 */       NULL,
+/* 172 */       NULL,
+/* 173 */       NULL,
+/* 174 */       NULL,
+/* 175 */       NULL,
+/* 176 */       NULL,
+/* 177 */       NULL,
+/* 178 */       NULL,
+/* 179 */       NULL,
+/* 180 */       NULL,
+/* 181 */       NULL,
+/* 182 */       NULL,
+/* 183 */       NULL,
+/* 184 */       NULL,
+/* 185 */       NULL,
+/* 186 */       NULL,
+/* 187 */       NULL,
+/* 188 */       NULL,
+/* 189 */       NULL,
+/* 190 */       NULL,
+/* 191 */       NULL,
+/* 192 */       NULL,
+/* 193 */       NULL,
+/* 194 */       NULL,
+/* 195 */       NULL,
+/* 196 */       NULL,
+/* 197 */       NULL,
+/* 198 */       NULL,
+/* 199 */       NULL,
+/* 200 RPL_TRACELINK, */        "Link %s %s %s",
+/* 201 RPL_TRACECONNECTING, */  "Try. %s %s",
+/* 202 RPL_TRACEHANDSHAKE, */   "H.S. %s %s",
+/* 203 RPL_TRACEUNKNOWN, */     "???? %s %s (%s) %d",
+/* 204 RPL_TRACEOPERATOR, */    "Oper %s %s (%s) %lu %lu",
+/* 205 RPL_TRACEUSER, */        "User %s %s (%s) %lu %lu",
+/* 206 RPL_TRACESERVER, */      "Serv %s %dS %dC %s %s!%s@%s %lu",
+/* 207 */       NULL,
+/* 208 RPL_TRACENEWTYPE, */     "<newtype> 0 %s",
+/* 209 RPL_TRACECLASS, */       "Class %s %d",
+/* 210 */       NULL,
+/* 211 RPL_STATSLINKINFO, */    NULL,
+/* 212 RPL_STATSCOMMANDS, */    "%s %u %u :%u",
+/* 213 RPL_STATSCLINE, */       "C %s %s %s %d %s",
+/* 214 RPL_STATSNLINE, */       NULL,
+/* 215 RPL_STATSILINE, */       "I %s * %s@%s %d %s",
+/* 216 RPL_STATSKLINE, */       "%c %s * %s :%s%s%s",
+/* 217 RPL_STATSQLINE, */       "%c %d %s :%s",
+/* 218 RPL_STATSYLINE, */       "Y %s %d %d %d %u %d.%d %d.%d %u",
+/* 219 RPL_ENDOFSTATS, */       "%c :End of /STATS report",
+/* 220 RPL_STATSPLINE, */       "%c %d %s %d :%s",
+/* 221 RPL_UMODEIS, */          ":%s 221 %s %s",
+/* 222 */      NULL,
+/* 223 */       NULL,
+/* 224 */       NULL,
+/* 225 RPL_STATSDLINE*/         "%c %s :%s%s%s",
+/* 226 */      NULL,
+/* 227 */       NULL,
+/* 228 */       NULL,
+/* 229 */       NULL,
+/* 230 */       NULL,
+/* 231 */       NULL,
+/* 232 */       NULL,
+/* 233 */       NULL,
+/* 234 RPL_SERVLIST, */ NULL,
+/* 235 RPL_SERVLISTEND, */ NULL,
+/* 236 */       NULL,
+/* 237 */       NULL,
+/* 238 */       NULL,
+/* 239 */       NULL,
+/* 240 */       NULL,
+/* 241 RPL_STATSLLINE, */       "L %s * %s 0 -1",
+/* 242 RPL_STATSUPTIME,*/       ":Server Up %d days, %d:%02d:%02d",
+/* 243 RPL_STATSOLINE, */       "O %s@%s * %s %s %s",
+/* 244 RPL_STATSHLINE, */       "H %s * %s 0 -1", 
+/* 245 RPL_STATSSLINE, */       NULL,
+/* 246 */       NULL,
+/* 247 RPL_STATSXLINE, */      "%c %d %s :%s",
+
+/* 248 RPL_STATSULINE, */       "U %s %s@%s %s",
+/* 249 RPL_STATSDEBUG */       NULL,
+/* 250 RPL_STATSCONN, */       ":Highest connection count: %d (%d clients) (%d connections received)",
+/* 251 RPL_LUSERCLIENT, */     ":There are %d users and %d invisible on %d servers",
+/* 252 RPL_LUSEROP, */          "%d :IRC Operators online",
+/* 253 RPL_LUSERUNKNOWN, */     "%d :unknown connection(s)",
+/* 254 RPL_LUSERCHANNELS, */    "%d :channels formed",
+/* 255 RPL_LUSERME, */          ":I have %d clients and %d servers",
+/* 256 RPL_ADMINME, */          ":%s 256 %s :Administrative info about %s",
+/* 257 RPL_ADMINLOC1, */        ":%s 257 %s :%s",
+/* 258 RPL_ADMINLOC2, */        ":%s 258 %s :%s",
+/* 259 RPL_ADMINEMAIL, */       ":%s 259 %s :%s",
+/* 260 */       NULL,
+/* 261 RPL_TRACELOG, */         NULL,
+/* 262 RPL_ENDOFTRACE, */       "%s :End of TRACE",
+/* 263 RPL_LOAD2HI, */          
+":%s 263 %s %s :Server load is temporarily too heavy. Please wait a while and try again.",
+/* 264 */       NULL,
+/* 265 RPL_LOCALUSERS, */       "%d %d :Current local users %d, max %d",
+/* 266 RPL_GLOBALUSERS, */      "%d %d :Current global users %d, max %d",
+/* 267 */       NULL,
+/* 268 */       NULL,
+/* 269 */       NULL,
+/* 270 */       NULL,
+/* 271 */       NULL,
+/* 272 */       NULL,
+/* 273 */       NULL,
+/* 274 */       NULL,
+/* 275 */       NULL,
+/* 276 */       NULL,
+/* 277 */       NULL,
+/* 278 */       NULL,
+/* 279 */       NULL,
+/* 280 */       NULL,
+/* 281 RPL_ACCEPTLIST, */       ":%s 281 %s %s",
+/* 282 RPL_ENDOFACCEPT */       ":%s 282 %s :End of /ACCEPT list.",
+/* 283 */       NULL,
+/* 284 */       NULL,
+/* 285 */       NULL,
+/* 286 */       NULL,
+/* 287 */       NULL,
+/* 288 */       NULL,
+/* 289 */       NULL,
+/* 290 */       NULL,
+/* 291 */       NULL,
+/* 292 */       NULL,
+/* 293 */       NULL,
+/* 294 */       NULL,
+/* 295 */       NULL,
+/* 296 */       NULL,
+/* 297 */       NULL,
+/* 298 */       NULL,
+/* 299 */       NULL,
+/* 300 RPL_NONE, */      NULL,
+/* 301 RPL_AWAY, */      "%s :%s",
+/* 302 RPL_USERHOST, */  ":%s 302 %s :%s",
+/* 303 RPL_ISON, */     ":%s 303 %s :",
+/* 304 RPL_TEXT, */      NULL,
+/* 305 RPL_UNAWAY, */   ":%s 305 %s :You are no longer marked as being away",
+/* 306 RPL_NOWAWAY, */  ":%s 306 %s :You have been marked as being away",
+/* 307 */       NULL,
+/* 308 */       NULL,
+/* 309 */       NULL,
+/* 310 */       NULL,
+/* 311 RPL_WHOISUSER, */        "%s %s %s * :%s",
+/* 312 RPL_WHOISSERVER, */      "%s %s :%s",
+/* 313 RPL_WHOISOPERATOR, */    "%s :%s",
+/* 314 RPL_WHOWASUSER, */       ":%s 314 %s %s %s %s * :%s",
+/* 315 RPL_ENDOFWHO, */         ":%s 315 %s %s :End of /WHO list.",
+/* 316 RPL_WHOISCHANOP, */      NULL,
+/* 317 RPL_WHOISIDLE, */        "%s %d %d :seconds idle, signon time",
+/* 318 RPL_ENDOFWHOIS, */       "%s :End of /WHOIS list.",
+/* 319 RPL_WHOISCHANNELS, */    ":%s 319 %s %s :",
+/* 320 */      NULL,
+/* 321 RPL_LISTSTART, */        ":%s 321 %s Channel :Users  Name",
+/* 322 RPL_LIST, */             ":%s 322 %s %s %d :%s",
+/* 323 RPL_LISTEND, */          ":%s 323 %s :End of /LIST",
+/* 324 RPL_CHANNELMODEIS, */    ":%s 324 %s %s %s",
+/* 325 */       NULL,
+/* 326 */       NULL,
+/* 327 */       NULL,
+/* 328 */       NULL,
+/* 329 RPL_CREATIONTIME, */    ":%s 329 %s %s %lu", 
+/* 330 RPL_WHOISLOGGEDIN */    ":%s 330 %s %s %s :is logged in as",
+/* 331 RPL_NOTOPIC, */          ":%s 331 %s %s :No topic is set.",
+/* 332 RPL_TOPIC, */            ":%s 332 %s %s :%s",
+/* 333 RPL_TOPICWHOTIME, */     ":%s 333 %s %s %s %lu",
+/* 334 */       NULL,
+/* 335 */       NULL,
+/* 336 */       NULL,
+/* 337 */       NULL,
+/* 338 RPL_WHOISACTUALLY, */   "%s %s :actually using host",
+/* 339 */       NULL,
+/* 340 */       NULL,
+/* 341 RPL_INVITING, */         ":%s 341 %s %s %s",
+/* 342 RPL_SUMMONING, */ NULL,
+/* 343 */       NULL,
+/* 344 */       NULL,
+/* 345 */       NULL,
+/* 346 RPL_INVEXLIST */         ":%s 346 %s %s %s %s %lu",       
+/* 347 RPL_ENDOFINVEXLIST */    ":%s 347 %s %s :End of Channel Invite List",
+/* 348 RPL_EXCEPTLIST */        ":%s 348 %s %s %s %s %lu",
+/* 349 RPL_ENDOFEXCEPTLIST */   ":%s 349 %s %s :End of Channel Exception List",
+/* 350 */       NULL,
+/* 351 RPL_VERSION, */          "%s(%s). %s :%s TS%dow %s",
+/* 352 RPL_WHOREPLY, */         ":%s 352 %s %s %s %s %s %s %s :%d %s",
+/* 353 RPL_NAMREPLY, */         ":%s 353 %s %s %s :",
+/* 354 */       NULL,
+/* 355 */       NULL,
+/* 356 */       NULL,
+/* 357 */       NULL,
+/* 358 */       NULL,
+/* 359 */       NULL,
+/* 360 RPL_WHOWASREAL, */       ":%s 360 %s %s :was connecting from *@%s %s",
+/* 361 RPL_KILLDONE, */ NULL,
+/* 362 RPL_CLOSING, */          ":%s 362 %s %s :Closed. Status = %d",
+/* 363 RPL_CLOSEEND, */         ":%s 363 %s %d :Connections Closed",
+/* 364 RPL_LINKS, */            "%s %s :%d %s",
+/* 365 RPL_ENDOFLINKS, */       "%s :End of /LINKS list.",
+/* 366 RPL_ENDOFNAMES, */       ":%s 366 %s %s :End of /NAMES list.",
+/* 367 RPL_BANLIST, */          ":%s 367 %s %s %s %s %lu",
+/* 368 RPL_ENDOFBANLIST, */     ":%s 368 %s %s :End of Channel Ban List",
+/* 369 RPL_ENDOFWHOWAS, */      ":%s 369 %s %s :End of WHOWAS",
+/* 370 */       NULL,
+/* 371 RPL_INFO, */             ":%s",
+/* 372 RPL_MOTD, */             ":%s 372 %s :- %s",
+/* 373 RPL_INFOSTART, */       NULL,
+/* 374 RPL_ENDOFINFO, */        ":End of /INFO list.",
+/* 375 RPL_MOTDSTART, */        ":%s 375 %s :- %s Message of the Day - ",
+/* 376 RPL_ENDOFMOTD, */        ":%s 376 %s :End of /MOTD command.",
+/* 377 */       NULL,
+/* 378 RPL_WHOISHOST, */        "%s :is connecting from *@%s %s",
+/* 379 */       NULL,
+/* 380 */       NULL,
+/* 381 RPL_YOUREOPER, */        ":%s 381 %s :Here I am with a brain the size of a planet, and they want me to bring them coffee. I think I'll just kill myself...",
+/* 382 RPL_REHASHING, */        ":%s 382 %s %s :Rehashing",
+/* 383 */       NULL,
+/* 384 RPL_MYPORTIS, */                NULL,
+/* 385 RPL_NOTOPERANYMORE, */   NULL,
+/* 386 RPL_RSACHALLENGE, */    ":%s 386 %s :%s",
+/* 387 */       NULL,
+/* 388 */       NULL,
+/* 389 */       NULL,
+/* 390 */       NULL,
+/* 391 RPL_TIME, */             "%s :%s",
+/* 392 */       NULL,
+/* 393 */       NULL,
+/* 394 */       NULL,
+/* 395 */       NULL,
+/* 396 */       NULL,
+/* 397 */       NULL,
+/* 398 */       NULL,
+/* 399 */       NULL,
+/* 400 */       NULL,
+/* 401 ERR_NOSUCHNICK, */       "%s :No such nick/channel",
+/* 402 ERR_NOSUCHSERVER, */     "%s :No such server",
+/* 403 ERR_NOSUCHCHANNEL, */    "%s :No such channel",
+/* 404 ERR_CANNOTSENDTOCHAN, */ "%s :Cannot send to channel",
+/* 405 ERR_TOOMANYCHANNELS, */  ":%s 405 %s %s :You have joined too many channels",
+/* 406 ERR_WASNOSUCHNICK, */    ":%s 406 %s %s :There was no such nickname",
+/* 407 ERR_TOOMANYTARGETS, */   ":%s 407 %s %s :Too many recipients.",
+/* 408 */       NULL,
+/* 409 ERR_NOORIGIN, */         ":%s 409 %s :No origin specified",
+/* 410 ERR_INVALIDCAPCMD */    ":%s 410 %s %s :Invalid CAP subcommand",
+/* 411 ERR_NORECIPIENT, */      ":%s 411 %s :No recipient given (%s)",
+/* 412 ERR_NOTEXTTOSEND, */     ":%s 412 %s :No text to send",
+/* 413 ERR_NOTOPLEVEL, */       "%s :No toplevel domain specified",
+/* 414 ERR_WILDTOPLEVEL, */     "%s :Wildcard in toplevel Domain",
+/* 415 */       NULL,
+/* 416 ERR_TOOMANYMATCHES */    ":%s 416 %s %s :output too large, truncated",
+/* 417 */       NULL,
+/* 418 */       NULL,
+/* 419 */       NULL,
+/* 420 */       NULL,
+/* 421 ERR_UNKNOWNCOMMAND, */   ":%s 421 %s %s :Unknown command",
+/* 422 ERR_NOMOTD, */           ":%s 422 %s :MOTD File is missing",
+/* 423 ERR_NOADMININFO, */     NULL,
+/* 424 ERR_FILEERROR, */       NULL,
+/* 425 */       NULL,
+/* 426 */       NULL,
+/* 427 */       NULL,
+/* 428 */       NULL,
+/* 429 */       NULL,
+/* 430 */       NULL,
+/* 431 ERR_NONICKNAMEGIVEN, */  ":%s 431 %s :No nickname given",
+/* 432 ERR_ERRONEUSNICKNAME, */ ":%s 432 %s %s :Erroneous Nickname",
+/* 433 ERR_NICKNAMEINUSE, */    ":%s 433 %s %s :Nickname is already in use.",
+/* 434 */       NULL,
+/* 435 ERR_BANNICKCHANGE */     "%s %s :Cannot change nickname while banned on channel",
+/* 436 ERR_NICKCOLLISION, */    "%s :Nickname collision KILL",
+/* 437 ERR_UNAVAILRESOURCE, */ ":%s 437 %s %s :Nick/channel is temporarily unavailable",
+/* 438 ERR_NICKTOOFAST */       ":%s 438 %s %s %s :Nick change too fast. Please wait %d seconds.",
+/* 439 */       NULL,
+/* 440 ERR_SERVICESDOWN, */     "%s :Services are currently unavailable",
+/* 441 ERR_USERNOTINCHANNEL, */ "%s %s :They aren't on that channel",
+/* 442 ERR_NOTONCHANNEL, */     "%s :You're not on that channel",
+/* 443 ERR_USERONCHANNEL, */    "%s %s :is already on channel",
+/* 444 ERR_NOLOGIN, */         NULL,
+/* 445 ERR_SUMMONDISABLED, */  NULL,
+/* 446 ERR_USERSDISABLED, */   NULL,
+/* 447 */       NULL,
+/* 448 */       NULL,
+/* 449 */       NULL,
+/* 450 */       NULL,
+/* 451 ERR_NOTREGISTERED, */    ":%s 451 * :You have not registered",
+/* 452 */       NULL,
+/* 453 */       NULL,
+/* 454 */       NULL,
+/* 455 */       NULL,
+/* 456 ERR_ACCEPTFULL */        ":%s 456 %s :Accept list is full",
+/* 457 ERR_ACCEPTEXIST */       ":%s 457 %s %s :is already on your accept list",
+/* 458 ERR_ACCEPTNOT */         ":%s 458 %s %s :is not on your accept list",
+/* 459 */       NULL,
+/* 460 */       NULL,
+/* 461 ERR_NEEDMOREPARAMS, */   ":%s 461 %s %s :Not enough parameters",
+/* 462 ERR_ALREADYREGISTRED, */ ":%s 462 %s :You may not reregister",
+/* 463 ERR_NOPERMFORHOST, */   NULL,
+/* 464 ERR_PASSWDMISMATCH, */   ":%s 464 %s :Password Incorrect",
+/* 465 ERR_YOUREBANNEDCREEP, */ ":%s 465 %s :You are banned from this server- %s",
+/* 466 ERR_YOUWILLBEBANNED, */  NULL,
+/* 467 ERR_KEYSET, */          NULL,
+/* 468 */       NULL,
+/* 469 */       NULL,
+/* 470 ERR_LINKCHANNEL */       "%s %s :Forwarding to another channel",
+/* 471 ERR_CHANNELISFULL, */    ":%s 471 %s %s :Cannot join channel (+l)",
+/* 472 ERR_UNKNOWNMODE  , */    ":%s 472 %s %c :is unknown mode char to me",
+/* 473 ERR_INVITEONLYCHAN, */   ":%s 473 %s %s :Cannot join channel (+i)",
+/* 474 ERR_BANNEDFROMCHAN, */   ":%s 474 %s %s :Cannot join channel (+b)",
+/* 475 ERR_BADCHANNELKEY, */    ":%s 475 %s %s :Cannot join channel (+k)",
+/* 476 ERR_BADCHANMASK, */     NULL,
+/* 477 ERR_NEEDREGGEDNICK */   ":%s 477 %s %s :Cannot join channel (+r)",
+/* 478 ERR_BANLISTFULL, */      ":%s 478 %s %s %s :Channel ban list is full",
+/* 479 ERR_BADCHANNAME */       "%s :Illegal channel name",
+/* 480 ERR_THROTTLE */          ":%s 480 %s %s :Cannot join channel (throttle exceeded)",
+/* 481 ERR_NOPRIVILEGES, */    ":Permission Denied - You're not an IRC operator",
+/* 482 ERR_CHANOPRIVSNEEDED, */ ":%s 482 %s %s :You're not channel operator",
+/* 483 ERR_CANTKILLSERVER, */   ":You can't kill a server!",
+/* 484 ERR_ISCHANSERVICE */     ":%s 484 %s %s %s :Cannot kill, kick or deop a network service",
+/* 485 ERR_BANNEDNICK, */      NULL,
+/* 486 ERR_NONONREG */          "%s :You must log in with services to message this user",
+/* 487 */       NULL,
+/* 488 */       NULL,
+/* 489 ERR_VOICENEEDED */      ":%s 489 %s %s :You're neither voiced nor channel operator",
+/* 490 */       NULL,
+/* 491 ERR_NOOPERHOST, */       ":%s 491 %s :Only few of mere mortals may try to enter the twilight zone",
+/* 492 */       NULL,
+/* 493 */       NULL,
+/* 494 */       NULL,
+/* 495 */       NULL,
+/* 496 */       NULL,
+/* 497 */       NULL,
+/* 498 */       NULL,
+/* 499 */       NULL,
+/* 500 */       NULL,
+/* 501 ERR_UMODEUNKNOWNFLAG, */ ":%s 501 %s :Unknown MODE flag",
+/* 502 ERR_USERSDONTMATCH, */   ":%s 502 %s :Can't change mode for other users",
+/* 503 ERR_GHOSTEDCLIENT, */   NULL,
+/* 504 ERR_USERNOTONSERV, */    ":%s 504 %s %s :User is not on this server",
+/* 505 */      NULL,
+/* 506 */       NULL,
+/* 507 */       NULL,
+/* 508 */      NULL,
+/* 509 */      NULL,
+/* 510 */      NULL,
+/* 511 */      NULL,
+/* 512 */      NULL,
+/* 513 ERR_WRONGPONG */                ":%s 513 %s :To connect type /QUOTE PONG %08lX",
+/* 514 */      NULL,
+/* 515 */      NULL,
+/* 516 */      NULL,
+/* 517 */      NULL,
+/* 518 */      NULL,
+/* 519 */      NULL,
+/* 520 */      NULL,
+/* 521 */      NULL,
+/* 522 */      NULL,
+/* 523 */      NULL,
+/* 524 ERR_HELPNOTFOUND, */    ":%s 524 %s %s :Help not found",
+/* 525 */      NULL,
+/* 526 */      NULL,
+/* 527 */      NULL,
+/* 528 */      NULL,
+/* 529 */      NULL,
+/* 530 */      NULL,
+/* 531 */      NULL,
+/* 532 */      NULL,
+/* 533 */      NULL,
+/* 534 */      NULL,
+/* 535 */      NULL,
+/* 536 */      NULL,
+/* 537 */      NULL,
+/* 538 */      NULL,
+/* 539 */      NULL,
+/* 540 */      NULL,
+/* 541 */      NULL,
+/* 542 */      NULL,
+/* 543 */      NULL,
+/* 544 */      NULL,
+/* 545 */      NULL,
+/* 546 */      NULL,
+/* 547 */      NULL,
+/* 548 */      NULL,
+/* 549 */      NULL,
+/* 550 */      NULL,
+/* 551 */      NULL,
+/* 552 */      NULL,
+/* 553 */      NULL,
+/* 554 */      NULL,
+/* 555 */      NULL,
+/* 556 */      NULL,
+/* 557 */      NULL,
+/* 558 */      NULL,
+/* 559 */      NULL,
+/* 560 */      NULL,
+/* 561 */      NULL,
+/* 562 */      NULL,
+/* 563 */      NULL,
+/* 564 */      NULL,
+/* 565 */      NULL,
+/* 566 */      NULL,
+/* 567 */      NULL,
+/* 568 */      NULL,
+/* 569 */      NULL,
+/* 570 */      NULL,
+/* 571 */      NULL,
+/* 572 */      NULL,
+/* 573 */      NULL,
+/* 574 */      NULL,
+/* 575 */      NULL,
+/* 576 */      NULL,
+/* 577 */      NULL,
+/* 578 */      NULL,
+/* 579 */      NULL,
+/* 580 */      NULL,
+/* 581 */      NULL,
+/* 582 */      NULL,
+/* 583 */      NULL,
+/* 584 */      NULL,
+/* 585 */      NULL,
+/* 586 */      NULL,
+/* 587 */      NULL,
+/* 588 */      NULL,
+/* 589 */      NULL,
+/* 590 */      NULL,
+/* 591 */      NULL,
+/* 592 */      NULL,
+/* 593 */      NULL,
+/* 594 */      NULL,
+/* 595 */      NULL,
+/* 596 */      NULL,
+/* 597 */      NULL,
+/* 598 */      NULL,
+/* 599 */      NULL,
+/* 600 */      NULL,
+/* 601 */      NULL,
+/* 602 */      NULL,
+/* 603 */      NULL,
+/* 604 */      NULL,
+/* 605 */      NULL,
+/* 606 */      NULL,
+/* 607 */      NULL,
+/* 608 */       NULL, /* Do not use -- Reserved for WATCH -Rak */
+/* 609 */      NULL,
+/* 610 */      NULL,
+/* 611 */      NULL,
+/* 612 */      NULL,
+/* 613 */      NULL,
+/* 614 */      NULL,
+/* 615 */      NULL,
+/* 616 */      NULL,
+/* 617 */      NULL,
+/* 618 */      NULL,
+/* 619 */      NULL,
+/* 620 */      NULL,
+/* 621 */      NULL,
+/* 622 */      NULL,
+/* 623 */      NULL,
+/* 624 */      NULL,
+/* 625 */      NULL,
+/* 626 */      NULL,
+/* 627 */      NULL,
+/* 628 */      NULL,
+/* 629 */      NULL,
+/* 630 */      NULL,
+/* 631 */      NULL,
+/* 632 */      NULL,
+/* 633 */      NULL,
+/* 634 */      NULL,
+/* 635 */      NULL,
+/* 636 */      NULL,
+/* 637 */      NULL,
+/* 638 */      NULL,
+/* 639 */      NULL,
+/* 640 */      NULL,
+/* 641 */      NULL,
+/* 642 */      NULL,
+/* 643 */      NULL,
+/* 644 */      NULL,
+/* 645 */      NULL,
+/* 646 */      NULL,
+/* 647 */      NULL,
+/* 648 */      NULL,
+/* 649 */      NULL,
+/* 650 */      NULL,
+/* 651 */      NULL,
+/* 652 */      NULL,
+/* 653 */      NULL,
+/* 654 */      NULL,
+/* 655 */      NULL,
+/* 656 */      NULL,
+/* 657 */      NULL,
+/* 658 */      NULL,
+/* 659 */      NULL,
+/* 660 */      NULL,
+/* 661 */      NULL,
+/* 662 */      NULL,
+/* 663 */      NULL,
+/* 664 */      NULL,
+/* 665 */      NULL,
+/* 666 */      NULL,
+/* 667 */      NULL,
+/* 668 */      NULL,
+/* 669 */      NULL,
+/* 670 */      NULL,
+/* 671 */      NULL,
+/* 672 */      NULL,
+/* 673 */      NULL,
+/* 674 */      NULL,
+/* 675 */      NULL,
+/* 676 */      NULL,
+/* 677 */      NULL,
+/* 678 */      NULL,
+/* 679 */      NULL,
+/* 680 */      NULL,
+/* 681 */      NULL,
+/* 682 */      NULL,
+/* 683 */      NULL,
+/* 684 */      NULL,
+/* 685 */      NULL,
+/* 686 */      NULL,
+/* 687 */      NULL,
+/* 688 */      NULL,
+/* 689 */      NULL,
+/* 690 */      NULL,
+/* 691 */      NULL,
+/* 692 */      NULL,
+/* 693 */      NULL,
+/* 694 */      NULL,
+/* 695 */      NULL,
+/* 696 */      NULL,
+/* 697 */      NULL,
+/* 698 */      NULL,
+/* 699 */      NULL,
+/* 700 */      NULL,
+/* 701 */      NULL,
+/* 702 RPL_MODLIST, */         ":%s 702 %s %s 0x%x %s %s",
+/* 703 RPL_ENDOFMODLIST, */    ":%s 703 %s :End of /MODLIST.",
+/* 704 RPL_HELPSTART, */       ":%s 704 %s %s :%s",
+/* 705 RPL_HELPTXT, */         ":%s 705 %s %s :%s",
+/* 706 RPL_ENDOFHELP, */       ":%s 706 %s %s :End of /HELP.",
+/* 707 ERR_TARGCHANGE */       ":%s 707 %s %s :Targets changing too fast, message dropped",
+/* 708 RPL_ETRACEFULL */       ":%s 708 %s %s %s %s %s %s %s %s :%s",
+/* 709 RPL_ETRACE */           ":%s 709 %s %s %s %s %s %s %s :%s",
+/* 710 RPL_KNOCK */            ":%s 710 %s %s %s!%s@%s :has asked for an invite.",
+/* 711 RPL_KNOCKDLVR */                ":%s 711 %s %s :Your KNOCK has been delivered.",
+/* 712 ERR_TOOMANYKNOCK */     ":%s 712 %s %s :Too many KNOCKs (%s).",
+/* 713 ERR_CHANOPEN */         "%s :Channel is open.",
+/* 714 ERR_KNOCKONCHAN */      ":%s 714 %s %s :You are already on that channel.",
+/* 715 ERR_KNOCKDISABLED */    ":%s 715 %s :KNOCKs are disabled.",
+/* 716 ERR_TARGUMODEG */       "%s :is in +g mode (server-side ignore.)",
+/* 717 RPL_TARGNOTIFY */       "%s :has been informed that you messaged them.",
+/* 718 RPL_UMODEGMSG */                ":%s 718 %s %s %s@%s :is messaging you, and you have umode +g.",
+/* 719 */      NULL,
+/* 720 RPL_OMOTDSTART */       ":%s 720 %s :Start of OPER MOTD",
+/* 721 RPL_OMOTD */            ":%s 721 %s :%s",
+/* 722 RPL_ENDOFOMOTD */       ":%s 722 %s :End of OPER MOTD",
+/* 723 ERR_NOPRIVS */          ":%s 723 %s %s :Insufficient oper privs",
+/* 724 RPL_TESTMASK */         NULL,   /* Used in 1.x and 2.0.x */
+/* 725 RPL_TESTLINE */         ":%s 725 %s %c %ld %s :%s",
+/* 726 RPL_NOTESTLINE */       ":%s 726 %s %s :No matches",
+/* 727 RPL_TESTMASKGECOS */     ":%s 727 %s %d %d %s!%s@%s %s :Local/remote clients match",
+/* 728 */      NULL,
+/* 729 */      NULL,
+/* 730 RPL_MONONLINE */                ":%s 730 %s :%s",
+/* 731 RPL_MONOFFLINE */       ":%s 731 %s :%s",
+/* 732 RPL_MONLIST */          ":%s 732 %s :%s",
+/* 733 RPL_ENDOFMONLIST */     ":%s 733 %s :End of MONITOR list",
+/* 734 ERR_MONLISTFULL */      ":%s 734 %s %d %s :Monitor list is full",
+/* 735 */      NULL,
+/* 736 */      NULL,
+/* 737 */      NULL,
+/* 738 */      NULL,
+/* 739 */      NULL,
+/* 740 */      ":%s 740 %s :%s",
+/* 741 */      ":%s 741 %s :End of CHALLENGE",
+/* 742 */      NULL,
+/* 743 */      NULL,
+/* 744 */      NULL,
+/* 745 */      NULL,
+/* 746 */      NULL,
+/* 747 */      NULL,
+/* 748 */      NULL,
+/* 749 */      NULL,
+/* 750 RPL_SCANMATCHED */      "%d :matches",
+/* 751 RPL_SCANUMODES */       "%s %s %s %s %s %s :%s",
+/* 752 */      NULL,
+/* 753 */      NULL,
+/* 754 */      NULL,
+/* 755 */      NULL,
+/* 756 */      NULL,
+/* 757 */      NULL,
+/* 758 */      NULL,
+/* 759 */      NULL,
+/* 760 */      NULL,
+/* 761 */      NULL,
+/* 762 */      NULL,
+/* 763 */      NULL,
+/* 764 */      NULL,
+/* 765 */      NULL,
+/* 766 */      NULL,
+/* 767 */      NULL,
+/* 768 */      NULL,
+/* 769 */      NULL,
+/* 770 */      NULL,
+/* 771 */      NULL,
+/* 772 */      NULL,
+/* 773 */      NULL,
+/* 774 */      NULL,
+/* 775 */      NULL,
+/* 776 */      NULL,
+/* 777 */      NULL,
+/* 778 */      NULL,
+/* 779 */      NULL,
+/* 780 */      NULL,
+/* 781 */      NULL,
+/* 782 */      NULL,
+/* 783 */      NULL,
+/* 784 */      NULL,
+/* 785 */      NULL,
+/* 786 */      NULL,
+/* 787 */      NULL,
+/* 788 */      NULL,
+/* 789 */      NULL,
+/* 790 */      NULL,
+/* 791 */      NULL,
+/* 792 */      NULL,
+/* 793 */      NULL,
+/* 794 */      NULL,
+/* 795 */      NULL,
+/* 796 */      NULL,
+/* 797 */      NULL,
+/* 798 */      NULL,
+/* 799 */      NULL,
+/* 800 */      NULL,
+/* 801 */      NULL,
+/* 802 */      NULL,
+/* 803 */      NULL,
+/* 804 */      NULL,
+/* 805 */      NULL,
+/* 806 */      NULL,
+/* 807 */      NULL,
+/* 808 */      NULL,
+/* 809 */      NULL,
+/* 810 */      NULL,
+/* 811 */      NULL,
+/* 812 */      NULL,
+/* 813 */      NULL,
+/* 814 */      NULL,
+/* 815 */      NULL,
+/* 816 */      NULL,
+/* 817 */      NULL,
+/* 818 */      NULL,
+/* 819 */      NULL,
+/* 820 */      NULL,
+/* 821 */      NULL,
+/* 822 */      NULL,
+/* 823 */      NULL,
+/* 824 */      NULL,
+/* 825 */      NULL,
+/* 826 */      NULL,
+/* 827 */      NULL,
+/* 828 */      NULL,
+/* 829 */      NULL,
+/* 830 */      NULL,
+/* 831 */      NULL,
+/* 832 */      NULL,
+/* 833 */      NULL,
+/* 834 */      NULL,
+/* 835 */      NULL,
+/* 836 */      NULL,
+/* 837 */      NULL,
+/* 838 */      NULL,
+/* 839 */      NULL,
+/* 840 */      NULL,
+/* 841 */      NULL,
+/* 842 */      NULL,
+/* 843 */      NULL,
+/* 844 */      NULL,
+/* 845 */      NULL,
+/* 846 */      NULL,
+/* 847 */      NULL,
+/* 848 */      NULL,
+/* 849 */      NULL,
+/* 850 */      NULL,
+/* 851 */      NULL,
+/* 852 */      NULL,
+/* 853 */      NULL,
+/* 854 */      NULL,
+/* 855 */      NULL,
+/* 856 */      NULL,
+/* 857 */      NULL,
+/* 858 */      NULL,
+/* 859 */      NULL,
+/* 860 */      NULL,
+/* 861 */      NULL,
+/* 862 */      NULL,
+/* 863 */      NULL,
+/* 864 */      NULL,
+/* 865 */      NULL,
+/* 866 */      NULL,
+/* 867 */      NULL,
+/* 868 */      NULL,
+/* 869 */      NULL,
+/* 870 */      NULL,
+/* 871 */      NULL,
+/* 872 */      NULL,
+/* 873 */      NULL,
+/* 874 */      NULL,
+/* 875 */      NULL,
+/* 876 */      NULL,
+/* 877 */      NULL,
+/* 878 */      NULL,
+/* 879 */      NULL,
+/* 880 */      NULL,
+/* 881 */      NULL,
+/* 882 */      NULL,
+/* 883 */      NULL,
+/* 884 */      NULL,
+/* 885 */      NULL,
+/* 886 */      NULL,
+/* 887 */      NULL,
+/* 888 */      NULL,
+/* 889 */      NULL,
+/* 890 */      NULL,
+/* 891 */      NULL,
+/* 892 */      NULL,
+/* 893 */      NULL,
+/* 894 */      NULL,
+/* 895 */      NULL,
+/* 896 */      NULL,
+/* 897 */      NULL,
+/* 898 */      NULL,
+/* 899 */      NULL,
+/* 900 RPL_LOGGEDIN */         ":%s 900 %s %s!%s@%s %s :You are now logged in as %s.",
+/* 901 RPL_LOGGEDOUT */                ":%s 901 %s %s!%s@%s :You are now logged out.",
+/* 902 ERR_NICKLOCKED */       ":%s 902 %s :You must use a nick assigned to you.",
+/* 903 RPL_SASLSUCCESS */      ":%s 903 %s :SASL authentication successful",
+/* 904 ERR_SASLFAIL */         ":%s 904 %s :SASL authentication failed",
+/* 905 ERR_SASLTOOLONG */      ":%s 905 %s :SASL message too long",
+/* 906 ERR_SASLABORTED */      ":%s 906 %s :SASL authentication aborted",
+/* 907 ERR_SASLALREADY */      ":%s 907 %s :You have already completed SASL authentication",
+/* 908 */      NULL,
+/* 909 */      NULL,
+/* 910 */      NULL,
+/* 911 */      NULL,
+/* 912 */      NULL,
+/* 913 */      NULL,
+/* 914 */      NULL,
+/* 915 */      NULL,
+/* 916 */      NULL,
+/* 917 */      NULL,
+/* 918 */      NULL,
+/* 919 */      NULL,
+/* 920 */      NULL,
+/* 921 */      NULL,
+/* 922 */      NULL,
+/* 923 */      NULL,
+/* 924 */      NULL,
+/* 925 */      NULL,
+/* 926 */      NULL,
+/* 927 */      NULL,
+/* 928 */      NULL,
+/* 929 */      NULL,
+/* 930 */      NULL,
+/* 931 */      NULL,
+/* 932 */      NULL,
+/* 933 */      NULL,
+/* 934 */      NULL,
+/* 935 */      NULL,
+/* 936 */      NULL,
+/* 937 */      NULL,
+/* 938 */      NULL,
+/* 939 */      NULL,
+/* 940 */      NULL,
+/* 941 */      NULL,
+/* 942 */      NULL,
+/* 943 */      NULL,
+/* 944 */      NULL,
+/* 945 */      NULL,
+/* 946 */      NULL,
+/* 947 */      NULL,
+/* 948 */      NULL,
+/* 949 */      NULL,
+/* 950 */      NULL,
+/* 951 */      NULL,
+/* 952 */      NULL,
+/* 953 */      NULL,
+/* 954 */      NULL,
+/* 955 */      NULL,
+/* 956 */      NULL,
+/* 957 */      NULL,
+/* 958 */      NULL,
+/* 959 */      NULL,
+/* 960 */      NULL,
+/* 961 */      NULL,
+/* 962 */      NULL,
+/* 963 */      NULL,
+/* 964 */      NULL,
+/* 965 */      NULL,
+/* 966 */      NULL,
+/* 967 */      NULL,
+/* 968 */      NULL,
+/* 969 */      NULL,
+/* 970 */      NULL,
+/* 971 */      NULL,
+/* 972 */      NULL,
+/* 973 */      NULL,
+/* 974 */      NULL,
+/* 975 */      NULL,
+/* 976 */      NULL,
+/* 977 */      NULL,
+/* 978 */      NULL,
+/* 979 */      NULL,
+/* 980 */      NULL,
+/* 981 */      NULL,
+/* 982 */      NULL,
+/* 983 */      NULL,
+/* 984 */      NULL,
+/* 985 */      NULL,
+/* 986 */      NULL,
+/* 987 */      NULL,
+/* 988 */      NULL,
+/* 989 */      NULL,
+/* 990 */      NULL,
+/* 991 */      NULL,
+/* 992 */      NULL,
+/* 993 */      NULL,
+/* 994 */      NULL,
+/* 995 */      NULL,
+/* 996 */      NULL,
+/* 997 */      NULL,
+/* 998 */      NULL,
+/* 999 LAST ERR_LAST_ERR_MSG,*/        ":%s 999 %s :Last Error Message"
+};
diff --git a/src/modules.c b/src/modules.c
new file mode 100644 (file)
index 0000000..d03eae1
--- /dev/null
@@ -0,0 +1,960 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  modules.c: A module loader.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: modules.c 1509 2006-05-28 02:35:58Z nenolod $
+ */
+
+#include "stdinc.h"
+
+
+#include "modules.h"
+#include "s_log.h"
+#include "ircd.h"
+#include "client.h"
+#include "send.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "numeric.h"
+#include "parse.h"
+#include "ircd_defs.h"
+#include "irc_string.h"
+#include "memory.h"
+#include "tools.h"
+#include "sprintf_irc.h"
+
+
+
+/* -TimeMr14C:
+ * I have moved the dl* function definitions and
+ * the two functions (load_a_module / unload_a_module) to the
+ * file dynlink.c 
+ * And also made the necessary changes to those functions
+ * to comply with shl_load and friends.
+ * In this file, to keep consistency with the makefile, 
+ * I added the ability to load *.sl files, too.
+ * 27/02/2002
+ */
+
+#ifndef STATIC_MODULES
+
+struct module **modlist = NULL;
+
+static const char *core_module_table[] = {
+       "m_die",
+       "m_error",
+       "m_join",
+       "m_kick",
+       "m_kill",
+       "m_message",
+       "m_mode",
+       "m_nick",
+       "m_part",
+       "m_quit",
+       "m_server",
+       "m_sjoin",
+       "m_squit",
+       NULL
+};
+
+#define MODS_INCREMENT 10
+int num_mods = 0;
+int max_mods = MODS_INCREMENT;
+
+static dlink_list mod_paths;
+
+static int mo_modload(struct Client *, struct Client *, int, const char **);
+static int mo_modlist(struct Client *, struct Client *, int, const char **);
+static int mo_modreload(struct Client *, struct Client *, int, const char **);
+static int mo_modunload(struct Client *, struct Client *, int, const char **);
+static int mo_modrestart(struct Client *, struct Client *, int, const char **);
+
+struct Message modload_msgtab = {
+       "MODLOAD", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_modload, 2}}
+};
+
+struct Message modunload_msgtab = {
+       "MODUNLOAD", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_modunload, 2}}
+};
+
+struct Message modreload_msgtab = {
+       "MODRELOAD", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_modreload, 2}}
+};
+
+struct Message modlist_msgtab = {
+       "MODLIST", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_modlist, 0}}
+};
+
+struct Message modrestart_msgtab = {
+       "MODRESTART", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_modrestart, 0}}
+};
+
+extern struct Message error_msgtab;
+
+void
+modules_init(void)
+{
+       mod_add_cmd(&modload_msgtab);
+       mod_add_cmd(&modunload_msgtab);
+       mod_add_cmd(&modreload_msgtab);
+       mod_add_cmd(&modlist_msgtab);
+       mod_add_cmd(&modrestart_msgtab);
+
+       /* Add the default paths we look in to the module system --nenolod */
+       mod_add_path(MODPATH);
+       mod_add_path(AUTOMODPATH);
+}
+
+/* mod_find_path()
+ *
+ * input       - path
+ * output      - none
+ * side effects - returns a module path from path
+ */
+static struct module_path *
+mod_find_path(const char *path)
+{
+       dlink_node *ptr;
+       struct module_path *mpath;
+
+       DLINK_FOREACH(ptr, mod_paths.head)
+       {
+               mpath = ptr->data;
+
+               if(!strcmp(path, mpath->path))
+                       return mpath;
+       }
+
+       return NULL;
+}
+
+/* mod_add_path
+ *
+ * input       - path
+ * ouput       - 
+ * side effects - adds path to list
+ */
+void
+mod_add_path(const char *path)
+{
+       struct module_path *pathst;
+
+       if(mod_find_path(path))
+               return;
+
+       pathst = MyMalloc(sizeof(struct module_path));
+
+       strcpy(pathst->path, path);
+       dlinkAddAlloc(pathst, &mod_paths);
+}
+
+/* mod_clear_paths()
+ *
+ * input       -
+ * output      -
+ * side effects - clear the lists of paths
+ */
+void
+mod_clear_paths(void)
+{
+       dlink_node *ptr, *next_ptr;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, mod_paths.head)
+       {
+               MyFree(ptr->data);
+               free_dlink_node(ptr);
+       }
+
+       mod_paths.head = mod_paths.tail = NULL;
+       mod_paths.length = 0;
+}
+
+/* irc_basename
+ *
+ * input       -
+ * output      -
+ * side effects -
+ */
+char *
+irc_basename(const char *path)
+{
+       char *mod_basename = MyMalloc(strlen(path) + 1);
+       const char *s;
+
+       if(!(s = strrchr(path, '/')))
+               s = path;
+       else
+               s++;
+
+       (void) strcpy(mod_basename, s);
+       return mod_basename;
+}
+
+/* findmodule_byname
+ *
+ * input        -
+ * output       -
+ * side effects -
+ */
+
+int
+findmodule_byname(const char *name)
+{
+       int i;
+
+       for (i = 0; i < num_mods; i++)
+       {
+               if(!irccmp(modlist[i]->name, name))
+                       return i;
+       }
+       return -1;
+}
+
+/* load_all_modules()
+ *
+ * input        -
+ * output       -
+ * side effects -
+ */
+void
+load_all_modules(int warn)
+{
+       DIR *system_module_dir = NULL;
+       struct dirent *ldirent = NULL;
+       char module_fq_name[PATH_MAX + 1];
+       int len;
+
+       modules_init();
+
+       modlist = (struct module **) MyMalloc(sizeof(struct module) * (MODS_INCREMENT));
+
+       max_mods = MODS_INCREMENT;
+
+       system_module_dir = opendir(AUTOMODPATH);
+
+       if(system_module_dir == NULL)
+       {
+               ilog(L_MAIN, "Could not load modules from %s: %s", AUTOMODPATH, strerror(errno));
+               return;
+       }
+
+       while ((ldirent = readdir(system_module_dir)) != NULL)
+       {
+               len = strlen(ldirent->d_name);
+               if((len > 3) && !strcmp(ldirent->d_name+len-3, SHARED_SUFFIX))
+                {
+                       (void) ircsnprintf(module_fq_name, sizeof(module_fq_name), "%s/%s", AUTOMODPATH, ldirent->d_name);
+                       (void) load_a_module(module_fq_name, warn, 0);
+                }
+
+       }
+       (void) closedir(system_module_dir);
+}
+
+/* load_core_modules()
+ *
+ * input        -
+ * output       -
+ * side effects - core modules are loaded, if any fail, kill ircd
+ */
+void
+load_core_modules(int warn)
+{
+       char module_name[MAXPATHLEN];
+       int i;
+
+
+       for (i = 0; core_module_table[i]; i++)
+       {
+               ircsnprintf(module_name, sizeof(module_name), "%s/%s%s", MODPATH,
+                           core_module_table[i], SHARED_SUFFIX);
+
+               if(load_a_module(module_name, warn, 1) == -1)
+               {
+                       ilog(L_MAIN,
+                            "Error loading core module %s%s: terminating ircd",
+                            core_module_table[i], SHARED_SUFFIX);
+                       exit(0);
+               }
+       }
+}
+
+/* load_one_module()
+ *
+ * input        -
+ * output       -
+ * side effects -
+ */
+int
+load_one_module(const char *path, int coremodule)
+{
+       char modpath[MAXPATHLEN];
+       dlink_node *pathst;
+       struct module_path *mpath;
+
+       struct stat statbuf;
+
+       if (server_state_foreground == 1)
+               inotice("loading module %s ...", path); 
+
+       DLINK_FOREACH(pathst, mod_paths.head)
+       {
+               mpath = pathst->data;
+
+               ircsnprintf(modpath, sizeof(modpath), "%s/%s", mpath->path, path);
+               if((strstr(modpath, "../") == NULL) && (strstr(modpath, "/..") == NULL))
+               {
+                       if(stat(modpath, &statbuf) == 0)
+                       {
+                               if(S_ISREG(statbuf.st_mode))
+                               {
+                                       /* Regular files only please */
+                                       if(coremodule)
+                                               return load_a_module(modpath, 1, 1);
+                                       else
+                                               return load_a_module(modpath, 1, 0);
+                               }
+                       }
+
+               }
+       }
+
+       sendto_realops_snomask(SNO_GENERAL, L_ALL, "Cannot locate module %s", path);
+       return -1;
+}
+
+
+/* load a module .. */
+static int
+mo_modload(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
+{
+       char *m_bn;
+
+       if(!IsOperAdmin(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS),
+                          me.name, source_p->name, "admin");
+               return 0;
+       }
+
+       m_bn = irc_basename(parv[1]);
+
+       if(findmodule_byname(m_bn) != -1)
+       {
+               sendto_one(source_p,
+                          ":%s NOTICE %s :Module %s is already loaded",
+                          me.name, source_p->name, m_bn);
+               MyFree(m_bn);
+               return 0;
+       }
+
+       load_one_module(parv[1], 0);
+
+       MyFree(m_bn);
+
+       return 0;
+}
+
+
+/* unload a module .. */
+static int
+mo_modunload(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
+{
+       char *m_bn;
+       int modindex;
+
+       if(!IsOperAdmin(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS),
+                          me.name, source_p->name, "admin");
+               return 0;
+       }
+
+       m_bn = irc_basename(parv[1]);
+
+       if((modindex = findmodule_byname(m_bn)) == -1)
+       {
+               sendto_one(source_p,
+                          ":%s NOTICE %s :Module %s is not loaded", me.name, source_p->name, m_bn);
+               MyFree(m_bn);
+               return 0;
+       }
+
+       if(modlist[modindex]->core == 1)
+       {
+               sendto_one(source_p,
+                          ":%s NOTICE %s :Module %s is a core module and may not be unloaded",
+                          me.name, source_p->name, m_bn);
+               MyFree(m_bn);
+               return 0;
+       }
+
+       if(unload_one_module(m_bn, 1) == -1)
+       {
+               sendto_one(source_p,
+                          ":%s NOTICE %s :Module %s is not loaded", me.name, source_p->name, m_bn);
+       }
+       MyFree(m_bn);
+       return 0;
+}
+
+/* unload and load in one! */
+static int
+mo_modreload(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
+{
+       char *m_bn;
+       int modindex;
+       int check_core;
+
+       if(!IsOperAdmin(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS),
+                          me.name, source_p->name, "admin");
+               return 0;
+       }
+
+       m_bn = irc_basename(parv[1]);
+
+       if((modindex = findmodule_byname(m_bn)) == -1)
+       {
+               sendto_one(source_p,
+                          ":%s NOTICE %s :Module %s is not loaded", me.name, source_p->name, m_bn);
+               MyFree(m_bn);
+               return 0;
+       }
+
+       check_core = modlist[modindex]->core;
+
+       if(unload_one_module(m_bn, 1) == -1)
+       {
+               sendto_one(source_p,
+                          ":%s NOTICE %s :Module %s is not loaded", me.name, source_p->name, m_bn);
+               MyFree(m_bn);
+               return 0;
+       }
+
+       if((load_one_module(parv[1], check_core) == -1) && check_core)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Error reloading core module: %s: terminating ircd", parv[1]);
+               ilog(L_MAIN, "Error loading core module %s: terminating ircd", parv[1]);
+               exit(0);
+       }
+
+       MyFree(m_bn);
+       return 0;
+}
+
+/* list modules .. */
+static int
+mo_modlist(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
+{
+       int i;
+
+       if(!IsOperAdmin(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS),
+                          me.name, source_p->name, "admin");
+               return 0;
+       }
+
+       for (i = 0; i < num_mods; i++)
+       {
+               if(parc > 1)
+               {
+                       if(match(parv[1], modlist[i]->name))
+                       {
+                               sendto_one(source_p, form_str(RPL_MODLIST),
+                                          me.name, source_p->name,
+                                          modlist[i]->name,
+                                          modlist[i]->address,
+                                          modlist[i]->version, modlist[i]->core ? "(core)" : "");
+                       }
+               }
+               else
+               {
+                       sendto_one(source_p, form_str(RPL_MODLIST),
+                                  me.name, source_p->name, modlist[i]->name,
+                                  modlist[i]->address, modlist[i]->version,
+                                  modlist[i]->core ? "(core)" : "");
+               }
+       }
+
+       sendto_one(source_p, form_str(RPL_ENDOFMODLIST), me.name, source_p->name);
+       return 0;
+}
+
+/* unload and reload all modules */
+static int
+mo_modrestart(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
+{
+       int modnum;
+
+       if(!IsOperAdmin(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS),
+                          me.name, source_p->name, "admin");
+               return 0;
+       }
+
+       sendto_one(source_p, ":%s NOTICE %s :Reloading all modules", me.name, parv[0]);
+
+       modnum = num_mods;
+       while (num_mods)
+               unload_one_module(modlist[0]->name, 0);
+
+       load_all_modules(0);
+       load_core_modules(0);
+       rehash(0);
+
+       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                            "Module Restart: %d modules unloaded, %d modules loaded",
+                            modnum, num_mods);
+       ilog(L_MAIN, "Module Restart: %d modules unloaded, %d modules loaded", modnum, num_mods);
+       return 0;
+}
+
+
+
+#ifndef RTLD_NOW
+#define RTLD_NOW RTLD_LAZY     /* openbsd deficiency */
+#endif
+
+#ifdef CHARYBDIS_PROFILE
+# ifndef RTLD_PROFILE
+#  warning libdl may not support profiling, sucks. :(
+#  define RTLD_PROFILE 0
+# endif
+#endif
+
+static void increase_modlist(void);
+
+#define MODS_INCREMENT 10
+
+static char unknown_ver[] = "<unknown>";
+
+/* This file contains the core functions to use dynamic libraries.
+ * -TimeMr14C
+ */
+
+
+#ifdef HAVE_MACH_O_DYLD_H
+/*
+** jmallett's dl*(3) shims for NSModule(3) systems.
+*/
+#include <mach-o/dyld.h>
+
+#ifndef HAVE_DLOPEN
+#ifndef        RTLD_LAZY
+#define RTLD_LAZY 2185         /* built-in dl*(3) don't care */
+#endif
+
+void undefinedErrorHandler(const char *);
+NSModule multipleErrorHandler(NSSymbol, NSModule, NSModule);
+void linkEditErrorHandler(NSLinkEditErrors, int, const char *, const char *);
+char *dlerror(void);
+void *dlopen(char *, int);
+int dlclose(void *);
+void *dlsym(void *, char *);
+
+static int firstLoad = TRUE;
+static int myDlError;
+static char *myErrorTable[] = { "Loading file as object failed\n",
+       "Loading file as object succeeded\n",
+       "Not a valid shared object\n",
+       "Architecture of object invalid on this architecture\n",
+       "Invalid or corrupt image\n",
+       "Could not access object\n",
+       "NSCreateObjectFileImageFromFile failed\n",
+       NULL
+};
+
+void
+undefinedErrorHandler(const char *symbolName)
+{
+       sendto_realops_snomask(SNO_GENERAL, L_ALL, "Undefined symbol: %s", symbolName);
+       ilog(L_MAIN, "Undefined symbol: %s", symbolName);
+       return;
+}
+
+NSModule
+multipleErrorHandler(NSSymbol s, NSModule old, NSModule new)
+{
+       /* XXX
+        ** This results in substantial leaking of memory... Should free one
+        ** module, maybe?
+        */
+       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                            "Symbol `%s' found in `%s' and `%s'",
+                            NSNameOfSymbol(s), NSNameOfModule(old), NSNameOfModule(new));
+       ilog(L_MAIN, "Symbol `%s' found in `%s' and `%s'",
+            NSNameOfSymbol(s), NSNameOfModule(old), NSNameOfModule(new));
+       /* We return which module should be considered valid, I believe */
+       return new;
+}
+
+void
+linkEditErrorHandler(NSLinkEditErrors errorClass, int errnum,
+                    const char *fileName, const char *errorString)
+{
+       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                            "Link editor error: %s for %s", errorString, fileName);
+       ilog(L_MAIN, "Link editor error: %s for %s", errorString, fileName);
+       return;
+}
+
+char *
+dlerror(void)
+{
+       return myDlError == NSObjectFileImageSuccess ? NULL : myErrorTable[myDlError % 7];
+}
+
+void *
+dlopen(char *filename, int unused)
+{
+       NSObjectFileImage myImage;
+       NSModule myModule;
+
+       if(firstLoad)
+       {
+               /*
+                ** If we are loading our first symbol (huzzah!) we should go ahead
+                ** and install link editor error handling!
+                */
+               NSLinkEditErrorHandlers linkEditorErrorHandlers;
+
+               linkEditorErrorHandlers.undefined = undefinedErrorHandler;
+               linkEditorErrorHandlers.multiple = multipleErrorHandler;
+               linkEditorErrorHandlers.linkEdit = linkEditErrorHandler;
+               NSInstallLinkEditErrorHandlers(&linkEditorErrorHandlers);
+               firstLoad = FALSE;
+       }
+       myDlError = NSCreateObjectFileImageFromFile(filename, &myImage);
+       if(myDlError != NSObjectFileImageSuccess)
+       {
+               return NULL;
+       }
+       myModule = NSLinkModule(myImage, filename, NSLINKMODULE_OPTION_PRIVATE);
+       return (void *) myModule;
+}
+
+int
+dlclose(void *myModule)
+{
+       NSUnLinkModule(myModule, FALSE);
+       return 0;
+}
+
+void *
+dlsym(void *myModule, char *mySymbolName)
+{
+       NSSymbol mySymbol;
+
+       mySymbol = NSLookupSymbolInModule((NSModule) myModule, mySymbolName);
+       return NSAddressOfSymbol(mySymbol);
+}
+#endif
+#endif
+
+
+/*
+ * HPUX dl compat functions
+ */
+#if defined(HAVE_SHL_LOAD) && !defined(HAVE_DLOPEN)
+#define RTLD_LAZY BIND_DEFERRED
+#define RTLD_GLOBAL DYNAMIC_PATH
+#define dlopen(file,mode) (void *)shl_load((file), (mode), (long) 0)
+#define dlclose(handle) shl_unload((shl_t)(handle))
+#define dlsym(handle,name) hpux_dlsym(handle,name)
+#define dlerror() strerror(errno)
+
+static void *
+hpux_dlsym(void *handle, char *name)
+{
+       void *sym_addr;
+       if(!shl_findsym((shl_t *) & handle, name, TYPE_UNDEFINED, &sym_addr))
+               return sym_addr;
+       return NULL;
+}
+
+#endif
+
+/* unload_one_module()
+ *
+ * inputs      - name of module to unload
+ *             - 1 to say modules unloaded, 0 to not
+ * output      - 0 if successful, -1 if error
+ * side effects        - module is unloaded
+ */
+int
+unload_one_module(const char *name, int warn)
+{
+       int modindex;
+
+       if((modindex = findmodule_byname(name)) == -1)
+               return -1;
+
+       /*
+        ** XXX - The type system in C does not allow direct conversion between
+        ** data and function pointers, but as it happens, most C compilers will
+        ** safely do this, however it is a theoretical overlow to cast as we 
+        ** must do here.  I have library functions to take care of this, but 
+        ** despite being more "correct" for the C language, this is more 
+        ** practical.  Removing the abuse of the ability to cast ANY pointer
+        ** to and from an integer value here will break some compilers.
+        **          -jmallett
+        */
+       /* Left the comment in but the code isn't here any more         -larne */
+       switch (modlist[modindex]->mapi_version)
+       {
+       case 1:
+               {
+                       struct mapi_mheader_av1 *mheader = modlist[modindex]->mapi_header;
+                       if(mheader->mapi_command_list)
+                       {
+                               struct Message **m;
+                               for (m = mheader->mapi_command_list; *m; ++m)
+                                       mod_del_cmd(*m);
+                       }
+
+                       /* hook events are never removed, we simply lose the
+                        * ability to call them --fl
+                        */
+                       if(mheader->mapi_hfn_list)
+                       {
+                               mapi_hfn_list_av1 *m;
+                               for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
+                                       remove_hook(m->hapi_name, m->fn);
+                       }
+
+                       if(mheader->mapi_unregister)
+                               mheader->mapi_unregister();
+                       break;
+               }
+       default:
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Unknown/unsupported MAPI version %d when unloading %s!",
+                                    modlist[modindex]->mapi_version, modlist[modindex]->name);
+               ilog(L_MAIN, "Unknown/unsupported MAPI version %d when unloading %s!",
+                    modlist[modindex]->mapi_version, modlist[modindex]->name);
+               break;
+       }
+
+       dlclose(modlist[modindex]->address);
+
+       MyFree(modlist[modindex]->name);
+       memcpy(&modlist[modindex], &modlist[modindex + 1],
+              sizeof(struct module) * ((num_mods - 1) - modindex));
+
+       if(num_mods != 0)
+               num_mods--;
+
+       if(warn == 1)
+       {
+               ilog(L_MAIN, "Module %s unloaded", name);
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "Module %s unloaded", name);
+       }
+
+       return 0;
+}
+
+
+/*
+ * load_a_module()
+ *
+ * inputs      - path name of module, int to notice, int of core
+ * output      - -1 if error 0 if success
+ * side effects - loads a module if successful
+ */
+int
+load_a_module(const char *path, int warn, int core)
+{
+       void *tmpptr = NULL;
+
+       char *mod_basename;
+       const char *ver;
+
+       int *mapi_version;
+
+       mod_basename = irc_basename(path);
+
+#ifdef CHARYBDIS_PROFILE
+       tmpptr = dlopen(path, RTLD_NOW | RTLD_PROFILE);
+#else
+       tmpptr = dlopen(path, RTLD_NOW);
+#endif
+
+       if(tmpptr == NULL)
+       {
+               const char *err = dlerror();
+
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Error loading module %s: %s", mod_basename, err);
+               ilog(L_MAIN, "Error loading module %s: %s", mod_basename, err);
+               MyFree(mod_basename);
+               return -1;
+       }
+
+
+       /*
+        * _mheader is actually a struct mapi_mheader_*, but mapi_version
+        * is always the first member of this structure, so we treate it
+        * as a single int in order to determine the API version.
+        *      -larne.
+        */
+       mapi_version = (int *) (uintptr_t) dlsym(tmpptr, "_mheader");
+       if((mapi_version == NULL
+           && (mapi_version = (int *) (uintptr_t) dlsym(tmpptr, "__mheader")) == NULL)
+          || MAPI_MAGIC(*mapi_version) != MAPI_MAGIC_HDR)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Data format error: module %s has no MAPI header.",
+                                    mod_basename);
+               ilog(L_MAIN, "Data format error: module %s has no MAPI header.", mod_basename);
+               (void) dlclose(tmpptr);
+               MyFree(mod_basename);
+               return -1;
+       }
+
+       switch (MAPI_VERSION(*mapi_version))
+       {
+       case 1:
+               {
+                       struct mapi_mheader_av1 *mheader = (struct mapi_mheader_av1 *) mapi_version;    /* see above */
+                       if(mheader->mapi_register && (mheader->mapi_register() == -1))
+                       {
+                               ilog(L_MAIN, "Module %s indicated failure during load.",
+                                    mod_basename);
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                                    "Module %s indicated failure during load.",
+                                                    mod_basename);
+                               dlclose(tmpptr);
+                               MyFree(mod_basename);
+                               return -1;
+                       }
+                       if(mheader->mapi_command_list)
+                       {
+                               struct Message **m;
+                               for (m = mheader->mapi_command_list; *m; ++m)
+                                       mod_add_cmd(*m);
+                       }
+
+                       if(mheader->mapi_hook_list)
+                       {
+                               mapi_hlist_av1 *m;
+                               for (m = mheader->mapi_hook_list; m->hapi_name; ++m)
+                                       *m->hapi_id = register_hook(m->hapi_name);
+                       }
+
+                       if(mheader->mapi_hfn_list)
+                       {
+                               mapi_hfn_list_av1 *m;
+                               for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
+                                       add_hook(m->hapi_name, m->fn);
+                       }
+
+                       ver = mheader->mapi_module_version;
+                       break;
+               }
+
+       default:
+               ilog(L_MAIN, "Module %s has unknown/unsupported MAPI version %d.",
+                    mod_basename, MAPI_VERSION(*mapi_version));
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Module %s has unknown/unsupported MAPI version %d.",
+                                    mod_basename, *mapi_version);
+               dlclose(tmpptr);
+               MyFree(mod_basename);
+               return -1;
+       }
+
+       if(ver == NULL)
+               ver = unknown_ver;
+
+       increase_modlist();
+
+       modlist[num_mods] = MyMalloc(sizeof(struct module));
+       modlist[num_mods]->address = tmpptr;
+       modlist[num_mods]->version = ver;
+       modlist[num_mods]->core = core;
+       DupString(modlist[num_mods]->name, mod_basename);
+       modlist[num_mods]->mapi_header = mapi_version;
+       modlist[num_mods]->mapi_version = MAPI_VERSION(*mapi_version);
+       num_mods++;
+
+       if(warn == 1)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Module %s [version: %s; MAPI version: %d] loaded at 0x%lx",
+                                    mod_basename, ver, MAPI_VERSION(*mapi_version),
+                                    (unsigned long) tmpptr);
+               ilog(L_MAIN, "Module %s [version: %s; MAPI version: %d] loaded at 0x%lx",
+                    mod_basename, ver, MAPI_VERSION(*mapi_version), (unsigned long) tmpptr);
+       }
+       MyFree(mod_basename);
+       return 0;
+}
+
+/*
+ * increase_modlist
+ *
+ * inputs      - NONE
+ * output      - NONE
+ * side effects        - expand the size of modlist if necessary
+ */
+static void
+increase_modlist(void)
+{
+       struct module **new_modlist = NULL;
+
+       if((num_mods + 1) < max_mods)
+               return;
+
+       new_modlist = (struct module **) MyMalloc(sizeof(struct module) *
+                                                 (max_mods + MODS_INCREMENT));
+       memcpy((void *) new_modlist, (void *) modlist, sizeof(struct module) * num_mods);
+
+       MyFree(modlist);
+       modlist = new_modlist;
+       max_mods += MODS_INCREMENT;
+}
+
+#else /* STATIC_MODULES */
+
+/* load_all_modules()
+ *
+ * input        -
+ * output       -
+ * side effects - all the msgtabs are added for static modules
+ */
+void
+load_all_modules(int warn)
+{
+       load_static_modules();
+}
+
+#endif /* STATIC_MODULES */
diff --git a/src/monitor.c b/src/monitor.c
new file mode 100644 (file)
index 0000000..c0a6694
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * ircd-ratbox: an advanced Internet Relay Chat Daemon(ircd).
+ * monitor.c - Code for server-side notify lists
+ *
+ * Copyright (C) 2005 Lee Hardy <lee -at- leeh.co.uk>
+ * Copyright (C) 2005 ircd-ratbox development team
+ *
+ * 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.The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: monitor.c 312 2005-11-07 10:47:33Z jilles $
+ */
+#include "stdinc.h"
+#include "tools.h"
+#include "client.h"
+#include "memory.h"
+#include "balloc.h"
+#include "monitor.h"
+#include "hash.h"
+#include "event.h"
+#include "numeric.h"
+
+static struct monitor *monitorTable[MONITOR_HASH_SIZE];
+BlockHeap *monitor_heap;
+
+static void cleanup_monitor(void *unused);
+
+void
+init_monitor(void)
+{
+       monitor_heap = BlockHeapCreate(sizeof(struct monitor), MONITOR_HEAP_SIZE);
+       eventAddIsh("cleanup_monitor", cleanup_monitor, NULL, 3600);
+}
+
+static inline unsigned int
+hash_monitor_nick(const char *name)
+{
+       return fnv_hash_upper((const unsigned char *) name, MONITOR_HASH_BITS);
+}
+
+struct monitor *
+find_monitor(const char *name, int add)
+{
+       struct monitor *monptr;
+
+       unsigned int hashv = hash_monitor_nick(name);
+
+       for(monptr = monitorTable[hashv]; monptr; monptr = monptr->hnext)
+       {
+               if(!irccmp(monptr->name, name))
+                       return monptr;
+       }
+
+       if(add)
+       {
+               monptr = BlockHeapAlloc(monitor_heap);
+               strlcpy(monptr->name, name, sizeof(monptr->name));
+
+               monptr->hnext = monitorTable[hashv];
+               monitorTable[hashv] = monptr;
+
+               return monptr;
+       }
+
+       return NULL;
+}
+
+/* monitor_signon()
+ *
+ * inputs      - client who has just connected
+ * outputs     -
+ * side effects        - notifies any clients monitoring this nickname that it has
+ *               connected to the network
+ */
+void
+monitor_signon(struct Client *client_p)
+{
+       char buf[USERHOST_REPLYLEN];
+       struct monitor *monptr = find_monitor(client_p->name, 0);
+       struct Client *target_p;
+       dlink_node *ptr;
+
+       /* noones watching this nick */
+       if(monptr == NULL)
+               return;
+
+       ircsnprintf(buf, sizeof(buf), "%s!%s@%s",
+                   client_p->name, client_p->username, client_p->host);
+
+       DLINK_FOREACH(ptr, monptr->users.head)
+       {
+               target_p = ptr->data;
+
+               sendto_one(target_p, form_str(RPL_MONONLINE),
+                               me.name, target_p->name, buf);
+       }
+}
+
+/* monitor_signoff()
+ *
+ * inputs      - client who is exiting
+ * outputs     -
+ * side effects        - notifies any clients monitoring this nickname that it has
+ *               left the network
+ */
+void
+monitor_signoff(struct Client *client_p)
+{
+       struct monitor *monptr = find_monitor(client_p->name, 0);
+       dlink_node *ptr;
+
+       /* noones watching this nick */
+       if(monptr == NULL)
+               return;
+
+       DLINK_FOREACH(ptr, monptr->users.head)
+       {
+               sendto_one(ptr->data, form_str(RPL_MONOFFLINE),
+                               me.name, ((struct Client *) ptr->data)->name, client_p->name);
+       }
+}
+
+void
+clear_monitor(struct Client *client_p)
+{
+       struct monitor *monptr;
+       dlink_node *ptr, *next_ptr;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->localClient->monitor_list.head)
+       {
+               monptr = ptr->data;
+
+               /* we leave the actual entry around with no users, itll be
+                * cleaned up periodically by cleanup_monitor() --anfl
+                */
+               dlinkFindDestroy(client_p, &monptr->users);
+               free_dlink_node(ptr);
+       }
+
+       client_p->localClient->monitor_list.head = client_p->localClient->monitor_list.tail = NULL;
+       client_p->localClient->monitor_list.length = 0;
+}
+
+static void
+cleanup_monitor(void *unused)
+{
+       struct monitor *last_ptr = NULL;
+       struct monitor *next_ptr, *ptr;
+       int i;
+
+       for(i = 0; i < MONITOR_HASH_SIZE; i++)
+       {
+               last_ptr = NULL;
+               for(ptr = monitorTable[i]; ptr; ptr = next_ptr)
+               {
+                       next_ptr = ptr->hnext;
+
+                       if(!dlink_list_length(&ptr->users))
+                       {
+                               if(last_ptr)
+                                       last_ptr->hnext = next_ptr;
+                               else
+                                       monitorTable[i] = next_ptr;
+
+                               BlockHeapFree(monitor_heap, ptr);
+                       }
+                       else
+                               last_ptr = ptr;
+               }
+       }
+}
diff --git a/src/newconf.c b/src/newconf.c
new file mode 100644 (file)
index 0000000..7e2a376
--- /dev/null
@@ -0,0 +1,2159 @@
+/* This code is in the public domain.
+ * $Id: newconf.c 3131 2007-01-21 15:36:31Z jilles $
+ */
+
+#include "stdinc.h"
+
+#ifdef HAVE_LIBCRYPTO
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
+#endif
+
+#include "memory.h"
+#include "newconf.h"
+#include "tools.h"
+#include "ircd_defs.h"
+#include "sprintf_irc.h"
+#include "common.h"
+#include "s_log.h"
+#include "s_conf.h"
+#include "s_user.h"
+#include "s_newconf.h"
+#include "send.h"
+#include "setup.h"
+#include "modules.h"
+#include "listener.h"
+#include "hostmask.h"
+#include "s_serv.h"
+#include "event.h"
+#include "hash.h"
+#include "cache.h"
+#include "ircd.h"
+#include "snomask.h"
+#include "blacklist.h"
+
+#define CF_TYPE(x) ((x) & CF_MTYPE)
+
+struct TopConf *conf_cur_block;
+static char *conf_cur_block_name;
+
+static dlink_list conf_items;
+
+static struct ConfItem *yy_aconf = NULL;
+
+static struct Class *yy_class = NULL;
+
+static struct remote_conf *yy_shared = NULL;
+static struct server_conf *yy_server = NULL;
+
+static dlink_list yy_aconf_list;
+static dlink_list yy_oper_list;
+static dlink_list yy_shared_list;
+static dlink_list yy_cluster_list;
+static struct oper_conf *yy_oper = NULL;
+
+static struct alias_entry *yy_alias = NULL;
+
+static char *yy_blacklist_host = NULL;
+static char *yy_blacklist_reason = NULL;
+
+static const char *
+conf_strtype(int type)
+{
+       switch (type & CF_MTYPE)
+       {
+       case CF_INT:
+               return "integer value";
+       case CF_STRING:
+               return "unquoted string";
+       case CF_YESNO:
+               return "yes/no value";
+       case CF_QSTRING:
+               return "quoted string";
+       case CF_TIME:
+               return "time/size value";
+       default:
+               return "unknown type";
+       }
+}
+
+int
+add_top_conf(const char *name, int (*sfunc) (struct TopConf *), 
+               int (*efunc) (struct TopConf *), struct ConfEntry *items)
+{
+       struct TopConf *tc;
+
+       tc = MyMalloc(sizeof(struct TopConf));
+
+       DupString(tc->tc_name, name);
+       tc->tc_sfunc = sfunc;
+       tc->tc_efunc = efunc;
+       tc->tc_entries = items;
+
+       dlinkAddAlloc(tc, &conf_items);
+       return 0;
+}
+
+struct TopConf *
+find_top_conf(const char *name)
+{
+       dlink_node *d;
+       struct TopConf *tc;
+
+       DLINK_FOREACH(d, conf_items.head)
+       {
+               tc = d->data;
+               if(strcasecmp(tc->tc_name, name) == 0)
+                       return tc;
+       }
+
+       return NULL;
+}
+
+
+struct ConfEntry *
+find_conf_item(const struct TopConf *top, const char *name)
+{
+       struct ConfEntry *cf;
+       dlink_node *d;
+
+       if(top->tc_entries)
+       {
+               int i;
+
+               for(i = 0; top->tc_entries[i].cf_type; i++)
+               {
+                       cf = &top->tc_entries[i];
+
+                       if(!strcasecmp(cf->cf_name, name))
+                               return cf;
+               }
+       }
+
+       DLINK_FOREACH(d, top->tc_items.head)
+       {
+               cf = d->data;
+               if(strcasecmp(cf->cf_name, name) == 0)
+                       return cf;
+       }
+
+       return NULL;
+}
+
+int
+remove_top_conf(char *name)
+{
+       struct TopConf *tc;
+       dlink_node *ptr;
+
+       if((tc = find_top_conf(name)) == NULL)
+               return -1;
+
+       if((ptr = dlinkFind(tc, &conf_items)) == NULL)
+               return -1;
+
+       dlinkDestroy(ptr, &conf_items);
+       MyFree(tc->tc_name);
+       MyFree(tc);
+
+       return 0;
+}
+
+static void
+conf_set_serverinfo_name(void *data)
+{
+       if(ServerInfo.name == NULL)
+       {
+               const char *s;
+               int dots = 0;
+
+               for(s = data; *s != '\0'; s++)
+               {
+                       if(!IsServChar(*s))
+                       {
+                               conf_report_error("Ignoring serverinfo::name "
+                                                 "-- bogus servername.");
+                               return;
+                       }
+                       else if(*s == '.')
+                               ++dots;
+               }
+
+               if(!dots)
+               {
+                       conf_report_error("Ignoring serverinfo::name -- must contain '.'");
+                       return;
+               }
+
+               s = data;
+
+               if(IsDigit(*s))
+               {
+                       conf_report_error("Ignoring serverinfo::name -- cannot begin with digit.");
+                       return;
+               }
+
+               /* the ircd will exit() in main() if we dont set one */
+               if(strlen(s) <= HOSTLEN)
+                       DupString(ServerInfo.name, (char *) data);
+       }
+}
+
+static void
+conf_set_serverinfo_sid(void *data)
+{
+       char *sid = data;
+
+       if(ServerInfo.sid[0] == '\0')
+       {
+               if(!IsDigit(sid[0]) || !IsIdChar(sid[1]) ||
+                  !IsIdChar(sid[2]) || sid[3] != '\0')
+               {
+                       conf_report_error("Ignoring serverinfo::sid "
+                                         "-- bogus sid.");
+                       return;
+               }
+
+               strcpy(ServerInfo.sid, sid);
+       }
+}
+
+static void
+conf_set_serverinfo_network_name(void *data)
+{
+       char *p;
+
+       if((p = strchr((char *) data, ' ')))
+               *p = '\0';
+
+       MyFree(ServerInfo.network_name);
+       DupString(ServerInfo.network_name, (char *) data);
+}
+
+static void
+conf_set_serverinfo_vhost(void *data)
+{
+       if(inetpton(AF_INET, (char *) data, &ServerInfo.ip.sin_addr) <= 0)
+       {
+               conf_report_error("Invalid netmask for server IPv4 vhost (%s)", (char *) data);
+               return;
+       }
+       ServerInfo.ip.sin_family = AF_INET;
+       ServerInfo.specific_ipv4_vhost = 1;
+}
+
+static void
+conf_set_serverinfo_vhost6(void *data)
+{
+#ifdef IPV6
+       if(inetpton(AF_INET6, (char *) data, &ServerInfo.ip6.sin6_addr) <= 0)
+       {
+               conf_report_error("Invalid netmask for server IPv6 vhost (%s)", (char *) data);
+               return;
+       }
+
+       ServerInfo.specific_ipv6_vhost = 1;
+       ServerInfo.ip6.sin6_family = AF_INET6;
+#else
+       conf_report_error("Warning -- ignoring serverinfo::vhost6 -- IPv6 support not available.");
+#endif
+}
+
+static void
+conf_set_modules_module(void *data)
+{
+#ifndef STATIC_MODULES
+       char *m_bn;
+
+       m_bn = irc_basename((char *) data);
+
+       if(findmodule_byname(m_bn) != -1)
+               return;
+
+       load_one_module((char *) data, 0);
+
+       MyFree(m_bn);
+#else
+       conf_report_error("Ignoring modules::module -- loadable module support not present.");
+#endif
+}
+
+static void
+conf_set_modules_path(void *data)
+{
+#ifndef STATIC_MODULES
+       mod_add_path((char *) data);
+#else
+       conf_report_error("Ignoring modules::path -- loadable module support not present.");
+#endif
+}
+
+struct mode_table
+{
+       const char *name;
+       int mode;
+};
+
+/* *INDENT-OFF* */
+static struct mode_table umode_table[] = {
+       {"callerid",    UMODE_CALLERID  },
+       {"deaf",        UMODE_DEAF      },
+       {"invisible",   UMODE_INVISIBLE },
+       {"locops",      UMODE_LOCOPS    },
+       {"noforward",   UMODE_NOFORWARD },
+       {"regonlymsg",  UMODE_REGONLYMSG},
+       {"servnotice",  UMODE_SERVNOTICE},
+       {"wallop",      UMODE_WALLOP    },
+       {"operwall",    UMODE_OPERWALL  },
+       {NULL, 0}
+};
+
+static struct mode_table flag_table[] = {
+       {"encrypted",           OPER_ENCRYPTED          },
+       {"local_kill",          OPER_LOCKILL            },
+       {"global_kill",         OPER_GLOBKILL|OPER_LOCKILL      },
+       {"remote",              OPER_REMOTE             },
+       {"kline",               OPER_KLINE              },
+       {"unkline",             OPER_UNKLINE            },
+       {"gline",               OPER_GLINE              },
+       {"nick_changes",        OPER_NICKS              },
+       {"rehash",              OPER_REHASH             },
+       {"die",                 OPER_DIE                },
+       {"admin",               OPER_ADMIN              },
+       {"hidden_admin",        OPER_HADMIN             },
+       {"xline",               OPER_XLINE              },
+       {"operwall",            OPER_OPERWALL           },
+       {"oper_spy",            OPER_SPY                },
+       {"hidden_oper",         OPER_INVIS              },
+       {"remoteban",           OPER_REMOTEBAN          },
+       {NULL, 0}
+};
+
+static struct mode_table auth_table[] = {
+       {"encrypted",           CONF_FLAGS_ENCRYPTED    },
+       {"spoof_notice",        CONF_FLAGS_SPOOF_NOTICE },
+       {"exceed_limit",        CONF_FLAGS_NOLIMIT      },
+       {"dnsbl_exempt",        CONF_FLAGS_EXEMPTDNSBL  },
+       {"kline_exempt",        CONF_FLAGS_EXEMPTKLINE  },
+       {"gline_exempt",        CONF_FLAGS_EXEMPTGLINE  },
+       {"flood_exempt",        CONF_FLAGS_EXEMPTFLOOD  },
+       {"spambot_exempt",      CONF_FLAGS_EXEMPTSPAMBOT },
+       {"shide_exempt",        CONF_FLAGS_EXEMPTSHIDE  },
+       {"jupe_exempt",         CONF_FLAGS_EXEMPTJUPE   },
+       {"resv_exempt",         CONF_FLAGS_EXEMPTRESV   },
+       {"no_tilde",            CONF_FLAGS_NO_TILDE     },
+       {"need_ident",          CONF_FLAGS_NEED_IDENTD  },
+       {"have_ident",          CONF_FLAGS_NEED_IDENTD  },
+       {"need_sasl",           CONF_FLAGS_NEED_SASL    },
+       {NULL, 0}
+};
+
+static struct mode_table connect_table[] = {
+       { "autoconn",   SERVER_AUTOCONN         },
+       { "compressed", SERVER_COMPRESSED       },
+       { "encrypted",  SERVER_ENCRYPTED        },
+       { "topicburst", SERVER_TB               },
+       { NULL,         0                       },
+};
+
+static struct mode_table cluster_table[] = {
+       { "kline",      SHARED_PKLINE   },
+       { "tkline",     SHARED_TKLINE   },
+       { "unkline",    SHARED_UNKLINE  },
+       { "locops",     SHARED_LOCOPS   },
+       { "xline",      SHARED_PXLINE   },
+       { "txline",     SHARED_TXLINE   },
+       { "unxline",    SHARED_UNXLINE  },
+       { "resv",       SHARED_PRESV    },
+       { "tresv",      SHARED_TRESV    },
+       { "unresv",     SHARED_UNRESV   },
+       { "all",        CLUSTER_ALL     },
+       {NULL, 0}
+};
+
+static struct mode_table shared_table[] =
+{
+       { "kline",      SHARED_PKLINE|SHARED_TKLINE     },
+       { "xline",      SHARED_PXLINE|SHARED_TXLINE     },
+       { "resv",       SHARED_PRESV|SHARED_TRESV       },
+       { "tkline",     SHARED_TKLINE   },
+       { "unkline",    SHARED_UNKLINE  },
+       { "txline",     SHARED_TXLINE   },
+       { "unxline",    SHARED_UNXLINE  },
+       { "tresv",      SHARED_TRESV    },
+       { "unresv",     SHARED_UNRESV   },
+       { "locops",     SHARED_LOCOPS   },
+       { "rehash",     SHARED_REHASH   },
+       { "all",        SHARED_ALL      },
+       { "none",       0               },
+       {NULL, 0}
+};
+/* *INDENT-ON* */
+
+static int
+find_umode(struct mode_table *tab, const char *name)
+{
+       int i;
+
+       for (i = 0; tab[i].name; i++)
+       {
+               if(strcmp(tab[i].name, name) == 0)
+                       return tab[i].mode;
+       }
+
+       return -1;
+}
+
+static void
+set_modes_from_table(int *modes, const char *whatis, struct mode_table *tab, conf_parm_t * args)
+{
+       for (; args; args = args->next)
+       {
+               const char *umode;
+               int dir = 1;
+               int mode;
+
+               if((args->type & CF_MTYPE) != CF_STRING)
+               {
+                       conf_report_error("Warning -- %s is not a string; ignoring.", whatis);
+                       continue;
+               }
+
+               umode = args->v.string;
+
+               if(*umode == '~')
+               {
+                       dir = 0;
+                       umode++;
+               }
+
+               mode = find_umode(tab, umode);
+
+               if(mode == -1)
+               {
+                       conf_report_error("Warning -- unknown %s %s.", whatis, args->v.string);
+                       continue;
+               }
+
+               if(mode)
+               {
+                       if(dir)
+                               *modes |= mode;
+                       else
+                               *modes &= ~mode;
+               }
+               else
+                       *modes = 0;
+       }
+}
+
+static int
+conf_begin_oper(struct TopConf *tc)
+{
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+
+       if(yy_oper != NULL)
+       {
+               free_oper_conf(yy_oper);
+               yy_oper = NULL;
+       }
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, yy_oper_list.head)
+       {
+               free_oper_conf(ptr->data);
+               dlinkDestroy(ptr, &yy_oper_list);
+       }
+
+       yy_oper = make_oper_conf();
+       yy_oper->flags |= OPER_ENCRYPTED|OPER_OPERWALL|OPER_REMOTEBAN;
+
+       return 0;
+}
+
+static int
+conf_end_oper(struct TopConf *tc)
+{
+       struct oper_conf *yy_tmpoper;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+
+       if(conf_cur_block_name != NULL)
+       {
+               if(strlen(conf_cur_block_name) > OPERNICKLEN)
+                       conf_cur_block_name[OPERNICKLEN] = '\0';
+
+               DupString(yy_oper->name, conf_cur_block_name);
+       }
+
+       if(EmptyString(yy_oper->name))
+       {
+               conf_report_error("Ignoring operator block -- missing name.");
+               return 0;
+       }
+
+#ifdef HAVE_LIBCRYPTO
+       if(EmptyString(yy_oper->passwd) && EmptyString(yy_oper->rsa_pubkey_file))
+#else
+       if(EmptyString(yy_oper->passwd))
+#endif
+       {
+               conf_report_error("Ignoring operator block for %s -- missing password",
+                                       yy_oper->name);
+               return 0;
+       }
+
+       /* now, yy_oper_list contains a stack of oper_conf's with just user
+        * and host in, yy_oper contains the rest of the information which
+        * we need to copy into each element in yy_oper_list
+        */
+       DLINK_FOREACH_SAFE(ptr, next_ptr, yy_oper_list.head)
+       {
+               yy_tmpoper = ptr->data;
+
+               DupString(yy_tmpoper->name, yy_oper->name);
+
+               /* could be an rsa key instead.. */
+               if(!EmptyString(yy_oper->passwd))
+                       DupString(yy_tmpoper->passwd, yy_oper->passwd);
+
+               yy_tmpoper->flags = yy_oper->flags;
+               yy_tmpoper->umodes = yy_oper->umodes;
+               yy_tmpoper->snomask = yy_oper->snomask;
+
+#ifdef HAVE_LIBCRYPTO
+               if(yy_oper->rsa_pubkey_file)
+               {
+                       BIO *file;
+
+                       if((file = BIO_new_file(yy_oper->rsa_pubkey_file, "r")) == NULL)
+                       {
+                               conf_report_error("Ignoring operator block for %s -- "
+                                               "rsa_public_key_file cant be opened",
+                                               yy_tmpoper->name);
+                               return 0;
+                       }
+                               
+                       yy_tmpoper->rsa_pubkey =
+                               (RSA *) PEM_read_bio_RSA_PUBKEY(file, NULL, 0, NULL);
+
+                       BIO_set_close(file, BIO_CLOSE);
+                       BIO_free(file);
+
+                       if(yy_tmpoper->rsa_pubkey == NULL)
+                       {
+                               conf_report_error("Ignoring operator block for %s -- "
+                                               "rsa_public_key_file key invalid; check syntax",
+                                               yy_tmpoper->name);
+                               return 0;
+                       }
+               }
+#endif
+
+               /* all is ok, put it on oper_conf_list */
+               dlinkMoveNode(ptr, &yy_oper_list, &oper_conf_list);
+       }
+
+       free_oper_conf(yy_oper);
+       yy_oper = NULL;
+
+       return 0;
+}
+
+static void
+conf_set_oper_flags(void *data)
+{
+       conf_parm_t *args = data;
+
+       set_modes_from_table(&yy_oper->flags, "flag", flag_table, args);
+}
+
+static void
+conf_set_oper_user(void *data)
+{
+       struct oper_conf *yy_tmpoper;
+       char *p;
+       char *host = (char *) data;
+
+       yy_tmpoper = make_oper_conf();
+
+       if((p = strchr(host, '@')))
+       {
+               *p++ = '\0';
+
+               DupString(yy_tmpoper->username, host);
+               DupString(yy_tmpoper->host, p);
+       }
+       else
+       {
+
+               DupString(yy_tmpoper->username, "*");
+               DupString(yy_tmpoper->host, host);
+       }
+
+       if(EmptyString(yy_tmpoper->username) || EmptyString(yy_tmpoper->host))
+       {
+               conf_report_error("Ignoring user -- missing username/host");
+               free_oper_conf(yy_tmpoper);
+               return;
+       }
+
+       dlinkAddAlloc(yy_tmpoper, &yy_oper_list);
+}
+
+static void
+conf_set_oper_password(void *data)
+{
+       if(yy_oper->passwd)
+       {
+               memset(yy_oper->passwd, 0, strlen(yy_oper->passwd));
+               MyFree(yy_oper->passwd);
+       }
+
+       DupString(yy_oper->passwd, (char *) data);
+}
+
+static void
+conf_set_oper_rsa_public_key_file(void *data)
+{
+#ifdef HAVE_LIBCRYPTO
+       MyFree(yy_oper->rsa_pubkey_file);
+       DupString(yy_oper->rsa_pubkey_file, (char *) data);
+#else
+       conf_report_error("Warning -- ignoring rsa_public_key_file (OpenSSL support not available");
+#endif
+}
+
+static void
+conf_set_oper_umodes(void *data)
+{
+       set_modes_from_table(&yy_oper->umodes, "umode", umode_table, data);
+}
+
+static void
+conf_set_oper_snomask(void *data)
+{
+       yy_oper->snomask = parse_snobuf_to_mask(0, (const char *) data);
+}
+
+static int
+conf_begin_class(struct TopConf *tc)
+{
+       if(yy_class)
+               free_class(yy_class);
+
+       yy_class = make_class();
+       return 0;
+}
+
+static int
+conf_end_class(struct TopConf *tc)
+{
+       if(conf_cur_block_name != NULL)
+               DupString(yy_class->class_name, conf_cur_block_name);
+
+       if(EmptyString(yy_class->class_name))
+       {
+               conf_report_error("Ignoring connect block -- missing name.");
+               return 0;
+       }
+
+       add_class(yy_class);
+       yy_class = NULL;
+       return 0;
+}
+
+static void
+conf_set_class_ping_time(void *data)
+{
+       yy_class->ping_freq = *(unsigned int *) data;
+}
+
+static void
+conf_set_class_cidr_bitlen(void *data)
+{
+#ifdef IPV6
+       unsigned int maxsize = 128;
+#else
+       unsigned int maxsize = 32;
+#endif
+       if(*(unsigned int *) data > maxsize)
+               conf_report_error
+                       ("class::cidr_bitlen argument exceeds maxsize (%d > %d) - ignoring.",
+                        *(unsigned int *) data, maxsize);
+       else
+               yy_class->cidr_bitlen = *(unsigned int *) data;
+
+}
+static void
+conf_set_class_number_per_cidr(void *data)
+{
+       yy_class->cidr_amount = *(unsigned int *) data;
+}
+
+static void
+conf_set_class_number_per_ip(void *data)
+{
+       yy_class->max_local = *(unsigned int *) data;
+}
+
+
+static void
+conf_set_class_number_per_ip_global(void *data)
+{
+       yy_class->max_global = *(unsigned int *) data;
+}
+
+static void
+conf_set_class_number_per_ident(void *data)
+{
+       yy_class->max_ident = *(unsigned int *) data;
+}
+
+static void
+conf_set_class_connectfreq(void *data)
+{
+       yy_class->con_freq = *(unsigned int *) data;
+}
+
+static void
+conf_set_class_max_number(void *data)
+{
+       yy_class->max_total = *(unsigned int *) data;
+}
+
+static void
+conf_set_class_sendq(void *data)
+{
+       yy_class->max_sendq = *(unsigned int *) data;
+}
+
+static char *listener_address;
+
+static int
+conf_begin_listen(struct TopConf *tc)
+{
+       MyFree(listener_address);
+       listener_address = NULL;
+       return 0;
+}
+
+static int
+conf_end_listen(struct TopConf *tc)
+{
+       MyFree(listener_address);
+       listener_address = NULL;
+       return 0;
+}
+
+static void
+conf_set_listen_port(void *data)
+{
+       conf_parm_t *args = data;
+       for (; args; args = args->next)
+       {
+               if((args->type & CF_MTYPE) != CF_INT)
+               {
+                       conf_report_error
+                               ("listener::port argument is not an integer " "-- ignoring.");
+                       continue;
+               }
+                if(listener_address == NULL)
+                {
+                       add_listener(args->v.number, listener_address, AF_INET);
+#ifdef IPV6
+                       add_listener(args->v.number, listener_address, AF_INET6);
+#endif
+                }
+               else
+                {
+                       int family;
+#ifdef IPV6
+                       if(strchr(listener_address, ':') != NULL)
+                               family = AF_INET6;
+                       else 
+#endif
+                               family = AF_INET;
+               
+                       add_listener(args->v.number, listener_address, family);
+                
+                }
+
+       }
+}
+
+static void
+conf_set_listen_address(void *data)
+{
+       MyFree(listener_address);
+       DupString(listener_address, data);
+}
+
+static int
+conf_begin_auth(struct TopConf *tc)
+{
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+
+       if(yy_aconf)
+               free_conf(yy_aconf);
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, yy_aconf_list.head)
+       {
+               free_conf(ptr->data);
+               dlinkDestroy(ptr, &yy_aconf_list);
+       }
+
+       yy_aconf = make_conf();
+       yy_aconf->status = CONF_CLIENT;
+
+       return 0;
+}
+
+static int
+conf_end_auth(struct TopConf *tc)
+{
+       struct ConfItem *yy_tmp;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+
+       if(EmptyString(yy_aconf->name))
+               DupString(yy_aconf->name, "NOMATCH");
+
+       /* didnt even get one ->host? */
+       if(EmptyString(yy_aconf->host))
+       {
+               conf_report_error("Ignoring auth block -- missing user@host");
+               return 0;
+       }
+
+       /* so the stacking works in order.. */
+       collapse(yy_aconf->user);
+       collapse(yy_aconf->host);
+       conf_add_class_to_conf(yy_aconf);
+       add_conf_by_address(yy_aconf->host, CONF_CLIENT, yy_aconf->user, yy_aconf);
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, yy_aconf_list.head)
+       {
+               yy_tmp = ptr->data;
+
+               if(yy_aconf->passwd)
+                       DupString(yy_tmp->passwd, yy_aconf->passwd);
+
+               /* this will always exist.. */
+               DupString(yy_tmp->name, yy_aconf->name);
+
+               if(yy_aconf->className)
+                       DupString(yy_tmp->className, yy_aconf->className);
+
+               yy_tmp->flags = yy_aconf->flags;
+               yy_tmp->port = yy_aconf->port;
+
+               collapse(yy_tmp->user);
+               collapse(yy_tmp->host);
+
+               conf_add_class_to_conf(yy_tmp);
+
+               add_conf_by_address(yy_tmp->host, CONF_CLIENT, yy_tmp->user, yy_tmp);
+               dlinkDestroy(ptr, &yy_aconf_list);
+       }
+
+       yy_aconf = NULL;
+       return 0;
+}
+
+static void
+conf_set_auth_user(void *data)
+{
+       struct ConfItem *yy_tmp;
+       char *p;
+
+       /* The first user= line doesn't allocate a new conf */
+       if(!EmptyString(yy_aconf->host))
+       {
+               yy_tmp = make_conf();
+               yy_tmp->status = CONF_CLIENT;
+       }
+       else
+               yy_tmp = yy_aconf;
+
+       if((p = strchr(data, '@')))
+       {
+               *p++ = '\0';
+
+               DupString(yy_tmp->user, data);
+               DupString(yy_tmp->host, p);
+       }
+       else
+       {
+               DupString(yy_tmp->user, "*");
+               DupString(yy_tmp->host, data);
+       }
+
+       if(yy_aconf != yy_tmp)
+               dlinkAddAlloc(yy_tmp, &yy_aconf_list);
+}
+
+static void
+conf_set_auth_passwd(void *data)
+{
+       if(yy_aconf->passwd)
+               memset(yy_aconf->passwd, 0, strlen(yy_aconf->passwd));
+       MyFree(yy_aconf->passwd);
+       DupString(yy_aconf->passwd, data);
+}
+
+static void
+conf_set_auth_spoof(void *data)
+{
+       char *p;
+       char *user = NULL;
+       char *host = NULL;
+
+       host = data;
+
+       /* user@host spoof */
+       if((p = strchr(host, '@')) != NULL)
+       {
+               *p = '\0';
+               user = data;
+               host = p+1;
+
+               if(EmptyString(user))
+               {
+                       conf_report_error("Warning -- spoof ident empty.");
+                       return;
+               }
+
+               if(strlen(user) > USERLEN)
+               {
+                       conf_report_error("Warning -- spoof ident length invalid.");
+                       return;
+               }
+
+               if(!valid_username(user))
+               {
+                       conf_report_error("Warning -- invalid spoof (ident).");
+                       return;
+               }
+
+               /* this must be restored! */
+               *p = '@';
+       }
+
+       if(EmptyString(host))
+       {
+               conf_report_error("Warning -- spoof host empty.");
+               return;
+       }
+
+       if(strlen(host) > HOSTLEN)
+       {
+               conf_report_error("Warning -- spoof host length invalid.");
+               return;
+       }
+
+       if(!valid_hostname(host))
+       {
+               conf_report_error("Warning -- invalid spoof (host).");
+               return;
+       }
+
+       MyFree(yy_aconf->name);
+       DupString(yy_aconf->name, data);
+       yy_aconf->flags |= CONF_FLAGS_SPOOF_IP;
+}
+
+static void
+conf_set_auth_flags(void *data)
+{
+       conf_parm_t *args = data;
+
+       set_modes_from_table((int *) &yy_aconf->flags, "flag", auth_table, args);
+}
+
+static void
+conf_set_auth_redir_serv(void *data)
+{
+       yy_aconf->flags |= CONF_FLAGS_REDIR;
+       MyFree(yy_aconf->name);
+       DupString(yy_aconf->name, data);
+}
+
+static void
+conf_set_auth_redir_port(void *data)
+{
+       int port = *(unsigned int *) data;
+
+       yy_aconf->flags |= CONF_FLAGS_REDIR;
+       yy_aconf->port = port;
+}
+
+static void
+conf_set_auth_class(void *data)
+{
+       MyFree(yy_aconf->className);
+       DupString(yy_aconf->className, data);
+}
+
+/* ok, shared_oper handles the stacking, shared_flags handles adding
+ * things.. so all we need to do when we start and end a shared block, is
+ * clean up anything thats been left over.
+ */
+static int
+conf_cleanup_shared(struct TopConf *tc)
+{
+       dlink_node *ptr, *next_ptr;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, yy_shared_list.head)
+       {
+               free_remote_conf(ptr->data);
+               dlinkDestroy(ptr, &yy_shared_list);
+       }
+
+       if(yy_shared != NULL)
+       {
+               free_remote_conf(yy_shared);
+               yy_shared = NULL;
+       }
+
+       return 0;
+}
+
+static void
+conf_set_shared_oper(void *data)
+{
+       conf_parm_t *args = data;
+       const char *username;
+       char *p;
+
+       if(yy_shared != NULL)
+               free_remote_conf(yy_shared);
+
+       yy_shared = make_remote_conf();
+
+       if(args->next != NULL)
+       {
+               if((args->type & CF_MTYPE) != CF_QSTRING)
+               {
+                       conf_report_error("Ignoring shared::oper -- server is not a qstring");
+                       return;
+               }
+
+               DupString(yy_shared->server, args->v.string);
+               args = args->next;
+       }
+       else
+               DupString(yy_shared->server, "*");
+
+       if((args->type & CF_MTYPE) != CF_QSTRING)
+       {
+               conf_report_error("Ignoring shared::oper -- oper is not a qstring");
+               return;
+       }
+
+       if((p = strchr(args->v.string, '@')) == NULL)
+       {
+               conf_report_error("Ignoring shard::oper -- oper is not a user@host");
+               return;
+       }
+
+       username = args->v.string;
+       *p++ = '\0';
+
+       if(EmptyString(p))
+               DupString(yy_shared->host, "*");
+       else
+               DupString(yy_shared->host, p);
+
+       if(EmptyString(username))
+               DupString(yy_shared->username, "*");
+       else
+               DupString(yy_shared->username, username);
+
+       dlinkAddAlloc(yy_shared, &yy_shared_list);
+       yy_shared = NULL;
+}
+
+static void
+conf_set_shared_flags(void *data)
+{
+       conf_parm_t *args = data;
+       int flags = 0;
+       dlink_node *ptr, *next_ptr;
+
+       if(yy_shared != NULL)
+               free_remote_conf(yy_shared);
+
+       set_modes_from_table(&flags, "flag", shared_table, args);
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, yy_shared_list.head)
+       {
+               yy_shared = ptr->data;
+
+               yy_shared->flags = flags;
+               dlinkDestroy(ptr, &yy_shared_list);
+               dlinkAddTail(yy_shared, &yy_shared->node, &shared_conf_list);
+       }
+
+       yy_shared = NULL;
+}
+
+static int
+conf_begin_connect(struct TopConf *tc)
+{
+       if(yy_server)
+               free_server_conf(yy_server);
+
+       yy_server = make_server_conf();
+       yy_server->port = PORTNUM;
+
+       if(conf_cur_block_name != NULL)
+               DupString(yy_server->name, conf_cur_block_name);
+
+       return 0;
+}
+
+static int
+conf_end_connect(struct TopConf *tc)
+{
+       if(EmptyString(yy_server->name))
+       {
+               conf_report_error("Ignoring connect block -- missing name.");
+               return 0;
+       }
+
+       if(ServerInfo.name != NULL && !irccmp(ServerInfo.name, yy_server->name))
+       {
+               conf_report_error("Ignoring connect block for %s -- name is equal to my own name.",
+                               yy_server->name);
+               return 0;
+       }
+
+       if(EmptyString(yy_server->passwd) || EmptyString(yy_server->spasswd))
+       {
+               conf_report_error("Ignoring connect block for %s -- missing password.",
+                                       yy_server->name);
+               return 0;
+       }
+
+       if(EmptyString(yy_server->host))
+       {
+               conf_report_error("Ignoring connect block for %s -- missing host.",
+                                       yy_server->name);
+               return 0;
+       }
+
+#ifndef HAVE_LIBZ
+       if(ServerConfCompressed(yy_server))
+       {
+               conf_report_error("Ignoring connect::flags::compressed -- zlib not available.");
+               yy_server->flags &= ~SERVER_COMPRESSED;
+       }
+#endif
+
+       add_server_conf(yy_server);
+       dlinkAdd(yy_server, &yy_server->node, &server_conf_list);
+
+       yy_server = NULL;
+       return 0;
+}
+
+static void
+conf_set_connect_host(void *data)
+{
+       MyFree(yy_server->host);
+       DupString(yy_server->host, data);
+       if (strchr(yy_server->host, ':'))
+               yy_server->aftype = AF_INET6;
+}
+
+static void
+conf_set_connect_vhost(void *data)
+{
+       if(inetpton_sock(data, (struct sockaddr *)&yy_server->my_ipnum) <= 0)
+       {
+               conf_report_error("Invalid netmask for server vhost (%s)",
+                                 (char *) data);
+               return;
+       }
+
+       yy_server->flags |= SERVER_VHOSTED;
+}
+
+static void
+conf_set_connect_send_password(void *data)
+{
+       if(yy_server->spasswd)
+       {
+               memset(yy_server->spasswd, 0, strlen(yy_server->spasswd));
+               MyFree(yy_server->spasswd);
+       }
+
+       DupString(yy_server->spasswd, data);
+}
+
+static void
+conf_set_connect_accept_password(void *data)
+{
+       if(yy_server->passwd)
+       {
+               memset(yy_server->passwd, 0, strlen(yy_server->passwd));
+               MyFree(yy_server->passwd);
+       }
+       DupString(yy_server->passwd, data);
+}
+
+static void
+conf_set_connect_port(void *data)
+{
+       int port = *(unsigned int *) data;
+
+       if(port < 1)
+               port = PORTNUM;
+
+       yy_server->port = port;
+}
+
+static void
+conf_set_connect_aftype(void *data)
+{
+       char *aft = data;
+
+       if(strcasecmp(aft, "ipv4") == 0)
+               yy_server->aftype = AF_INET;
+#ifdef IPV6
+       else if(strcasecmp(aft, "ipv6") == 0)
+               yy_server->aftype = AF_INET6;
+#endif
+       else
+               conf_report_error("connect::aftype '%s' is unknown.", aft);
+}
+
+static void
+conf_set_connect_flags(void *data)
+{
+       conf_parm_t *args = data;
+
+       /* note, we allow them to set compressed, then remove it later if
+        * they do and LIBZ isnt available
+        */
+       set_modes_from_table(&yy_server->flags, "flag", connect_table, args);
+}
+
+static void
+conf_set_connect_hub_mask(void *data)
+{
+       struct remote_conf *yy_hub;
+
+       if(EmptyString(yy_server->name))
+               return;
+
+       yy_hub = make_remote_conf();
+       yy_hub->flags = CONF_HUB;
+
+       DupString(yy_hub->host, data);
+       DupString(yy_hub->server, yy_server->name);
+       dlinkAdd(yy_hub, &yy_hub->node, &hubleaf_conf_list);
+}
+
+static void
+conf_set_connect_leaf_mask(void *data)
+{
+       struct remote_conf *yy_leaf;
+
+       if(EmptyString(yy_server->name))
+               return;
+
+       yy_leaf = make_remote_conf();
+       yy_leaf->flags = CONF_LEAF;
+
+       DupString(yy_leaf->host, data);
+       DupString(yy_leaf->server, yy_server->name);
+       dlinkAdd(yy_leaf, &yy_leaf->node, &hubleaf_conf_list);
+}
+
+static void
+conf_set_connect_class(void *data)
+{
+       MyFree(yy_server->class_name);
+       DupString(yy_server->class_name, data);
+}
+
+static void
+conf_set_exempt_ip(void *data)
+{
+       struct ConfItem *yy_tmp;
+
+       if(parse_netmask(data, NULL, NULL) == HM_HOST)
+       {
+               conf_report_error("Ignoring exempt -- invalid exempt::ip.");
+               return;
+       }
+
+       yy_tmp = make_conf();
+       DupString(yy_tmp->passwd, "*");
+       DupString(yy_tmp->host, data);
+       yy_tmp->status = CONF_EXEMPTDLINE;
+       add_conf_by_address(yy_tmp->host, CONF_EXEMPTDLINE, NULL, yy_tmp);
+}
+
+static int
+conf_cleanup_cluster(struct TopConf *tc)
+{
+       dlink_node *ptr, *next_ptr;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, yy_cluster_list.head)
+       {
+               free_remote_conf(ptr->data);
+               dlinkDestroy(ptr, &yy_cluster_list);
+       }
+
+       if(yy_shared != NULL)
+       {
+               free_remote_conf(yy_shared);
+               yy_shared = NULL;
+       }
+
+       return 0;
+}
+
+static void
+conf_set_cluster_name(void *data)
+{
+       if(yy_shared != NULL)
+               free_remote_conf(yy_shared);
+
+       yy_shared = make_remote_conf();
+       DupString(yy_shared->server, data);
+       dlinkAddAlloc(yy_shared, &yy_cluster_list);
+
+       yy_shared = NULL;
+}
+
+static void
+conf_set_cluster_flags(void *data)
+{
+       conf_parm_t *args = data;
+       int flags = 0;
+       dlink_node *ptr, *next_ptr;
+
+       if(yy_shared != NULL)
+               free_remote_conf(yy_shared);
+
+       set_modes_from_table(&flags, "flag", cluster_table, args);
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, yy_cluster_list.head)
+       {
+               yy_shared = ptr->data;
+               yy_shared->flags = flags;
+               dlinkAddTail(yy_shared, &yy_shared->node, &cluster_conf_list);
+               dlinkDestroy(ptr, &yy_cluster_list);
+       }
+
+       yy_shared = NULL;
+}
+
+static void
+conf_set_general_havent_read_conf(void *data)
+{
+       if(*(unsigned int *) data)
+       {
+               conf_report_error("You haven't read your config file properly.");
+               conf_report_error
+                       ("There is a line in the example conf that will kill your server if not removed.");
+               conf_report_error
+                       ("Consider actually reading/editing the conf file, and removing this line.");
+               if (!testing_conf)
+                       exit(0);
+       }
+}
+
+static void
+conf_set_general_hide_error_messages(void *data)
+{
+       char *val = data;
+
+       if(strcasecmp(val, "yes") == 0)
+               ConfigFileEntry.hide_error_messages = 2;
+       else if(strcasecmp(val, "opers") == 0)
+               ConfigFileEntry.hide_error_messages = 1;
+       else if(strcasecmp(val, "no") == 0)
+               ConfigFileEntry.hide_error_messages = 0;
+       else
+               conf_report_error("Invalid setting '%s' for general::hide_error_messages.", val);
+}
+
+static void
+conf_set_general_kline_delay(void *data)
+{
+       ConfigFileEntry.kline_delay = *(unsigned int *) data;
+
+       /* THIS MUST BE HERE to stop us being unable to check klines */
+       kline_queued = 0;
+}
+
+static void
+conf_set_general_stats_k_oper_only(void *data)
+{
+       char *val = data;
+
+       if(strcasecmp(val, "yes") == 0)
+               ConfigFileEntry.stats_k_oper_only = 2;
+       else if(strcasecmp(val, "masked") == 0)
+               ConfigFileEntry.stats_k_oper_only = 1;
+       else if(strcasecmp(val, "no") == 0)
+               ConfigFileEntry.stats_k_oper_only = 0;
+       else
+               conf_report_error("Invalid setting '%s' for general::stats_k_oper_only.", val);
+}
+
+static void
+conf_set_general_stats_i_oper_only(void *data)
+{
+       char *val = data;
+
+       if(strcasecmp(val, "yes") == 0)
+               ConfigFileEntry.stats_i_oper_only = 2;
+       else if(strcasecmp(val, "masked") == 0)
+               ConfigFileEntry.stats_i_oper_only = 1;
+       else if(strcasecmp(val, "no") == 0)
+               ConfigFileEntry.stats_i_oper_only = 0;
+       else
+               conf_report_error("Invalid setting '%s' for general::stats_i_oper_only.", val);
+}
+
+static void
+conf_set_general_compression_level(void *data)
+{
+#ifdef HAVE_LIBZ
+       ConfigFileEntry.compression_level = *(unsigned int *) data;
+
+       if((ConfigFileEntry.compression_level < 1) || (ConfigFileEntry.compression_level > 9))
+       {
+               conf_report_error
+                       ("Invalid general::compression_level %d -- using default.",
+                        ConfigFileEntry.compression_level);
+               ConfigFileEntry.compression_level = 0;
+       }
+#else
+       conf_report_error("Ignoring general::compression_level -- zlib not available.");
+#endif
+}
+
+static void
+conf_set_general_default_umodes(void *data)
+{
+       char *pm;
+       int what = MODE_ADD, flag;
+
+       ConfigFileEntry.default_umodes = 0;
+       for (pm = (char *) data; *pm; pm++)
+       {
+               switch (*pm)
+               {
+               case '+':
+                       what = MODE_ADD;
+                       break;
+               case '-':
+                       what = MODE_DEL;
+                       break;
+
+               /* don't allow +o */
+               case 'o':
+               case 'S':
+               case ' ':
+                       break;
+
+               default:
+                       if ((flag = user_modes[(unsigned char) *pm]))
+                       {
+                               /* Proper value has probably not yet been set
+                                * so don't check oper_only_umodes -- jilles */
+                               if (what == MODE_ADD)
+                                       ConfigFileEntry.default_umodes |= flag;
+                               else
+                                       ConfigFileEntry.default_umodes &= ~flag;
+                       }
+                       break;
+               }
+       }                       
+}
+
+static void
+conf_set_general_oper_umodes(void *data)
+{
+       set_modes_from_table(&ConfigFileEntry.oper_umodes, "umode", umode_table, data);
+}
+
+static void
+conf_set_general_oper_only_umodes(void *data)
+{
+       set_modes_from_table(&ConfigFileEntry.oper_only_umodes, "umode", umode_table, data);
+}
+
+static void
+conf_set_general_oper_snomask(void *data)
+{
+       char *pm;
+       int what = MODE_ADD, flag;
+
+       ConfigFileEntry.oper_snomask = 0;
+       for (pm = (char *) data; *pm; pm++)
+       {
+               switch (*pm)
+               {
+               case '+':
+                       what = MODE_ADD;
+                       break;
+               case '-':
+                       what = MODE_DEL;
+                       break;
+
+               default:
+                       if ((flag = snomask_modes[(unsigned char) *pm]))
+                       {
+                               if (what == MODE_ADD)
+                                       ConfigFileEntry.oper_snomask |= flag;
+                               else
+                                       ConfigFileEntry.oper_snomask &= ~flag;
+                       }
+                       break;
+               }
+       }
+}
+
+static void
+conf_set_serverhide_links_delay(void *data)
+{
+       int val = *(unsigned int *) data;
+
+       if((val > 0) && ConfigServerHide.links_disabled == 1)
+       {
+               eventAddIsh("cache_links", cache_links, NULL, val);
+               ConfigServerHide.links_disabled = 0;
+       }
+       else if(val != ConfigServerHide.links_delay)
+               eventUpdate("cache_links", val);
+
+       ConfigServerHide.links_delay = val;
+}
+
+static int
+conf_begin_service(struct TopConf *tc)
+{
+       struct Client *target_p;
+       dlink_node *ptr;
+
+       DLINK_FOREACH(ptr, global_serv_list.head)
+       {
+               target_p = ptr->data;
+
+               target_p->flags &= ~FLAGS_SERVICE;
+       }
+
+       return 0;
+}
+
+static void
+conf_set_service_name(void *data)
+{
+       struct Client *target_p;
+       const char *s;
+       char *tmp;
+       int dots = 0;
+
+       for(s = data; *s != '\0'; s++)
+       {
+               if(!IsServChar(*s))
+               {
+                       conf_report_error("Ignoring service::name "
+                                        "-- bogus servername.");
+                       return;
+               }
+               else if(*s == '.')
+                        dots++;
+       }
+
+       if(!dots)
+       {
+               conf_report_error("Ignoring service::name -- must contain '.'");
+               return;
+       }
+
+       DupString(tmp, data);
+       dlinkAddAlloc(tmp, &service_list);
+
+       if((target_p = find_server(NULL, tmp)))
+               target_p->flags |= FLAGS_SERVICE;
+}
+
+static int
+alias_hash(const char *p)
+{
+       int hash_val = 0;
+
+       while (*p)
+       {
+               hash_val += ((int) (*p) & 0xDF);
+               p++;
+       }
+
+       return (hash_val % MAX_MSG_HASH);
+}
+
+static int
+conf_begin_alias(struct TopConf *tc)
+{
+       yy_alias = MyMalloc(sizeof(struct alias_entry));
+
+       if (conf_cur_block_name != NULL)
+               DupString(yy_alias->name, conf_cur_block_name);
+
+       yy_alias->flags = 0;
+       yy_alias->hits = 0;
+
+       return 0;
+}
+
+static int
+conf_end_alias(struct TopConf *tc)
+{
+       int hashval;
+
+       if (yy_alias == NULL)
+               return -1;
+
+       if (yy_alias->name == NULL)
+       {
+               conf_report_error("Ignoring alias -- must have a name.");
+
+               MyFree(yy_alias);
+
+               return -1;
+       }
+
+       if (yy_alias->target == NULL)
+       {
+               conf_report_error("Ignoring alias -- must have a target.");
+
+               MyFree(yy_alias);
+
+               return -1;
+       }
+
+       hashval = alias_hash(yy_alias->name);
+
+       dlinkAddAlloc(yy_alias, &alias_hash_table[hashval]);
+
+       return 0;
+}
+
+static void
+conf_set_alias_name(void *data)
+{
+       if (data == NULL || yy_alias == NULL)   /* this shouldn't ever happen */
+               return;
+
+       DupString(yy_alias->name, data);
+}
+
+static void
+conf_set_alias_target(void *data)
+{
+       if (data == NULL || yy_alias == NULL)   /* this shouldn't ever happen */
+               return;
+
+       DupString(yy_alias->target, data);
+}
+
+static void
+conf_set_blacklist_host(void *data)
+{
+       DupString(yy_blacklist_host, data);
+}
+
+static void
+conf_set_blacklist_reason(void *data)
+{
+       DupString(yy_blacklist_reason, data);
+
+       if (yy_blacklist_host && yy_blacklist_reason)
+       {
+               new_blacklist(yy_blacklist_host, yy_blacklist_reason);
+               MyFree(yy_blacklist_host);
+               MyFree(yy_blacklist_reason);
+               yy_blacklist_host = NULL;
+               yy_blacklist_reason = NULL;
+       }
+}
+
+/* public functions */
+
+
+void
+conf_report_error(const char *fmt, ...)
+{
+       va_list ap;
+       char msg[IRCD_BUFSIZE + 1] = { 0 };
+
+       va_start(ap, fmt);
+       ircvsnprintf(msg, IRCD_BUFSIZE, fmt, ap);
+       va_end(ap);
+
+       if (testing_conf)
+       {
+               fprintf(stderr, "\"%s\", line %d: %s\n", current_file, lineno + 1, msg);
+               return;
+       }
+
+       ierror("\"%s\", line %d: %s", current_file, lineno + 1, msg);
+       sendto_realops_snomask(SNO_GENERAL, L_ALL, "\"%s\", line %d: %s", current_file, lineno + 1, msg);
+}
+
+int
+conf_start_block(char *block, char *name)
+{
+       if((conf_cur_block = find_top_conf(block)) == NULL)
+       {
+               conf_report_error("Configuration block '%s' is not defined.", block);
+               return -1;
+       }
+
+       if(name)
+               DupString(conf_cur_block_name, name);
+       else
+               conf_cur_block_name = NULL;
+
+       if(conf_cur_block->tc_sfunc)
+               if(conf_cur_block->tc_sfunc(conf_cur_block) < 0)
+                       return -1;
+
+       return 0;
+}
+
+int
+conf_end_block(struct TopConf *tc)
+{
+       if(tc->tc_efunc)
+               return tc->tc_efunc(tc);
+
+       MyFree(conf_cur_block_name);
+       return 0;
+}
+
+static void
+conf_set_generic_int(void *data, void *location)
+{
+       *((int *) location) = *((unsigned int *) data);
+}
+
+static void
+conf_set_generic_string(void *data, int len, void *location)
+{
+       char **loc = location;
+       char *input = data;
+
+       if(len && strlen(input) > len)
+               input[len] = '\0';
+
+       MyFree(*loc);
+       DupString(*loc, input);
+}
+
+int
+conf_call_set(struct TopConf *tc, char *item, conf_parm_t * value, int type)
+{
+       struct ConfEntry *cf;
+       conf_parm_t *cp;
+
+       if(!tc)
+               return -1;
+
+       if((cf = find_conf_item(tc, item)) == NULL)
+       {
+               conf_report_error
+                       ("Non-existant configuration setting %s::%s.", tc->tc_name, (char *) item);
+               return -1;
+       }
+
+       /* if it takes one thing, make sure they only passed one thing,
+          and handle as needed. */
+       if(value->type & CF_FLIST && !cf->cf_type & CF_FLIST)
+       {
+               conf_report_error
+                       ("Option %s::%s does not take a list of values.", tc->tc_name, item);
+               return -1;
+       }
+
+       cp = value->v.list;
+
+
+       if(CF_TYPE(value->v.list->type) != CF_TYPE(cf->cf_type))
+       {
+               /* if it expects a string value, but we got a yesno, 
+                * convert it back
+                */
+               if((CF_TYPE(value->v.list->type) == CF_YESNO) &&
+                  (CF_TYPE(cf->cf_type) == CF_STRING))
+               {
+                       value->v.list->type = CF_STRING;
+
+                       if(cp->v.number == 1)
+                               DupString(cp->v.string, "yes");
+                       else
+                               DupString(cp->v.string, "no");
+               }
+
+               /* maybe it's a CF_TIME and they passed CF_INT --
+                  should still be valid */
+               else if(!((CF_TYPE(value->v.list->type) == CF_INT) &&
+                         (CF_TYPE(cf->cf_type) == CF_TIME)))
+               {
+                       conf_report_error
+                               ("Wrong type for %s::%s (expected %s, got %s)",
+                                tc->tc_name, (char *) item,
+                                conf_strtype(cf->cf_type), conf_strtype(value->v.list->type));
+                       return -1;
+               }
+       }
+
+       if(cf->cf_type & CF_FLIST)
+       {
+#if 0
+               if(cf->cf_arg)
+                       conf_set_generic_list(value->v.list, cf->cf_arg);
+               else
+#endif
+               /* just pass it the extended argument list */
+               cf->cf_func(value->v.list);
+       }
+       else
+       {
+               /* it's old-style, needs only one arg */
+               switch (cf->cf_type)
+               {
+               case CF_INT:
+               case CF_TIME:
+               case CF_YESNO:
+                       if(cf->cf_arg)
+                               conf_set_generic_int(&cp->v.number, cf->cf_arg);
+                       else
+                               cf->cf_func(&cp->v.number);
+                       break;
+               case CF_STRING:
+               case CF_QSTRING:
+                       if(EmptyString(cp->v.string))
+                               conf_report_error("Ignoring %s::%s -- empty field",
+                                               tc->tc_name, item);
+                       else if(cf->cf_arg)
+                               conf_set_generic_string(cp->v.string, cf->cf_len, cf->cf_arg);
+                       else
+                               cf->cf_func(cp->v.string);
+                       break;
+               }
+       }
+
+
+       return 0;
+}
+
+int
+add_conf_item(const char *topconf, const char *name, int type, void (*func) (void *))
+{
+       struct TopConf *tc;
+       struct ConfEntry *cf;
+
+       if((tc = find_top_conf(topconf)) == NULL)
+               return -1;
+
+       if((cf = find_conf_item(tc, name)) != NULL)
+               return -1;
+
+       cf = MyMalloc(sizeof(struct ConfEntry));
+
+       DupString(cf->cf_name, name);
+       cf->cf_type = type;
+       cf->cf_func = func;
+       cf->cf_arg = NULL;
+
+       dlinkAddAlloc(cf, &tc->tc_items);
+
+       return 0;
+}
+
+int
+remove_conf_item(const char *topconf, const char *name)
+{
+       struct TopConf *tc;
+       struct ConfEntry *cf;
+       dlink_node *ptr;
+
+       if((tc = find_top_conf(topconf)) == NULL)
+               return -1;
+
+       if((cf = find_conf_item(tc, name)) == NULL)
+               return -1;
+
+       if((ptr = dlinkFind(cf, &tc->tc_items)) == NULL)
+               return -1;
+
+       dlinkDestroy(ptr, &tc->tc_items);
+       MyFree(cf);
+
+       return 0;
+}
+
+/* *INDENT-OFF* */
+static struct ConfEntry conf_serverinfo_table[] =
+{
+       { "description",        CF_QSTRING, NULL, 0, &ServerInfo.description    },
+       { "network_desc",       CF_QSTRING, NULL, 0, &ServerInfo.network_desc   },
+       { "hub",                CF_YESNO,   NULL, 0, &ServerInfo.hub            },
+       { "use_ts6",            CF_YESNO,   NULL, 0, &ServerInfo.use_ts6        },
+
+       { "network_name",       CF_QSTRING, conf_set_serverinfo_network_name,   0, NULL },
+       { "name",               CF_QSTRING, conf_set_serverinfo_name,   0, NULL },
+       { "sid",                CF_QSTRING, conf_set_serverinfo_sid,    0, NULL },
+       { "vhost",              CF_QSTRING, conf_set_serverinfo_vhost,  0, NULL },
+       { "vhost6",             CF_QSTRING, conf_set_serverinfo_vhost6, 0, NULL },
+
+       { "\0", 0, NULL, 0, NULL }
+};
+
+static struct ConfEntry conf_admin_table[] =
+{
+       { "name",       CF_QSTRING, NULL, 200, &AdminInfo.name          },
+       { "description",CF_QSTRING, NULL, 200, &AdminInfo.description   },
+       { "email",      CF_QSTRING, NULL, 200, &AdminInfo.email         },
+       { "\0", 0, NULL, 0, NULL }
+};
+
+static struct ConfEntry conf_log_table[] =
+{
+       { "fname_userlog",      CF_QSTRING, NULL, MAXPATHLEN, &ConfigFileEntry.fname_userlog    },
+       { "fname_fuserlog",     CF_QSTRING, NULL, MAXPATHLEN, &ConfigFileEntry.fname_fuserlog   },
+       { "fname_operlog",      CF_QSTRING, NULL, MAXPATHLEN, &ConfigFileEntry.fname_operlog    },
+       { "fname_foperlog",     CF_QSTRING, NULL, MAXPATHLEN, &ConfigFileEntry.fname_foperlog   },
+       { "fname_serverlog",    CF_QSTRING, NULL, MAXPATHLEN, &ConfigFileEntry.fname_serverlog  },
+       { "fname_killlog",      CF_QSTRING, NULL, MAXPATHLEN, &ConfigFileEntry.fname_killlog    },
+       { "fname_glinelog",     CF_QSTRING, NULL, MAXPATHLEN, &ConfigFileEntry.fname_glinelog   },
+       { "fname_klinelog",     CF_QSTRING, NULL, MAXPATHLEN, &ConfigFileEntry.fname_klinelog   },
+       { "fname_operspylog",   CF_QSTRING, NULL, MAXPATHLEN, &ConfigFileEntry.fname_operspylog },
+       { "fname_ioerrorlog",   CF_QSTRING, NULL, MAXPATHLEN, &ConfigFileEntry.fname_ioerrorlog },
+       { "\0",                 0,          NULL, 0,          NULL }
+};
+
+static struct ConfEntry conf_operator_table[] =
+{
+       { "rsa_public_key_file",  CF_QSTRING, conf_set_oper_rsa_public_key_file, 0, NULL },
+       { "flags",      CF_STRING | CF_FLIST, conf_set_oper_flags,      0, NULL },
+       { "umodes",     CF_STRING | CF_FLIST, conf_set_oper_umodes,     0, NULL },
+       { "snomask",    CF_QSTRING, conf_set_oper_snomask,      0, NULL },
+       { "user",       CF_QSTRING, conf_set_oper_user,         0, NULL },
+       { "password",   CF_QSTRING, conf_set_oper_password,     0, NULL },
+       { "\0", 0, NULL, 0, NULL }
+};
+
+static struct ConfEntry conf_class_table[] =
+{
+       { "ping_time",          CF_TIME, conf_set_class_ping_time,              0, NULL },
+       { "cidr_bitlen",        CF_INT,  conf_set_class_cidr_bitlen,            0, NULL },
+       { "number_per_cidr",    CF_INT,  conf_set_class_number_per_cidr,        0, NULL },
+       { "number_per_ip",      CF_INT,  conf_set_class_number_per_ip,          0, NULL },
+       { "number_per_ip_global", CF_INT,conf_set_class_number_per_ip_global,   0, NULL },
+       { "number_per_ident",   CF_INT,  conf_set_class_number_per_ident,       0, NULL },
+       { "connectfreq",        CF_TIME, conf_set_class_connectfreq,            0, NULL },
+       { "max_number",         CF_INT,  conf_set_class_max_number,             0, NULL },
+       { "sendq",              CF_TIME, conf_set_class_sendq,                  0, NULL },
+       { "\0", 0, NULL, 0, NULL }
+};
+
+static struct ConfEntry conf_auth_table[] =
+{
+       { "user",       CF_QSTRING, conf_set_auth_user,         0, NULL },
+       { "password",   CF_QSTRING, conf_set_auth_passwd,       0, NULL },
+       { "class",      CF_QSTRING, conf_set_auth_class,        0, NULL },
+       { "spoof",      CF_QSTRING, conf_set_auth_spoof,        0, NULL },
+       { "redirserv",  CF_QSTRING, conf_set_auth_redir_serv,   0, NULL },
+       { "redirport",  CF_INT,     conf_set_auth_redir_port,   0, NULL },
+       { "flags",      CF_STRING | CF_FLIST, conf_set_auth_flags,      0, NULL },
+       { "\0", 0, NULL, 0, NULL }
+};
+
+static struct ConfEntry conf_connect_table[] =
+{
+       { "send_password",      CF_QSTRING,   conf_set_connect_send_password,   0, NULL },
+       { "accept_password",    CF_QSTRING,   conf_set_connect_accept_password, 0, NULL },
+       { "flags",      CF_STRING | CF_FLIST, conf_set_connect_flags,   0, NULL },
+       { "host",       CF_QSTRING, conf_set_connect_host,      0, NULL },
+       { "vhost",      CF_QSTRING, conf_set_connect_vhost,     0, NULL },
+       { "port",       CF_INT,     conf_set_connect_port,      0, NULL },
+       { "aftype",     CF_STRING,  conf_set_connect_aftype,    0, NULL },
+       { "hub_mask",   CF_QSTRING, conf_set_connect_hub_mask,  0, NULL },
+       { "leaf_mask",  CF_QSTRING, conf_set_connect_leaf_mask, 0, NULL },
+       { "class",      CF_QSTRING, conf_set_connect_class,     0, NULL },
+       { "\0", 0, NULL, 0, NULL }
+};
+
+static struct ConfEntry conf_general_table[] =
+{
+       { "oper_only_umodes",   CF_STRING | CF_FLIST, conf_set_general_oper_only_umodes, 0, NULL },
+       { "oper_umodes",        CF_STRING | CF_FLIST, conf_set_general_oper_umodes,      0, NULL },
+       { "oper_snomask",       CF_QSTRING, conf_set_general_oper_snomask, 0, NULL },
+       { "compression_level",  CF_INT,    conf_set_general_compression_level,  0, NULL },
+       { "havent_read_conf",   CF_YESNO,  conf_set_general_havent_read_conf,   0, NULL },
+       { "hide_error_messages",CF_STRING, conf_set_general_hide_error_messages,0, NULL },
+       { "kline_delay",        CF_TIME,   conf_set_general_kline_delay,        0, NULL },
+       { "stats_k_oper_only",  CF_STRING, conf_set_general_stats_k_oper_only,  0, NULL },
+       { "stats_i_oper_only",  CF_STRING, conf_set_general_stats_i_oper_only,  0, NULL },
+       { "default_umodes",     CF_QSTRING, conf_set_general_default_umodes, 0, NULL },
+
+       { "default_operstring", CF_QSTRING, NULL, REALLEN,    &ConfigFileEntry.default_operstring },
+       { "default_adminstring",CF_QSTRING, NULL, REALLEN,    &ConfigFileEntry.default_adminstring },
+       { "servicestring",      CF_QSTRING, NULL, REALLEN,    &ConfigFileEntry.servicestring },
+       { "egdpool_path",       CF_QSTRING, NULL, MAXPATHLEN, &ConfigFileEntry.egdpool_path },
+       { "kline_reason",       CF_QSTRING, NULL, REALLEN, &ConfigFileEntry.kline_reason },
+       { "identify_service",   CF_QSTRING, NULL, REALLEN, &ConfigFileEntry.identifyservice },
+       { "identify_command",   CF_QSTRING, NULL, REALLEN, &ConfigFileEntry.identifycommand },
+       { "servlink_path",      CF_QSTRING, NULL, MAXPATHLEN, &ConfigFileEntry.servlink_path },
+
+       { "anti_spam_exit_message_time", CF_TIME,  NULL, 0, &ConfigFileEntry.anti_spam_exit_message_time },
+       { "disable_fake_channels",       CF_YESNO, NULL, 0, &ConfigFileEntry.disable_fake_channels },
+       { "min_nonwildcard_simple",      CF_INT,   NULL, 0, &ConfigFileEntry.min_nonwildcard_simple },
+       { "non_redundant_klines",        CF_YESNO, NULL, 0, &ConfigFileEntry.non_redundant_klines },
+       { "tkline_expire_notices",       CF_YESNO, NULL, 0, &ConfigFileEntry.tkline_expire_notices },
+
+       { "anti_nick_flood",    CF_YESNO, NULL, 0, &ConfigFileEntry.anti_nick_flood     },
+       { "burst_away",         CF_YESNO, NULL, 0, &ConfigFileEntry.burst_away          },
+       { "caller_id_wait",     CF_TIME,  NULL, 0, &ConfigFileEntry.caller_id_wait      },
+       { "client_exit",        CF_YESNO, NULL, 0, &ConfigFileEntry.client_exit         },
+       { "client_flood",       CF_INT,   NULL, 0, &ConfigFileEntry.client_flood        },
+       { "collision_fnc",      CF_YESNO, NULL, 0, &ConfigFileEntry.collision_fnc       },
+       { "connect_timeout",    CF_TIME,  NULL, 0, &ConfigFileEntry.connect_timeout     },
+       { "default_floodcount", CF_INT,   NULL, 0, &ConfigFileEntry.default_floodcount  },
+       { "disable_auth",       CF_YESNO, NULL, 0, &ConfigFileEntry.disable_auth        },
+       { "dot_in_ip6_addr",    CF_YESNO, NULL, 0, &ConfigFileEntry.dot_in_ip6_addr     },
+       { "dots_in_ident",      CF_INT,   NULL, 0, &ConfigFileEntry.dots_in_ident       },
+       { "failed_oper_notice", CF_YESNO, NULL, 0, &ConfigFileEntry.failed_oper_notice  },
+       { "glines",             CF_YESNO, NULL, 0, &ConfigFileEntry.glines              },
+       { "gline_min_cidr",     CF_INT,   NULL, 0, &ConfigFileEntry.gline_min_cidr      },
+       { "gline_min_cidr6",    CF_INT,   NULL, 0, &ConfigFileEntry.gline_min_cidr6     },
+       { "gline_time",         CF_TIME,  NULL, 0, &ConfigFileEntry.gline_time          },
+       { "global_snotices",    CF_YESNO, NULL, 0, &ConfigFileEntry.global_snotices     },
+       { "idletime",           CF_TIME,  NULL, 0, &ConfigFileEntry.idletime            },
+       { "hide_spoof_ips",     CF_YESNO, NULL, 0, &ConfigFileEntry.hide_spoof_ips      },
+       { "dline_with_reason",  CF_YESNO, NULL, 0, &ConfigFileEntry.dline_with_reason   },
+       { "kline_with_reason",  CF_YESNO, NULL, 0, &ConfigFileEntry.kline_with_reason   },
+       { "map_oper_only",      CF_YESNO, NULL, 0, &ConfigFileEntry.map_oper_only       },
+       { "max_accept",         CF_INT,   NULL, 0, &ConfigFileEntry.max_accept          },
+       { "max_monitor",        CF_INT,   NULL, 0, &ConfigFileEntry.max_monitor         },
+       { "max_nick_time",      CF_TIME,  NULL, 0, &ConfigFileEntry.max_nick_time       },
+       { "max_nick_changes",   CF_INT,   NULL, 0, &ConfigFileEntry.max_nick_changes    },
+       { "max_targets",        CF_INT,   NULL, 0, &ConfigFileEntry.max_targets         },
+       { "min_nonwildcard",    CF_INT,   NULL, 0, &ConfigFileEntry.min_nonwildcard     },
+       { "nick_delay",         CF_TIME,  NULL, 0, &ConfigFileEntry.nick_delay          },
+       { "no_oper_flood",      CF_YESNO, NULL, 0, &ConfigFileEntry.no_oper_flood       },
+       { "operspy_admin_only", CF_YESNO, NULL, 0, &ConfigFileEntry.operspy_admin_only  },
+       { "operspy_dont_care_user_info", CF_YESNO, NULL, 0, &ConfigFileEntry.operspy_dont_care_user_info },
+       { "pace_wait",          CF_TIME,  NULL, 0, &ConfigFileEntry.pace_wait           },
+       { "pace_wait_simple",   CF_TIME,  NULL, 0, &ConfigFileEntry.pace_wait_simple    },
+       { "ping_cookie",        CF_YESNO, NULL, 0, &ConfigFileEntry.ping_cookie         },
+       { "reject_after_count", CF_INT,   NULL, 0, &ConfigFileEntry.reject_after_count  },
+       { "reject_ban_time",    CF_TIME,  NULL, 0, &ConfigFileEntry.reject_ban_time     },
+       { "reject_duration",    CF_TIME,  NULL, 0, &ConfigFileEntry.reject_duration     },
+       { "short_motd",         CF_YESNO, NULL, 0, &ConfigFileEntry.short_motd          },
+       { "stats_c_oper_only",  CF_YESNO, NULL, 0, &ConfigFileEntry.stats_c_oper_only   },
+       { "stats_e_disabled",   CF_YESNO, NULL, 0, &ConfigFileEntry.stats_e_disabled    },
+       { "stats_h_oper_only",  CF_YESNO, NULL, 0, &ConfigFileEntry.stats_h_oper_only   },
+       { "stats_o_oper_only",  CF_YESNO, NULL, 0, &ConfigFileEntry.stats_o_oper_only   },
+       { "stats_P_oper_only",  CF_YESNO, NULL, 0, &ConfigFileEntry.stats_P_oper_only   },
+       { "stats_y_oper_only",  CF_YESNO, NULL, 0, &ConfigFileEntry.stats_y_oper_only   },
+       { "target_change",      CF_YESNO, NULL, 0, &ConfigFileEntry.target_change       },
+       { "ts_max_delta",       CF_TIME,  NULL, 0, &ConfigFileEntry.ts_max_delta        },
+       { "use_egd",            CF_YESNO, NULL, 0, &ConfigFileEntry.use_egd             },
+       { "ts_warn_delta",      CF_TIME,  NULL, 0, &ConfigFileEntry.ts_warn_delta       },
+       { "use_whois_actually", CF_YESNO, NULL, 0, &ConfigFileEntry.use_whois_actually  },
+       { "warn_no_nline",      CF_YESNO, NULL, 0, &ConfigFileEntry.warn_no_nline       },
+       { "\0",                 0,        NULL, 0, NULL }
+};
+
+static struct ConfEntry conf_channel_table[] =
+{
+       { "default_split_user_count",   CF_INT,  NULL, 0, &ConfigChannel.default_split_user_count        },
+       { "default_split_server_count", CF_INT,  NULL, 0, &ConfigChannel.default_split_server_count },
+       { "burst_topicwho",     CF_YESNO, NULL, 0, &ConfigChannel.burst_topicwho        },
+       { "invite_ops_only",    CF_YESNO, NULL, 0, &ConfigChannel.invite_ops_only       },
+       { "kick_on_split_riding", CF_YESNO, NULL, 0, &ConfigChannel.kick_on_split_riding },
+       { "knock_delay",        CF_TIME,  NULL, 0, &ConfigChannel.knock_delay           },
+       { "knock_delay_channel",CF_TIME,  NULL, 0, &ConfigChannel.knock_delay_channel   },
+       { "max_bans",           CF_INT,   NULL, 0, &ConfigChannel.max_bans              },
+       { "max_bans_large",     CF_INT,   NULL, 0, &ConfigChannel.max_bans_large        },
+       { "max_chans_per_user", CF_INT,   NULL, 0, &ConfigChannel.max_chans_per_user    },
+       { "no_create_on_split", CF_YESNO, NULL, 0, &ConfigChannel.no_create_on_split    },
+       { "no_join_on_split",   CF_YESNO, NULL, 0, &ConfigChannel.no_join_on_split      },
+       { "use_except",         CF_YESNO, NULL, 0, &ConfigChannel.use_except            },
+       { "use_invex",          CF_YESNO, NULL, 0, &ConfigChannel.use_invex             },
+       { "use_knock",          CF_YESNO, NULL, 0, &ConfigChannel.use_knock             },
+       { "use_forward",        CF_YESNO, NULL, 0, &ConfigChannel.use_forward           },
+       { "\0",                 0,        NULL, 0, NULL }
+};
+
+static struct ConfEntry conf_serverhide_table[] =
+{
+       { "disable_hidden",     CF_YESNO, NULL, 0, &ConfigServerHide.disable_hidden     },
+       { "flatten_links",      CF_YESNO, NULL, 0, &ConfigServerHide.flatten_links      },
+       { "hidden",             CF_YESNO, NULL, 0, &ConfigServerHide.hidden             },
+       { "links_delay",        CF_TIME,  conf_set_serverhide_links_delay, 0, NULL      },
+       { "\0",                 0,        NULL, 0, NULL }
+};
+/* *INDENT-ON* */
+
+void
+newconf_init()
+{
+       add_top_conf("modules", NULL, NULL, NULL);
+       add_conf_item("modules", "path", CF_QSTRING, conf_set_modules_path);
+       add_conf_item("modules", "module", CF_QSTRING, conf_set_modules_module);
+
+       add_top_conf("serverinfo", NULL, NULL, conf_serverinfo_table);
+       add_top_conf("admin", NULL, NULL, conf_admin_table);
+       add_top_conf("log", NULL, NULL, conf_log_table);
+       add_top_conf("operator", conf_begin_oper, conf_end_oper, conf_operator_table);
+       add_top_conf("class", conf_begin_class, conf_end_class, conf_class_table);
+
+       add_top_conf("listen", conf_begin_listen, conf_end_listen, NULL);
+       add_conf_item("listen", "port", CF_INT | CF_FLIST, conf_set_listen_port);
+       add_conf_item("listen", "ip", CF_QSTRING, conf_set_listen_address);
+       add_conf_item("listen", "host", CF_QSTRING, conf_set_listen_address);
+
+       add_top_conf("auth", conf_begin_auth, conf_end_auth, conf_auth_table);
+
+       add_top_conf("shared", conf_cleanup_shared, conf_cleanup_shared, NULL);
+       add_conf_item("shared", "oper", CF_QSTRING|CF_FLIST, conf_set_shared_oper);
+       add_conf_item("shared", "flags", CF_STRING | CF_FLIST, conf_set_shared_flags);
+
+       add_top_conf("connect", conf_begin_connect, conf_end_connect, conf_connect_table);
+
+       add_top_conf("exempt", NULL, NULL, NULL);
+       add_conf_item("exempt", "ip", CF_QSTRING, conf_set_exempt_ip);
+
+       add_top_conf("cluster", conf_cleanup_cluster, conf_cleanup_cluster, NULL);
+       add_conf_item("cluster", "name", CF_QSTRING, conf_set_cluster_name);
+       add_conf_item("cluster", "flags", CF_STRING | CF_FLIST, conf_set_cluster_flags);
+
+       add_top_conf("general", NULL, NULL, conf_general_table);
+       add_top_conf("channel", NULL, NULL, conf_channel_table);
+       add_top_conf("serverhide", NULL, NULL, conf_serverhide_table);
+
+       add_top_conf("service", conf_begin_service, NULL, NULL);
+       add_conf_item("service", "name", CF_QSTRING, conf_set_service_name);
+
+       add_top_conf("alias", conf_begin_alias, conf_end_alias, NULL);
+       add_conf_item("alias", "name", CF_QSTRING, conf_set_alias_name);
+       add_conf_item("alias", "target", CF_QSTRING, conf_set_alias_target);
+
+       add_top_conf("blacklist", NULL, NULL, NULL);
+       add_conf_item("blacklist", "host", CF_QSTRING, conf_set_blacklist_host);
+       add_conf_item("blacklist", "reject_reason", CF_QSTRING, conf_set_blacklist_reason);
+}
diff --git a/src/numeric.c b/src/numeric.c
new file mode 100644 (file)
index 0000000..1a8c96c
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  numeric.c: Numeric handling functions.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: numeric.c 6 2005-09-10 01:02:21Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "setup.h"
+#include "config.h"
+#include "s_conf.h"
+#include "numeric.h"
+#include "irc_string.h"
+#include "common.h"            /* NULL cripes */
+#include "memory.h"
+
+#include "messages.tab"
+
+/*
+ * form_str
+ *
+ * inputs      - numeric
+ * output      - corresponding string
+ * side effects        - NONE
+ */
+const char *
+form_str(int numeric)
+{
+       const char *num_ptr;
+
+       s_assert(-1 < numeric);
+       s_assert(numeric < ERR_LAST_ERR_MSG);
+       s_assert(0 != replies[numeric]);
+
+       if(numeric > ERR_LAST_ERR_MSG)
+               numeric = ERR_LAST_ERR_MSG;
+       if(numeric < 0)
+               numeric = ERR_LAST_ERR_MSG;
+
+       num_ptr = replies[numeric];
+       if(num_ptr == NULL)
+               num_ptr = replies[ERR_LAST_ERR_MSG];
+
+       return (num_ptr);
+}
diff --git a/src/packet.c b/src/packet.c
new file mode 100644 (file)
index 0000000..7c8c87f
--- /dev/null
@@ -0,0 +1,474 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  packet.c: Packet handlers.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: packet.c 262 2005-09-22 00:38:45Z jilles $
+ */
+#include "stdinc.h"
+#include "tools.h"
+#include "commio.h"
+#include "s_conf.h"
+#include "s_serv.h"
+#include "client.h"
+#include "common.h"
+#include "ircd.h"
+#include "parse.h"
+#include "packet.h"
+#include "irc_string.h"
+#include "memory.h"
+#include "hook.h"
+#include "send.h"
+
+static char readBuf[READBUF_SIZE];
+static void client_dopacket(struct Client *client_p, char *buffer, size_t length);
+
+
+/*
+ * parse_client_queued - parse client queued messages
+ */
+static void
+parse_client_queued(struct Client *client_p)
+{
+       int dolen = 0;
+       int checkflood = 1;
+
+       if(IsAnyDead(client_p))
+               return;
+
+       if(IsUnknown(client_p))
+       {
+               int i = 0;
+
+               for (;;)
+               {
+                       /* rate unknown clients at MAX_FLOOD per loop */
+                       if(i >= MAX_FLOOD)
+                               break;
+
+                       dolen = linebuf_get(&client_p->localClient->
+                                           buf_recvq, readBuf, READBUF_SIZE,
+                                           LINEBUF_COMPLETE, LINEBUF_PARSED);
+
+                       if(dolen <= 0 || IsDead(client_p))
+                               break;
+
+                       client_dopacket(client_p, readBuf, dolen);
+                       i++;
+
+                       /* He's dead cap'n */
+                       if(IsAnyDead(client_p))
+                               return;
+                       /* if theyve dropped out of the unknown state, break and move
+                        * to the parsing for their appropriate status.  --fl
+                        */
+                       if(!IsUnknown(client_p))
+                               break;
+
+               }
+       }
+
+       if(IsAnyServer(client_p) || IsExemptFlood(client_p))
+       {
+               while (!IsAnyDead(client_p) && (dolen = linebuf_get(&client_p->localClient->buf_recvq,
+                                          readBuf, READBUF_SIZE, LINEBUF_COMPLETE,
+                                          LINEBUF_PARSED)) > 0)
+               {
+                       client_dopacket(client_p, readBuf, dolen);
+               }
+       }
+       else if(IsClient(client_p))
+       {
+
+               if(IsOper(client_p) && ConfigFileEntry.no_oper_flood)
+                       checkflood = 0;
+               /*
+                * Handle flood protection here - if we exceed our flood limit on
+                * messages in this loop, we simply drop out of the loop prematurely.
+                *   -- adrian
+                */
+               for (;;)
+               {
+                       /* This flood protection works as follows:
+                        *
+                        * A client is given allow_read lines to send to the server.  Every
+                        * time a line is parsed, sent_parsed is increased.  sent_parsed
+                        * is decreased by 1 every time flood_recalc is called.
+                        *
+                        * Thus a client can 'burst' allow_read lines to the server, any
+                        * excess lines will be parsed one per flood_recalc() call.
+                        *
+                        * Therefore a client will be penalised more if they keep flooding,
+                        * as sent_parsed will always hover around the allow_read limit
+                        * and no 'bursts' will be permitted.
+                        */
+                       if(checkflood)
+                       {
+                               if(client_p->localClient->sent_parsed >= client_p->localClient->allow_read)
+                                       break;
+                       }
+
+                       /* allow opers 4 times the amount of messages as users. why 4?
+                        * why not. :) --fl_
+                        */
+                       else if(client_p->localClient->sent_parsed >= (4 * client_p->localClient->allow_read))
+                               break;
+
+                       dolen = linebuf_get(&client_p->localClient->
+                                           buf_recvq, readBuf, READBUF_SIZE,
+                                           LINEBUF_COMPLETE, LINEBUF_PARSED);
+
+                       if(!dolen)
+                               break;
+
+                       client_dopacket(client_p, readBuf, dolen);
+                       if(IsAnyDead(client_p))
+                               return;
+                       client_p->localClient->sent_parsed++;
+               }
+       }
+}
+
+/* flood_endgrace()
+ *
+ * marks the end of the clients grace period
+ */
+void
+flood_endgrace(struct Client *client_p)
+{
+       SetFloodDone(client_p);
+
+       /* Drop their flood limit back down */
+       client_p->localClient->allow_read = MAX_FLOOD;
+
+       /* sent_parsed could be way over MAX_FLOOD but under MAX_FLOOD_BURST,
+        * so reset it.
+        */
+       client_p->localClient->sent_parsed = 0;
+}
+
+/*
+ * flood_recalc
+ *
+ * recalculate the number of allowed flood lines. this should be called
+ * once a second on any given client. We then attempt to flush some data.
+ */
+void
+flood_recalc(int fd, void *data)
+{
+       struct Client *client_p = data;
+       struct LocalUser *lclient_p = client_p->localClient;
+
+       /* This can happen in the event that the client detached. */
+       if(!lclient_p)
+               return;
+
+       /* allow a bursting client their allocation per second, allow
+        * a client whos flooding an extra 2 per second
+        */
+       if(IsFloodDone(client_p))
+               lclient_p->sent_parsed -= 2;
+       else
+               lclient_p->sent_parsed = 0;
+
+       if(lclient_p->sent_parsed < 0)
+               lclient_p->sent_parsed = 0;
+
+       if(--lclient_p->actually_read < 0)
+               lclient_p->actually_read = 0;
+
+       parse_client_queued(client_p);
+
+       if(IsAnyDead(client_p))
+               return;
+
+       /* and finally, reset the flood check */
+       comm_setflush(fd, 1000, flood_recalc, client_p);
+}
+
+/*
+ * read_ctrl_packet - Read a 'packet' of data from a servlink control
+ *                    link and process it.
+ */
+void
+read_ctrl_packet(int fd, void *data)
+{
+       struct Client *server = data;
+       struct LocalUser *lserver = server->localClient;
+       struct SlinkRpl *reply;
+       int length = 0;
+       unsigned char tmp[2];
+       unsigned char *len = tmp;
+       struct SlinkRplDef *replydef;
+#ifdef USE_IODEBUG_HOOKS
+       hook_data_int hdata;
+#endif
+
+       s_assert(lserver != NULL);
+       if(IsAnyDead(server))
+               return;
+
+       reply = &lserver->slinkrpl;
+
+
+       if(!reply->command)
+       {
+               reply->gotdatalen = 0;
+               reply->readdata = 0;
+               reply->data = NULL;
+
+               length = read(fd, tmp, 1);
+
+               if(length <= 0)
+               {
+                       if((length == -1) && ignoreErrno(errno))
+                               goto nodata;
+                       error_exit_client(server, length);
+                       return;
+               }
+
+               reply->command = tmp[0];
+       }
+
+       for (replydef = slinkrpltab; replydef->handler; replydef++)
+       {
+               if((int)replydef->replyid == reply->command)
+                       break;
+       }
+
+       /* we should be able to trust a local slink process...
+        * and if it sends an invalid command, that's a bug.. */
+       s_assert(replydef->handler);
+
+       if((replydef->flags & SLINKRPL_FLAG_DATA) && (reply->gotdatalen < 2))
+       {
+               /* we need a datalen u16 which we don't have yet... */
+               length = read(fd, len, (2 - reply->gotdatalen));
+               if(length <= 0)
+               {
+                       if((length == -1) && ignoreErrno(errno))
+                               goto nodata;
+                       error_exit_client(server, length);
+                       return;
+               }
+
+               if(reply->gotdatalen == 0)
+               {
+                       reply->datalen = *len << 8;
+                       reply->gotdatalen++;
+                       length--;
+                       len++;
+               }
+               if(length && (reply->gotdatalen == 1))
+               {
+                       reply->datalen |= *len;
+                       reply->gotdatalen++;
+                       if(reply->datalen > 0)
+                               reply->data = MyMalloc(reply->datalen);
+               }
+
+               if(reply->gotdatalen < 2)
+                       return; /* wait for more data */
+       }
+
+       if(reply->readdata < reply->datalen)    /* try to get any remaining data */
+       {
+               length = read(fd, (reply->data + reply->readdata),
+                             (reply->datalen - reply->readdata));
+               if(length <= 0)
+               {
+                       if((length == -1) && ignoreErrno(errno))
+                               goto nodata;
+                       error_exit_client(server, length);
+                       return;
+               }
+
+               reply->readdata += length;
+               if(reply->readdata < reply->datalen)
+                       return; /* wait for more data */
+       }
+
+#ifdef USE_IODEBUG_HOOKS
+       hdata.client = server;
+       hdata.arg1 = NULL;
+       hdata.arg2 = reply->command;
+       hdata.data = NULL;
+       call_hook(h_iorecvctrl_id, &hdata);
+#endif
+
+       /* we now have the command and any data, pass it off to the handler */
+       (*replydef->handler) (reply->command, reply->datalen, reply->data, server);
+
+       /* reset SlinkRpl */
+       if(reply->datalen > 0)
+               MyFree(reply->data);
+       reply->command = 0;
+
+       if(IsAnyDead(server))
+               return;
+
+      nodata:
+       /* If we get here, we need to register for another COMM_SELECT_READ */
+       comm_setselect(fd, FDLIST_SERVER, COMM_SELECT_READ, read_ctrl_packet, server, 0);
+}
+
+/*
+ * read_packet - Read a 'packet' of data from a connection and process it.
+ */
+void
+read_packet(int fd, void *data)
+{
+       struct Client *client_p = data;
+       struct LocalUser *lclient_p = client_p->localClient;
+       int length = 0;
+       int lbuf_len;
+
+       int binary = 0;
+#ifdef USE_IODEBUG_HOOKS
+       hook_data_int hdata;
+#endif
+       if(IsAnyDead(client_p))
+               return;
+
+       /*
+        * Read some data. We *used to* do anti-flood protection here, but
+        * I personally think it makes the code too hairy to make sane.
+        *     -- adrian
+        */
+       length = read(client_p->localClient->fd, readBuf, READBUF_SIZE);
+
+       if(length <= 0)
+       {
+               if((length == -1) && ignoreErrno(errno))
+               {
+                       comm_setselect(client_p->localClient->fd, FDLIST_IDLECLIENT,
+                                      COMM_SELECT_READ, read_packet, client_p, 0);
+                       return;
+               }
+               error_exit_client(client_p, length);
+               return;
+       }
+
+#ifdef USE_IODEBUG_HOOKS
+       hdata.client = client_p;
+       hdata.arg1 = readBuf;
+       hdata.arg2 = length;
+       call_hook(h_iorecv_id, &hdata);
+#endif
+
+       if(client_p->localClient->lasttime < CurrentTime)
+               client_p->localClient->lasttime = CurrentTime;
+       client_p->flags &= ~FLAGS_PINGSENT;
+
+       /*
+        * 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(IsHandshake(client_p) || IsUnknown(client_p))
+               binary = 1;
+
+       lbuf_len = linebuf_parse(&client_p->localClient->buf_recvq, readBuf, length, binary);
+
+       lclient_p->actually_read += lbuf_len;
+
+       if(IsAnyDead(client_p))
+               return;
+               
+       /* Attempt to parse what we have */
+       parse_client_queued(client_p);
+
+       if(IsAnyDead(client_p))
+               return;
+               
+       /* Check to make sure we're not flooding */
+       if(!IsAnyServer(client_p) &&
+          (linebuf_alloclen(&client_p->localClient->buf_recvq) > ConfigFileEntry.client_flood))
+       {
+               if(!(ConfigFileEntry.no_oper_flood && IsOper(client_p)))
+               {
+                       exit_client(client_p, client_p, client_p, "Excess Flood");
+                       return;
+               }
+       }
+
+       /* If we get here, we need to register for another COMM_SELECT_READ */
+       if(PARSE_AS_SERVER(client_p))
+       {
+               comm_setselect(client_p->localClient->fd, FDLIST_SERVER, COMM_SELECT_READ,
+                             read_packet, client_p, 0);
+       }
+       else
+       {
+               comm_setselect(client_p->localClient->fd, FDLIST_IDLECLIENT,
+                              COMM_SELECT_READ, read_packet, client_p, 0);
+       }
+}
+
+/*
+ * client_dopacket - copy packet to client buf and parse it
+ *      client_p - pointer to client structure for which the buffer data
+ *             applies.
+ *      buffer - pointr to the buffer containing the newly read data
+ *      length - number of valid bytes of data in the buffer
+ *
+ * Note:
+ *      It is implicitly assumed that dopacket is called only
+ *      with client_p of "local" variation, which contains all the
+ *      necessary fields (buffer etc..)
+ */
+void
+client_dopacket(struct Client *client_p, char *buffer, size_t length)
+{
+       s_assert(client_p != NULL);
+       s_assert(buffer != NULL);
+
+       if(client_p == NULL || buffer == NULL)
+               return;
+       if(IsAnyDead(client_p))
+               return;
+       /* 
+        * Update messages received
+        */
+       ++me.localClient->receiveM;
+       ++client_p->localClient->receiveM;
+
+       /* 
+        * Update bytes received
+        */
+       client_p->localClient->receiveB += length;
+
+       if(client_p->localClient->receiveB > 1023)
+       {
+               client_p->localClient->receiveK += (client_p->localClient->receiveB >> 10);
+               client_p->localClient->receiveB &= 0x03ff;      /* 2^10 = 1024, 3ff = 1023 */
+       }
+
+       me.localClient->receiveB += length;
+
+       if(me.localClient->receiveB > 1023)
+       {
+               me.localClient->receiveK += (me.localClient->receiveB >> 10);
+               me.localClient->receiveB &= 0x03ff;
+       }
+
+       parse(client_p, buffer, buffer + length);
+}
diff --git a/src/parse.c b/src/parse.c
new file mode 100644 (file)
index 0000000..7889f56
--- /dev/null
@@ -0,0 +1,870 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  parse.c: The message parser.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: parse.c 2723 2006-11-09 23:35:48Z jilles $
+ */
+
+#include "stdinc.h"
+#include "parse.h"
+#include "client.h"
+#include "channel.h"
+#include "common.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_log.h"
+#include "s_stats.h"
+#include "send.h"
+#include "msg.h"
+#include "s_conf.h"
+#include "memory.h"
+#include "s_serv.h"
+#include "packet.h"
+
+/*
+ * NOTE: parse() should not be called recursively by other functions!
+ */
+static char *sender;
+
+/* parv[0] == source, and parv[LAST] == NULL */
+static char *para[MAXPARA + 2];
+
+static void cancel_clients(struct Client *, struct Client *, char *);
+static void remove_unknown(struct Client *, char *, char *);
+
+static void do_numeric(char[], struct Client *, struct Client *, int, char **);
+static void do_alias(struct alias_entry *, struct Client *, char *);
+
+static int handle_command(struct Message *, struct Client *, struct Client *, int, const char**);
+
+static int cmd_hash(const char *p);
+static struct Message *hash_parse(const char *);
+static struct alias_entry *alias_parse(const char *);
+
+struct MessageHash *msg_hash_table[MAX_MSG_HASH];
+
+static char buffer[1024];
+
+dlink_list alias_hash_table[MAX_MSG_HASH];
+
+/* turn a string into a parc/parv pair */
+
+
+static inline int
+string_to_array(char *string, char **parv)
+{
+       char *p, *buf = string;
+       int x = 1;
+
+       parv[x] = NULL;
+       while (*buf == ' ')     /* skip leading spaces */
+               buf++;
+       if(*buf == '\0')        /* ignore all-space args */
+               return x;
+
+       do
+       {
+               if(*buf == ':') /* Last parameter */
+               {
+                       buf++;
+                       parv[x++] = buf;
+                       parv[x] = NULL;
+                       return x;
+               }
+               else
+               {
+                       parv[x++] = buf;
+                       parv[x] = NULL;
+                       if((p = strchr(buf, ' ')) != NULL)
+                       {
+                               *p++ = '\0';
+                               buf = p;
+                       }
+                       else
+                               return x;
+               }
+               while (*buf == ' ')
+                       buf++;
+               if(*buf == '\0')
+                       return x;
+       }
+       /* we can go upto parv[MAXPARA], as parv[0] is taken by source */
+       while (x < MAXPARA);
+
+       if(*p == ':')
+               p++;
+
+       parv[x++] = p;
+       parv[x] = NULL;
+       return x;
+}
+
+/* parse()
+ *
+ * given a raw buffer, parses it and generates parv, parc and sender
+ */
+void
+parse(struct Client *client_p, char *pbuffer, char *bufend)
+{
+       struct Client *from = client_p;
+       char *ch;
+       char *s;
+       char *end;
+       int i = 1;
+       char *numeric = 0;
+       struct Message *mptr;
+
+       s_assert(MyConnect(client_p));
+       s_assert(client_p->localClient->fd >= 0);
+       if(IsAnyDead(client_p))
+               return;
+
+       for (ch = pbuffer; *ch == ' '; ch++)    /* skip spaces */
+               /* null statement */ ;
+
+       para[0] = from->name;
+
+       if(*ch == ':')
+       {
+               ch++;
+
+               /* point sender to the sender param */
+               sender = ch;
+
+               if((s = strchr(ch, ' ')))
+               {
+                       *s = '\0';
+                       s++;
+                       ch = s;
+               }
+
+               if(*sender && IsServer(client_p))
+               {
+                       from = find_any_client(sender);
+
+                       /* didnt find any matching client, issue a kill */
+                       if(from == NULL)
+                       {
+                               ServerStats->is_unpf++;
+                               remove_unknown(client_p, sender, pbuffer);
+                               return;
+                       }
+
+                       para[0] = from->name;
+
+                       /* fake direction, hmm. */
+                       if(from->from != client_p)
+                       {
+                               ServerStats->is_wrdi++;
+                               cancel_clients(client_p, from, pbuffer);
+                               return;
+                       }
+               }
+               while (*ch == ' ')
+                       ch++;
+       }
+
+       if(*ch == '\0')
+       {
+               ServerStats->is_empt++;
+               return;
+       }
+
+       /* at this point there must be some sort of command parameter */
+
+       /*
+        * 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
+        */
+
+       /* EOB is 3 chars long but is not a numeric */
+
+       if(*(ch + 3) == ' ' &&  /* ok, lets see if its a possible numeric.. */
+          IsDigit(*ch) && IsDigit(*(ch + 1)) && IsDigit(*(ch + 2)))
+       {
+               mptr = NULL;
+               numeric = ch;
+               ServerStats->is_num++;
+               s = ch + 3;     /* I know this is ' ' from above if */
+               *s++ = '\0';    /* blow away the ' ', and point s to next part */
+       }
+       else
+       {
+               int ii = 0;
+
+               if((s = strchr(ch, ' ')))
+                       *s++ = '\0';
+
+               mptr = hash_parse(ch);
+
+               /* no command or its encap only, error */
+               if(!mptr || !mptr->cmd)
+               {
+                       /*
+                        * 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(pbuffer[0] != '\0')
+                       {
+                               if (IsPerson(client_p))
+                               {
+                                       struct alias_entry *aptr = alias_parse(ch);
+                                       if (aptr != NULL)
+                                       {
+                                               do_alias(aptr, client_p, s);
+                                               return;
+                                       }
+                               }
+                               if(IsPerson(from))
+                               {
+                                       sendto_one(from, form_str(ERR_UNKNOWNCOMMAND),
+                                                  me.name, from->name, ch);
+                               }
+                       }
+                       ServerStats->is_unco++;
+                       return;
+               }
+
+               ii = bufend - ((s) ? s : ch);
+               mptr->bytes += ii;
+       }
+
+       end = bufend - 1;
+
+       /* XXX this should be done before parse() is called */
+       if(*end == '\n')
+               *end-- = '\0';
+       if(*end == '\r')
+               *end = '\0';
+
+       if(s != NULL)
+               i = string_to_array(s, para);
+
+       if(mptr == NULL)
+       {
+               do_numeric(numeric, client_p, from, i, para);
+               return;
+       }
+
+       if(handle_command(mptr, client_p, from, i, /* XXX discards const!!! */ (const char **)para) < -1)
+       {
+               char *p;
+               for (p = pbuffer; p <= end; p += 8)
+               {
+                       /* HACK HACK */
+                       /* Its expected this nasty code can be removed
+                        * or rewritten later if still needed.
+                        */
+                       if((unsigned long) (p + 8) > (unsigned long) end)
+                       {
+                               for (; p <= end; p++)
+                               {
+                                       ilog(L_MAIN, "%02x |%c", p[0], p[0]);
+                               }
+                       }
+                       else
+                               ilog(L_MAIN,
+                                    "%02x %02x %02x %02x %02x %02x %02x %02x |%c%c%c%c%c%c%c%c",
+                                    p[0], p[1], p[2], p[3], p[4], p[5],
+                                    p[6], p[7], p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
+               }
+       }
+
+}
+
+/*
+ * handle_command
+ *
+ * inputs      - pointer to message block
+ *             - pointer to client
+ *             - pointer to client message is from
+ *             - count of number of args
+ *             - pointer to argv[] array
+ * output      - -1 if error from server
+ * side effects        -
+ */
+static int
+handle_command(struct Message *mptr, struct Client *client_p,
+              struct Client *from, int i, const char** hpara)
+{
+       struct MessageEntry ehandler;
+       MessageHandler handler = 0;
+       char squitreason[80];
+
+       if(IsAnyDead(client_p))
+               return -1;
+
+       if(IsServer(client_p))
+               mptr->rcount++;
+
+       mptr->count++;
+
+       /* New patch to avoid server flooding from unregistered connects
+          - Pie-Man 07/27/2000 */
+
+       if(!IsRegistered(client_p))
+       {
+               /* if its from a possible server connection
+                * ignore it.. more than likely its a header thats sneaked through
+                */
+
+               if(IsAnyServer(client_p) && !(mptr->flags & MFLG_UNREG))
+                       return (1);
+       }
+
+       ehandler = mptr->handlers[from->handler];
+       handler = ehandler.handler;
+
+       /* check right amount of params is passed... --is */
+       if(i < ehandler.min_para || 
+          (ehandler.min_para && EmptyString(hpara[ehandler.min_para - 1])))
+       {
+               if(!IsServer(client_p))
+               {
+                       sendto_one(client_p, form_str(ERR_NEEDMOREPARAMS),
+                                  me.name, 
+                                  EmptyString(client_p->name) ? "*" : client_p->name, 
+                                  mptr->cmd);
+                       if(MyClient(client_p))
+                               return (1);
+                       else
+                               return (-1);
+               }
+
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Dropping server %s due to (invalid) command '%s'"
+                                    " with only %d arguments (expecting %d).",
+                                    client_p->name, mptr->cmd, i, ehandler.min_para);
+               ilog(L_SERVER,
+                    "Insufficient parameters (%d < %d) for command '%s' from %s.",
+                    i, ehandler.min_para, mptr->cmd, client_p->name);
+               snprintf(squitreason, sizeof squitreason,
+                               "Insufficient parameters (%d < %d) for command '%s'",
+                               i, ehandler.min_para, mptr->cmd);
+               exit_client(client_p, client_p, client_p, squitreason);
+               return (-1);
+       }
+
+       (*handler) (client_p, from, i, hpara);
+       return (1);
+}
+
+void
+handle_encap(struct Client *client_p, struct Client *source_p,
+            const char *command, int parc, const char *parv[])
+{
+       struct Message *mptr;
+       struct MessageEntry ehandler;
+       MessageHandler handler = 0;
+
+       parv[0] = source_p->name;
+
+       mptr = hash_parse(command);
+
+       if(mptr == NULL || mptr->cmd == NULL)
+               return;
+
+       ehandler = mptr->handlers[ENCAP_HANDLER];
+       handler = ehandler.handler;
+
+       if(parc < ehandler.min_para || 
+          (ehandler.min_para && EmptyString(parv[ehandler.min_para - 1])))
+               return;
+
+       (*handler) (client_p, source_p, parc, parv);
+}
+
+/*
+ * clear_hash_parse()
+ *
+ * inputs       -
+ * output       - NONE
+ * side effects - MUST MUST be called at startup ONCE before
+ *                any other keyword hash routine is used.
+ *
+ */
+void
+clear_hash_parse()
+{
+       memset(msg_hash_table, 0, sizeof(msg_hash_table));
+}
+
+/* mod_add_cmd
+ *
+ * inputs      - command name
+ *             - pointer to struct Message
+ * output      - none
+ * side effects - load this one command name
+ *               msg->count msg->bytes is modified in place, in
+ *               modules address space. Might not want to do that...
+ */
+void
+mod_add_cmd(struct Message *msg)
+{
+       struct MessageHash *ptr;
+       struct MessageHash *last_ptr = NULL;
+       struct MessageHash *new_ptr;
+       int msgindex;
+
+       s_assert(msg != NULL);
+       if(msg == NULL)
+               return;
+
+       msgindex = cmd_hash(msg->cmd);
+
+       for (ptr = msg_hash_table[msgindex]; ptr; ptr = ptr->next)
+       {
+               if(strcasecmp(msg->cmd, ptr->cmd) == 0)
+                       return; /* Its already added */
+               last_ptr = ptr;
+       }
+
+       new_ptr = (struct MessageHash *) MyMalloc(sizeof(struct MessageHash));
+
+       new_ptr->next = NULL;
+       DupString(new_ptr->cmd, msg->cmd);
+       new_ptr->msg = msg;
+
+       msg->count = 0;
+       msg->rcount = 0;
+       msg->bytes = 0;
+
+       if(last_ptr == NULL)
+               msg_hash_table[msgindex] = new_ptr;
+       else
+               last_ptr->next = new_ptr;
+}
+
+/* mod_del_cmd
+ *
+ * inputs      - command name
+ * output      - none
+ * side effects - unload this one command name
+ */
+void
+mod_del_cmd(struct Message *msg)
+{
+       struct MessageHash *ptr;
+       struct MessageHash *last_ptr = NULL;
+       int msgindex;
+
+       s_assert(msg != NULL);
+       if(msg == NULL)
+               return;
+
+       msgindex = cmd_hash(msg->cmd);
+
+       for (ptr = msg_hash_table[msgindex]; ptr; ptr = ptr->next)
+       {
+               if(strcasecmp(msg->cmd, ptr->cmd) == 0)
+               {
+                       MyFree(ptr->cmd);
+                       if(last_ptr != NULL)
+                               last_ptr->next = ptr->next;
+                       else
+                               msg_hash_table[msgindex] = ptr->next;
+                       MyFree(ptr);
+                       return;
+               }
+               last_ptr = ptr;
+       }
+}
+
+/* hash_parse
+ *
+ * inputs      - command name
+ * output      - pointer to struct Message
+ * side effects - 
+ */
+static struct Message *
+hash_parse(const char *cmd)
+{
+       struct MessageHash *ptr;
+       int msgindex;
+
+       msgindex = cmd_hash(cmd);
+
+       for (ptr = msg_hash_table[msgindex]; ptr; ptr = ptr->next)
+       {
+               if(strcasecmp(cmd, ptr->cmd) == 0)
+                       return (ptr->msg);
+       }
+
+       return NULL;
+}
+
+/* alias_parse
+ *
+ * inputs      - command name
+ * output      - pointer to struct Message
+ * side effects - 
+ */
+static struct alias_entry *
+alias_parse(const char *cmd)
+{
+       dlink_node *ptr;
+       int msgindex;
+
+       msgindex = cmd_hash(cmd);
+
+       DLINK_FOREACH(ptr, alias_hash_table[msgindex].head)
+       {
+               struct alias_entry *ent = (struct alias_entry *) ptr->data;
+
+               if(strcasecmp(cmd, ent->name) == 0)
+                       return ent;
+       }
+
+       return NULL;
+}
+
+/*
+ * hash
+ *
+ * inputs      - char string
+ * output      - hash index
+ * side effects - NONE
+ *
+ * BUGS                - This a HORRIBLE hash function
+ */
+static int
+cmd_hash(const char *p)
+{
+       int hash_val = 0;
+
+       while (*p)
+       {
+               hash_val += ((int) (*p) & 0xDF);
+               p++;
+       }
+
+       return (hash_val % MAX_MSG_HASH);
+}
+
+/*
+ * report_messages
+ *
+ * inputs      - pointer to client to report to
+ * output      - NONE
+ * side effects        - NONE
+ */
+void
+report_messages(struct Client *source_p)
+{
+       int i;
+       struct MessageHash *ptr;
+       dlink_node *pptr;
+
+       for (i = 0; i < MAX_MSG_HASH; i++)
+       {
+               for (ptr = msg_hash_table[i]; ptr; ptr = ptr->next)
+               {
+                       s_assert(ptr->msg != NULL);
+                       s_assert(ptr->cmd != NULL);
+
+                       sendto_one_numeric(source_p, RPL_STATSCOMMANDS, 
+                                          form_str(RPL_STATSCOMMANDS),
+                                          ptr->cmd, ptr->msg->count, 
+                                          ptr->msg->bytes, ptr->msg->rcount);
+               }
+
+               DLINK_FOREACH(pptr, alias_hash_table[i].head)
+               {
+                       struct alias_entry *aptr = (struct alias_entry *) pptr->data;
+
+                       s_assert(aptr->name != NULL);
+
+                       sendto_one_numeric(source_p, RPL_STATSCOMMANDS,
+                                          form_str(RPL_STATSCOMMANDS),
+                                          aptr->name, aptr->hits, 0, 0);
+               }
+       }
+}
+
+/* cancel_clients()
+ *
+ * inputs      - client who sent us the message, client with fake
+ *               direction, command
+ * outputs     - a given warning about the fake direction
+ * side effects -
+ */
+static void
+cancel_clients(struct Client *client_p, struct Client *source_p, char *cmd)
+{
+       /* ok, fake prefix happens naturally during a burst on a nick
+        * collision with TS5, we cant kill them because one client has to
+        * survive, so we just send an error.
+        */
+       if(IsServer(source_p) || IsMe(source_p))
+       {
+               sendto_realops_snomask(SNO_DEBUG, L_ALL,
+                                    "Message for %s[%s] from %s",
+                                    source_p->name, source_p->from->name,
+                                    get_server_name(client_p, SHOW_IP));
+       }
+       else
+       {
+               sendto_realops_snomask(SNO_DEBUG, L_ALL,
+                                    "Message for %s[%s@%s!%s] from %s (TS, ignored)",
+                                    source_p->name,
+                                    source_p->username,
+                                    source_p->host,
+                                    source_p->from->name,
+                                    get_server_name(client_p, SHOW_IP));
+       }
+}
+
+/* remove_unknown()
+ *
+ * inputs      - client who gave us message, supposed sender, buffer
+ * output      - 
+ * side effects        - kills issued for clients, squits for servers
+ */
+static void
+remove_unknown(struct Client *client_p, char *lsender, char *lbuffer)
+{
+       int slen = strlen(lsender);
+
+       /* meepfoo      is a nickname (KILL)
+        * #XXXXXXXX    is a UID (KILL)
+        * #XX          is a SID (SQUIT)
+        * meep.foo     is a server (SQUIT)
+        */
+       if((IsDigit(lsender[0]) && slen == 3) || 
+          (strchr(lsender, '.') != NULL))
+       {
+               sendto_realops_snomask(SNO_DEBUG, L_ALL,
+                                    "Unknown prefix (%s) from %s, Squitting %s",
+                                    lbuffer, get_server_name(client_p, SHOW_IP), lsender);
+
+               sendto_one(client_p,
+                          ":%s SQUIT %s :(Unknown prefix (%s) from %s)",
+                          get_id(&me, client_p), lsender, 
+                          lbuffer, client_p->name);
+       }
+       else
+               sendto_one(client_p, ":%s KILL %s :%s (Unknown Client)", 
+                          get_id(&me, client_p), lsender, me.name);
+}
+
+
+
+/*
+ *
+ *      parc    number of arguments ('sender' counted as one!)
+ *      parv[0] pointer to 'sender' (may point to empty string) (not used)
+ *      parv[1]..parv[parc-1]
+ *              pointers to additional parameters, this is a NULL
+ *              terminated list (parv[parc] == NULL).
+ *
+ * *WARNING*
+ *      Numerics are mostly error reports. If there is something
+ *      wrong with the message, just *DROP* it! Don't even think of
+ *      sending back a neat error message -- big danger of creating
+ *      a ping pong error message...
+ */
+static void
+do_numeric(char numeric[], struct Client *client_p, struct Client *source_p, int parc, char *parv[])
+{
+       struct Client *target_p;
+       struct Channel *chptr;
+
+       if(parc < 2 || !IsServer(source_p))
+               return;
+
+       /* Remap low number numerics. */
+       if(numeric[0] == '0')
+               numeric[0] = '1';
+
+       /*
+        * Prepare the parameter portion of the message into 'buffer'.
+        * (Because the buffer is twice as large as the message buffer
+        * for the socket, no overflow can occur here... ...on current
+        * assumptions--bets are off, if these are changed --msa)
+        * Note: if buffer is non-empty, it will begin with SPACE.
+        */
+       if(parc > 1)
+       {
+               char *t = buffer;       /* Current position within the buffer */
+               int i;
+               int tl;         /* current length of presently being built string in t */
+               for (i = 2; i < (parc - 1); i++)
+               {
+                       tl = ircsprintf(t, " %s", parv[i]);
+                       t += tl;
+               }
+               ircsprintf(t, " :%s", parv[parc - 1]);
+       }
+
+       if((target_p = find_client(parv[1])) != NULL)
+       {
+               if(IsMe(target_p))
+               {
+                       /*
+                        * We shouldn't get numerics sent to us,
+                        * any numerics we do get indicate a bug somewhere..
+                        */
+                       /* ugh.  this is here because of nick collisions.  when two servers
+                        * relink, they burst each other their nicks, then perform collides.
+                        * if there is a nick collision, BOTH servers will kill their own
+                        * nicks, and BOTH will kill the other servers nick, which wont exist,
+                        * because it will have been already killed by the local server.
+                        *
+                        * unfortunately, as we cant guarantee other servers will do the
+                        * "right thing" on a nick collision, we have to keep both kills.  
+                        * ergo we need to ignore ERR_NOSUCHNICK. --fl_
+                        */
+                       /* quick comment. This _was_ tried. i.e. assume the other servers
+                        * will do the "right thing" and kill a nick that is colliding.
+                        * unfortunately, it did not work. --Dianora
+                        */
+                       /* note, now we send PING on server connect, we can
+                        * also get ERR_NOSUCHSERVER..
+                        */
+                       if(atoi(numeric) != ERR_NOSUCHNICK &&
+                          atoi(numeric) != ERR_NOSUCHSERVER)
+                               sendto_realops_snomask(SNO_GENERAL, L_ADMIN,
+                                                    "*** %s(via %s) sent a %s numeric to me: %s",
+                                                    source_p->name,
+                                                    client_p->name, numeric, buffer);
+                       return;
+               }
+               else if(target_p->from == client_p)
+               {
+                       /* This message changed direction (nick collision?)
+                        * ignore it.
+                        */
+                       return;
+               }
+
+               /* csircd will send out unknown umode flag for +a (admin), drop it here. */
+               if((atoi(numeric) == ERR_UMODEUNKNOWNFLAG) && MyClient(target_p))
+                       return;
+
+               /* Fake it for server hiding, if its our client */
+               sendto_one(target_p, ":%s %s %s%s", 
+                          get_id(source_p, target_p), numeric, 
+                          get_id(target_p, target_p), buffer);
+               return;
+       }
+       else if((chptr = find_channel(parv[1])) != NULL)
+               sendto_channel_local(ALL_MEMBERS, chptr,
+                                    ":%s %s %s %s",
+                                    source_p->name, numeric, chptr->chname, buffer);
+}
+
+static void do_alias(struct alias_entry *aptr, struct Client *source_p, char *text)
+{
+       char *p;
+       struct Client *target_p;
+
+       if (!IsFloodDone(source_p) && source_p->localClient->receiveM > 20)
+               flood_endgrace(source_p);
+
+       p = strchr(aptr->target, '@');
+       if (p != NULL)
+       {
+               /* user@server */
+               target_p = find_server(NULL, p + 1);
+               if (target_p != NULL && IsMe(target_p))
+                       target_p = NULL;
+       }
+       else
+       {
+               /* nick, must be +S */
+               target_p = find_named_person(aptr->target);
+               if (target_p != NULL && !IsService(target_p))
+                       target_p = NULL;
+       }
+
+       if (target_p == NULL)
+       {
+               sendto_one_numeric(source_p, ERR_SERVICESDOWN, form_str(ERR_SERVICESDOWN), aptr->target);
+               return;
+       }
+
+       if (text != NULL && *text == ':')
+               text++;
+       if (text == NULL || *text == '\0')
+       {
+               sendto_one(source_p, form_str(ERR_NOTEXTTOSEND), me.name, source_p->name);
+               return;
+       }
+
+       /* increment the hitcounter on this alias */
+       aptr->hits++;
+
+       sendto_one(target_p, ":%s PRIVMSG %s :%s",
+                       get_id(source_p, target_p),
+                       p != NULL ? aptr->target : get_id(target_p, target_p),
+                       text);
+}
+
+int
+m_not_oper(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES));
+       return 0;
+}
+
+int
+m_unregistered(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       /* bit of a hack.
+        * I don't =really= want to waste a bit in a flag
+        * number_of_nick_changes is only really valid after the client
+        * is fully registered..
+        */
+       if(client_p->localClient->number_of_nick_changes == 0)
+       {
+               sendto_one(client_p, form_str(ERR_NOTREGISTERED), me.name);
+               client_p->localClient->number_of_nick_changes++;
+       }
+
+       return 0;
+}
+
+int
+m_registered(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       sendto_one(client_p, form_str(ERR_ALREADYREGISTRED), me.name, source_p->name);
+       return 0;
+}
+
+int
+m_ignore(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       return 0;
+}
diff --git a/src/patricia.c b/src/patricia.c
new file mode 100644 (file)
index 0000000..43459e3
--- /dev/null
@@ -0,0 +1,1092 @@
+/*
+ * Yanked out of Net::Patricia by Aaron Sethman <androsyn@ratbox.org>
+ *
+ * $Id: patricia.c 1110 2006-03-29 22:55:25Z nenolod $
+ * Dave Plonka <plonka@doit.wisc.edu>
+ *
+ * This product includes software developed by the University of Michigan,
+ * Merit Network, Inc., and their contributors. 
+ *
+ * This file had been called "radix.c" in the MRT sources.
+ *
+ * I renamed it to "patricia.c" since it's not an implementation of a general
+ * radix trie.  Also I pulled in various requirements from "prefix.c" and
+ * "demo.c" so that it could be used as a standalone API.
+ *
+ * This product includes software developed by the University of Michigan, Merit
+ * Network, Inc., and their contributors.
+ *
+ */
+
+
+#include "stdinc.h"
+#include "config.h"
+#include "ircd_defs.h"
+#include "patricia.h"
+#include "balloc.h"
+
+extern BlockHeap *prefix_heap;
+extern BlockHeap *node_heap;
+extern BlockHeap *patricia_heap;
+
+/* Enable both of these to debug patricia.c
+ * #define NOTYET 1
+ * #define PATRICIA_DEBUG 1
+ */
+#define PREFIX_HEAP_COUNT      1024
+#define NODE_HEAP_COUNT                1024
+#define PATRICIA_HEAP_COUNT    128
+
+void
+init_patricia(void)
+{
+       prefix_heap = BlockHeapCreate(sizeof(prefix_t), PREFIX_HEAP_COUNT);
+       node_heap = BlockHeapCreate(sizeof(patricia_node_t), NODE_HEAP_COUNT);
+       patricia_heap = BlockHeapCreate(sizeof(patricia_tree_t), PATRICIA_HEAP_COUNT);
+}
+
+/* prefix_tochar
+ * convert prefix information to bytes
+ */
+static u_char *
+prefix_tochar(prefix_t * prefix)
+{
+       if(prefix == NULL)
+               return (NULL);
+
+       return ((u_char *) & prefix->add.sin);
+}
+
+#if 0
+static int
+comp_with_mask(void *addr, void *dest, u_int mask)
+{
+
+       if( /* mask/8 == 0 || */ memcmp(addr, dest, mask / 8) == 0)
+       {
+               int n = mask / 8;
+               int m = ((-1) << (8 - (mask % 8)));
+
+               if(mask % 8 == 0 || (((u_char *) addr)[n] & m) == (((u_char *) dest)[n] & m))
+                       return (1);
+       }
+       return (0);
+}
+#endif
+#ifdef NOTYET
+static char *
+prefix_toa2x(prefix_t * prefix, char *buf, int buf_len, int with_len)
+{
+       static char tmp[6];
+       if(prefix == NULL)
+       {
+               strcpy(buf, "(NULL)");
+               return (buf);
+       }
+       inet_ntop(prefix->family, &prefix->add.sin, buf, buf_len);
+       if(with_len)
+       {
+               ircsnprintf(tmp, sizeof(tmp), "/%d", prefix->bitlen);
+               strcat(buf, tmp);
+       }
+       return (buf);
+}
+
+/* prefix_toa2
+ * convert prefix information to ascii string
+ */
+
+static char *
+prefix_toa2(prefix_t * prefix, char *buff, int buf_len)
+{
+       return (prefix_toa2x(prefix, buff, buf_len, 0));
+}
+static char *
+prefix_toa(prefix_t * prefix)
+{
+#ifdef IPV6
+       static char buf[INET6_ADDRSTRLEN + 6];
+#else
+       static char buf[16 + 6];
+#endif
+       return (prefix_toa2(prefix, buf, sizeof(buf)));
+}
+#endif
+static prefix_t *
+New_Prefix2(int family, void *dest, int bitlen, prefix_t * prefix)
+{
+       int dynamic_allocated = 0;
+#ifdef IPV6
+       int default_bitlen = 128;
+#else
+       int default_bitlen = 32;
+#endif
+
+#ifdef IPV6
+       if(family == AF_INET6)
+       {
+               default_bitlen = 128;
+               if(prefix == NULL)
+               {
+                       prefix = BlockHeapAlloc(prefix_heap);
+                       dynamic_allocated++;
+               }
+               memcpy(&prefix->add.sin6, dest, 16);
+       }
+       else
+#endif /* IPV6 */
+       if(family == AF_INET)
+       {
+               if(prefix == NULL)
+               {
+                       prefix = BlockHeapAlloc(prefix_heap);
+                       dynamic_allocated++;
+               }
+               memcpy(&prefix->add.sin, dest, 4);
+       }
+       else
+       {
+               return (NULL);
+       }
+
+       prefix->bitlen = (bitlen >= 0) ? bitlen : default_bitlen;
+       prefix->family = family;
+       prefix->ref_count = 0;
+       if(dynamic_allocated)
+       {
+               prefix->ref_count++;
+       }
+       return (prefix);
+}
+
+static prefix_t *
+New_Prefix(int family, void *dest, int bitlen)
+{
+       return (New_Prefix2(family, dest, bitlen, NULL));
+}
+
+/* ascii2prefix
+ */
+static prefix_t *
+ascii2prefix(int family, const char *string)
+{
+       long bitlen, maxbitlen = 0;
+       char *cp;
+       struct in_addr sinaddr;
+#ifdef IPV6
+       struct in6_addr sinaddr6;
+#endif /* IPV6 */
+       int result;
+       char save[MAXLINE];
+
+       if(string == NULL)
+               return (NULL);
+
+       /* easy way to handle both families */
+       if(family == 0)
+       {
+               family = AF_INET;
+#ifdef IPV6
+               if(strchr(string, ':'))
+                       family = AF_INET6;
+#endif /* IPV6 */
+       }
+       if(family == AF_INET)
+       {
+               maxbitlen = 32;
+       }
+#ifdef IPV6
+       else if(family == AF_INET6)
+       {
+               maxbitlen = 128;
+       }
+#endif /* IPV6 */
+
+       if((cp = strchr(string, '/')) != NULL)
+       {
+               bitlen = atol(cp + 1);
+               /* *cp = '\0'; */
+               /* copy the string to save. Avoid destroying the string */
+               assert(cp - string < MAXLINE);
+               memcpy(save, string, cp - string);
+               save[cp - string] = '\0';
+               string = save;
+               if(bitlen <= 0 || bitlen > maxbitlen)
+                       bitlen = maxbitlen;
+       }
+       else
+       {
+               bitlen = maxbitlen;
+       }
+
+       if(family == AF_INET)
+       {
+               if((result = inetpton(AF_INET, string, &sinaddr)) <= 0)
+                       return (NULL);
+               return (New_Prefix(AF_INET, &sinaddr, bitlen));
+       }
+#ifdef IPV6
+       else if(family == AF_INET6)
+       {
+               if((result = inetpton(AF_INET6, string, &sinaddr6)) <= 0)
+                       return (NULL);
+               return (New_Prefix(AF_INET6, &sinaddr6, bitlen));
+       }
+#endif /* IPV6 */
+       else
+               return (NULL);
+}
+
+static prefix_t *
+Ref_Prefix(prefix_t * prefix)
+{
+       if(prefix == NULL)
+               return (NULL);
+       if(prefix->ref_count == 0)
+       {
+               /* make a copy in case of a static prefix */
+               return (New_Prefix2(prefix->family, &prefix->add, prefix->bitlen, NULL));
+       }
+       prefix->ref_count++;
+       return (prefix);
+}
+
+static void
+Deref_Prefix(prefix_t * prefix)
+{
+       if(prefix == NULL)
+               return;
+       /* for secure programming, raise an assert. no static prefix can call this */
+       assert(prefix->ref_count > 0);
+
+       prefix->ref_count--;
+       assert(prefix->ref_count >= 0);
+       if(prefix->ref_count <= 0)
+       {
+               BlockHeapFree(prefix_heap, prefix);
+               return;
+       }
+}
+
+/* } */
+
+/* #define PATRICIA_DEBUG 1 */
+
+static int num_active_patricia = 0;
+
+/* these routines support continuous mask only */
+
+patricia_tree_t *
+New_Patricia(int maxbits)
+{
+       patricia_tree_t *patricia = BlockHeapAlloc(patricia_heap);
+
+       patricia->maxbits = maxbits;
+       patricia->head = NULL;
+       patricia->num_active_node = 0;
+       assert(maxbits <= PATRICIA_MAXBITS);    /* XXX */
+       num_active_patricia++;
+       return (patricia);
+}
+
+
+/*
+ * if func is supplied, it will be called as func(node->data)
+ * before deleting the node
+ */
+
+void
+Clear_Patricia(patricia_tree_t * patricia, void_fn_t func)
+{
+       assert(patricia);
+       if(patricia->head)
+       {
+
+               patricia_node_t *Xstack[PATRICIA_MAXBITS + 1];
+               patricia_node_t **Xsp = Xstack;
+               patricia_node_t *Xrn = patricia->head;
+
+               while (Xrn)
+               {
+                       patricia_node_t *l = Xrn->l;
+                       patricia_node_t *r = Xrn->r;
+
+                       if(Xrn->prefix)
+                       {
+                               Deref_Prefix(Xrn->prefix);
+                               if(Xrn->data && func)
+                                       func(Xrn->data);
+                       }
+                       else
+                       {
+                               assert(Xrn->data == NULL);
+                       }
+                       BlockHeapFree(node_heap, Xrn);
+                       patricia->num_active_node--;
+
+                       if(l)
+                       {
+                               if(r)
+                               {
+                                       *Xsp++ = r;
+                               }
+                               Xrn = l;
+                       }
+                       else if(r)
+                       {
+                               Xrn = r;
+                       }
+                       else if(Xsp != Xstack)
+                       {
+                               Xrn = *(--Xsp);
+                       }
+                       else
+                       {
+                               Xrn = (patricia_node_t *) 0;
+                       }
+               }
+       }
+       assert(patricia->num_active_node == 0);
+       BlockHeapFree(patricia_heap, patricia);
+}
+
+
+void
+Destroy_Patricia(patricia_tree_t * patricia, void_fn_t func)
+{
+       Clear_Patricia(patricia, func);
+       num_active_patricia--;
+}
+
+
+/*
+ * if func is supplied, it will be called as func(node->prefix, node->data)
+ */
+
+void
+patricia_process(patricia_tree_t * patricia, void_fn_t func)
+{
+       patricia_node_t *node;
+       assert(func);
+
+       PATRICIA_WALK(patricia->head, node)
+       {
+               func(node->prefix, node->data);
+       }
+       PATRICIA_WALK_END;
+}
+
+patricia_node_t *
+patricia_search_exact(patricia_tree_t * patricia, prefix_t * prefix)
+{
+       patricia_node_t *node;
+       u_char *addr;
+       u_int bitlen;
+
+       assert(patricia);
+       assert(prefix);
+       assert(prefix->bitlen <= patricia->maxbits);
+
+       if(patricia->head == NULL)
+               return (NULL);
+
+       node = patricia->head;
+       addr = prefix_touchar(prefix);
+       bitlen = prefix->bitlen;
+
+       while (node->bit < bitlen)
+       {
+
+               if(BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07)))
+               {
+#ifdef PATRICIA_DEBUG
+                       if(node->prefix)
+                               fprintf(stderr,
+                                       "patricia_search_exact: take right %s/%d\n",
+                                       prefix_toa(node->prefix), node->prefix->bitlen);
+                       else
+                               fprintf(stderr,
+                                       "patricia_search_exact: take right at %d\n", node->bit);
+#endif /* PATRICIA_DEBUG */
+                       node = node->r;
+               }
+               else
+               {
+#ifdef PATRICIA_DEBUG
+                       if(node->prefix)
+                               fprintf(stderr,
+                                       "patricia_search_exact: take left %s/%d\n",
+                                       prefix_toa(node->prefix), node->prefix->bitlen);
+                       else
+                               fprintf(stderr,
+                                       "patricia_search_exact: take left at %d\n", node->bit);
+#endif /* PATRICIA_DEBUG */
+                       node = node->l;
+               }
+
+               if(node == NULL)
+                       return (NULL);
+       }
+
+#ifdef PATRICIA_DEBUG
+       if(node->prefix)
+               fprintf(stderr, "patricia_search_exact: stop at %s/%d %d\n",
+                       prefix_toa(node->prefix), node->prefix->bitlen, node->bit);
+       else
+               fprintf(stderr, "patricia_search_exact: stop at %d\n", node->bit);
+#endif /* PATRICIA_DEBUG */
+       if(node->bit > bitlen || node->prefix == NULL)
+               return (NULL);
+       assert(node->bit == bitlen);
+       assert(node->bit == node->prefix->bitlen);
+       if(comp_with_mask(prefix_tochar(node->prefix), prefix_tochar(prefix), bitlen))
+       {
+#ifdef PATRICIA_DEBUG
+               fprintf(stderr, "patricia_search_exact: found %s/%d\n",
+                       prefix_toa(node->prefix), node->prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+               return (node);
+       }
+       return (NULL);
+}
+
+/* if inclusive != 0, "best" may be the given prefix itself */
+patricia_node_t *
+patricia_search_best2(patricia_tree_t * patricia, prefix_t * prefix, int inclusive)
+{
+       patricia_node_t *node;
+       patricia_node_t *stack[PATRICIA_MAXBITS + 1];
+       u_char *addr;
+       u_int bitlen;
+       int cnt = 0;
+
+       assert(patricia);
+       assert(prefix);
+       assert(prefix->bitlen <= patricia->maxbits);
+
+       if(patricia->head == NULL)
+               return (NULL);
+
+       node = patricia->head;
+       addr = prefix_touchar(prefix);
+       bitlen = prefix->bitlen;
+
+       while (node->bit < bitlen)
+       {
+
+               if(node->prefix)
+               {
+#ifdef PATRICIA_DEBUG
+                       fprintf(stderr,
+                               "patricia_search_best: push %s/%d\n",
+                               prefix_toa(node->prefix), node->prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+                       stack[cnt++] = node;
+               }
+
+               if(BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07)))
+               {
+#ifdef PATRICIA_DEBUG
+                       if(node->prefix)
+                               fprintf(stderr,
+                                       "patricia_search_best: take right %s/%d\n",
+                                       prefix_toa(node->prefix), node->prefix->bitlen);
+                       else
+                               fprintf(stderr,
+                                       "patricia_search_best: take right at %d\n", node->bit);
+#endif /* PATRICIA_DEBUG */
+                       node = node->r;
+               }
+               else
+               {
+#ifdef PATRICIA_DEBUG
+                       if(node->prefix)
+                               fprintf(stderr,
+                                       "patricia_search_best: take left %s/%d\n",
+                                       prefix_toa(node->prefix), node->prefix->bitlen);
+                       else
+                               fprintf(stderr,
+                                       "patricia_search_best: take left at %d\n", node->bit);
+#endif /* PATRICIA_DEBUG */
+                       node = node->l;
+               }
+
+               if(node == NULL)
+                       break;
+       }
+
+       if(inclusive && node && node->prefix)
+               stack[cnt++] = node;
+
+#ifdef PATRICIA_DEBUG
+       if(node == NULL)
+               fprintf(stderr, "patricia_search_best: stop at null\n");
+       else if(node->prefix)
+               fprintf(stderr, "patricia_search_best: stop at %s/%d\n",
+                       prefix_toa(node->prefix), node->prefix->bitlen);
+       else
+               fprintf(stderr, "patricia_search_best: stop at %d\n", node->bit);
+#endif /* PATRICIA_DEBUG */
+
+       if(cnt <= 0)
+               return (NULL);
+
+       while (--cnt >= 0)
+       {
+               node = stack[cnt];
+#ifdef PATRICIA_DEBUG
+               fprintf(stderr, "patricia_search_best: pop %s/%d\n",
+                       prefix_toa(node->prefix), node->prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+               if(comp_with_mask(prefix_tochar(node->prefix),
+                                 prefix_tochar(prefix), node->prefix->bitlen))
+               {
+#ifdef PATRICIA_DEBUG
+                       fprintf(stderr,
+                               "patricia_search_best: found %s/%d\n",
+                               prefix_toa(node->prefix), node->prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+                       return (node);
+               }
+       }
+       return (NULL);
+}
+
+
+patricia_node_t *
+patricia_search_best(patricia_tree_t * patricia, prefix_t * prefix)
+{
+       return (patricia_search_best2(patricia, prefix, 1));
+}
+
+
+patricia_node_t *
+patricia_lookup(patricia_tree_t * patricia, prefix_t * prefix)
+{
+       patricia_node_t *node, *new_node, *parent, *glue;
+       u_char *addr, *test_addr;
+       u_int bitlen, check_bit, differ_bit;
+       unsigned int i, j, r;
+
+       assert(patricia);
+       assert(prefix);
+       assert(prefix->bitlen <= patricia->maxbits);
+
+       if(patricia->head == NULL)
+       {
+               node = BlockHeapAlloc(node_heap);
+               node->bit = prefix->bitlen;
+               node->prefix = Ref_Prefix(prefix);
+               node->parent = NULL;
+               node->l = node->r = NULL;
+               node->data = NULL;
+               patricia->head = node;
+#ifdef PATRICIA_DEBUG
+               fprintf(stderr,
+                       "patricia_lookup: new_node #0 %s/%d (head)\n",
+                       prefix_toa(prefix), prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+               patricia->num_active_node++;
+               return (node);
+       }
+
+       addr = prefix_touchar(prefix);
+       bitlen = prefix->bitlen;
+       node = patricia->head;
+
+       while (node->bit < bitlen || node->prefix == NULL)
+       {
+
+               if(node->bit < patricia->maxbits &&
+                  BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07)))
+               {
+                       if(node->r == NULL)
+                               break;
+#ifdef PATRICIA_DEBUG
+                       if(node->prefix)
+                               fprintf(stderr,
+                                       "patricia_lookup: take right %s/%d\n",
+                                       prefix_toa(node->prefix), node->prefix->bitlen);
+                       else
+                               fprintf(stderr, "patricia_lookup: take right at %d\n", node->bit);
+#endif /* PATRICIA_DEBUG */
+                       node = node->r;
+               }
+               else
+               {
+                       if(node->l == NULL)
+                               break;
+#ifdef PATRICIA_DEBUG
+                       if(node->prefix)
+                               fprintf(stderr,
+                                       "patricia_lookup: take left %s/%d\n",
+                                       prefix_toa(node->prefix), node->prefix->bitlen);
+                       else
+                               fprintf(stderr, "patricia_lookup: take left at %d\n", node->bit);
+#endif /* PATRICIA_DEBUG */
+                       node = node->l;
+               }
+
+               assert(node);
+       }
+
+       assert(node->prefix);
+#ifdef PATRICIA_DEBUG
+       fprintf(stderr, "patricia_lookup: stop at %s/%d\n",
+               prefix_toa(node->prefix), node->prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+
+       test_addr = prefix_touchar(node->prefix);
+       /* find the first bit different */
+       check_bit = (node->bit < bitlen) ? node->bit : bitlen;
+       differ_bit = 0;
+       for (i = 0; i * 8 < check_bit; i++)
+       {
+               if((r = (addr[i] ^ test_addr[i])) == 0)
+               {
+                       differ_bit = (i + 1) * 8;
+                       continue;
+               }
+               /* I know the better way, but for now */
+               for (j = 0; j < 8; j++)
+               {
+                       if(BIT_TEST(r, (0x80 >> j)))
+                               break;
+               }
+               /* must be found */
+               assert(j < 8);
+               differ_bit = i * 8 + j;
+               break;
+       }
+       if(differ_bit > check_bit)
+               differ_bit = check_bit;
+#ifdef PATRICIA_DEBUG
+       fprintf(stderr, "patricia_lookup: differ_bit %d\n", differ_bit);
+#endif /* PATRICIA_DEBUG */
+
+       parent = node->parent;
+       while (parent && parent->bit >= differ_bit)
+       {
+               node = parent;
+               parent = node->parent;
+#ifdef PATRICIA_DEBUG
+               if(node->prefix)
+                       fprintf(stderr, "patricia_lookup: up to %s/%d\n",
+                               prefix_toa(node->prefix), node->prefix->bitlen);
+               else
+                       fprintf(stderr, "patricia_lookup: up to %d\n", node->bit);
+#endif /* PATRICIA_DEBUG */
+       }
+
+       if(differ_bit == bitlen && node->bit == bitlen)
+       {
+               if(node->prefix)
+               {
+#ifdef PATRICIA_DEBUG
+                       fprintf(stderr, "patricia_lookup: found %s/%d\n",
+                               prefix_toa(node->prefix), node->prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+                       return (node);
+               }
+               node->prefix = Ref_Prefix(prefix);
+#ifdef PATRICIA_DEBUG
+               fprintf(stderr,
+                       "patricia_lookup: new node #1 %s/%d (glue mod)\n",
+                       prefix_toa(prefix), prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+               assert(node->data == NULL);
+               return (node);
+       }
+
+       new_node = BlockHeapAlloc(node_heap);
+       new_node->bit = prefix->bitlen;
+       new_node->prefix = Ref_Prefix(prefix);
+       new_node->parent = NULL;
+       new_node->l = new_node->r = NULL;
+       new_node->data = NULL;
+       patricia->num_active_node++;
+
+       if(node->bit == differ_bit)
+       {
+               new_node->parent = node;
+               if(node->bit < patricia->maxbits &&
+                  BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07)))
+               {
+                       assert(node->r == NULL);
+                       node->r = new_node;
+               }
+               else
+               {
+                       assert(node->l == NULL);
+                       node->l = new_node;
+               }
+#ifdef PATRICIA_DEBUG
+               fprintf(stderr,
+                       "patricia_lookup: new_node #2 %s/%d (child)\n",
+                       prefix_toa(prefix), prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+               return (new_node);
+       }
+
+       if(bitlen == differ_bit)
+       {
+               if(bitlen < patricia->maxbits &&
+                  BIT_TEST(test_addr[bitlen >> 3], 0x80 >> (bitlen & 0x07)))
+               {
+                       new_node->r = node;
+               }
+               else
+               {
+                       new_node->l = node;
+               }
+               new_node->parent = node->parent;
+               if(node->parent == NULL)
+               {
+                       assert(patricia->head == node);
+                       patricia->head = new_node;
+               }
+               else if(node->parent->r == node)
+               {
+                       node->parent->r = new_node;
+               }
+               else
+               {
+                       node->parent->l = new_node;
+               }
+               node->parent = new_node;
+#ifdef PATRICIA_DEBUG
+               fprintf(stderr,
+                       "patricia_lookup: new_node #3 %s/%d (parent)\n",
+                       prefix_toa(prefix), prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+       }
+       else
+       {
+               glue = BlockHeapAlloc(node_heap);
+               glue->bit = differ_bit;
+               glue->prefix = NULL;
+               glue->parent = node->parent;
+               glue->data = NULL;
+               patricia->num_active_node++;
+               if(differ_bit < patricia->maxbits &&
+                  BIT_TEST(addr[differ_bit >> 3], 0x80 >> (differ_bit & 0x07)))
+               {
+                       glue->r = new_node;
+                       glue->l = node;
+               }
+               else
+               {
+                       glue->r = node;
+                       glue->l = new_node;
+               }
+               new_node->parent = glue;
+
+               if(node->parent == NULL)
+               {
+                       assert(patricia->head == node);
+                       patricia->head = glue;
+               }
+               else if(node->parent->r == node)
+               {
+                       node->parent->r = glue;
+               }
+               else
+               {
+                       node->parent->l = glue;
+               }
+               node->parent = glue;
+#ifdef PATRICIA_DEBUG
+               fprintf(stderr,
+                       "patricia_lookup: new_node #4 %s/%d (glue+node)\n",
+                       prefix_toa(prefix), prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+       }
+       return (new_node);
+}
+
+
+void
+patricia_remove(patricia_tree_t * patricia, patricia_node_t * node)
+{
+       patricia_node_t *parent, *child;
+
+       assert(patricia);
+       assert(node);
+
+       if(node->r && node->l)
+       {
+#ifdef PATRICIA_DEBUG
+               fprintf(stderr, "patricia_remove: #0 %s/%d (r & l)\n",
+                       prefix_toa(node->prefix), node->prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+
+               /* this might be a placeholder node -- have to check and make sure
+                * there is a prefix aossciated with it ! */
+               if(node->prefix != NULL)
+                       Deref_Prefix(node->prefix);
+               node->prefix = NULL;
+               /* Also I needed to clear data pointer -- masaki */
+               node->data = NULL;
+               return;
+       }
+
+       if(node->r == NULL && node->l == NULL)
+       {
+#ifdef PATRICIA_DEBUG
+               fprintf(stderr, "patricia_remove: #1 %s/%d (!r & !l)\n",
+                       prefix_toa(node->prefix), node->prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+               parent = node->parent;
+               Deref_Prefix(node->prefix);
+               BlockHeapFree(node_heap, node);
+               patricia->num_active_node--;
+
+               if(parent == NULL)
+               {
+                       assert(patricia->head == node);
+                       patricia->head = NULL;
+                       return;
+               }
+
+               if(parent->r == node)
+               {
+                       parent->r = NULL;
+                       child = parent->l;
+               }
+               else
+               {
+                       assert(parent->l == node);
+                       parent->l = NULL;
+                       child = parent->r;
+               }
+
+               if(parent->prefix)
+                       return;
+
+               /* we need to remove parent too */
+
+               if(parent->parent == NULL)
+               {
+                       assert(patricia->head == parent);
+                       patricia->head = child;
+               }
+               else if(parent->parent->r == parent)
+               {
+                       parent->parent->r = child;
+               }
+               else
+               {
+                       assert(parent->parent->l == parent);
+                       parent->parent->l = child;
+               }
+               child->parent = parent->parent;
+               BlockHeapFree(node_heap, parent);
+               patricia->num_active_node--;
+               return;
+       }
+#ifdef PATRICIA_DEBUG
+       fprintf(stderr, "patricia_remove: #2 %s/%d (r ^ l)\n",
+               prefix_toa(node->prefix), node->prefix->bitlen);
+#endif /* PATRICIA_DEBUG */
+       if(node->r)
+       {
+               child = node->r;
+       }
+       else
+       {
+               assert(node->l);
+               child = node->l;
+       }
+       parent = node->parent;
+       child->parent = parent;
+
+       Deref_Prefix(node->prefix);
+       BlockHeapFree(node_heap, node);
+       patricia->num_active_node--;
+
+       if(parent == NULL)
+       {
+               assert(patricia->head == node);
+               patricia->head = child;
+               return;
+       }
+
+       if(parent->r == node)
+       {
+               parent->r = child;
+       }
+       else
+       {
+               assert(parent->l == node);
+               parent->l = child;
+       }
+}
+
+patricia_node_t *
+make_and_lookup_ip(patricia_tree_t * tree, struct sockaddr *in, int bitlen)
+{
+       prefix_t *prefix;
+       patricia_node_t *node;
+       void *ipptr = NULL;
+#ifdef IPV6
+       if(in->sa_family == AF_INET6)
+               ipptr = &((struct sockaddr_in6 *)in)->sin6_addr;        
+        else
+#endif
+               ipptr = &((struct sockaddr_in *)in)->sin_addr;
+       
+       prefix = New_Prefix(in->sa_family, ipptr, bitlen);
+
+       if(prefix == NULL)
+               return NULL;
+
+       node = patricia_lookup(tree, prefix);
+
+
+
+       Deref_Prefix(prefix);
+       return (node);
+}
+
+
+patricia_node_t *
+make_and_lookup(patricia_tree_t * tree, const char *string)
+{
+       prefix_t *prefix;
+       patricia_node_t *node;
+
+       if((prefix = ascii2prefix(AF_INET, string)) != NULL)
+       {
+               node = patricia_lookup(tree, prefix);
+       }
+       else
+#ifdef IPV6
+       if((prefix = ascii2prefix(AF_INET6, string)) != NULL)
+       {
+               node = patricia_lookup(tree, prefix);
+       }
+       else
+#endif
+               return NULL;
+#ifdef PATRICIA_DEBUG
+       printf("make_and_lookup: %s/%d\n", prefix_toa(prefix), prefix->bitlen);
+#endif
+       Deref_Prefix(prefix);
+       return (node);
+}
+
+#ifdef NOTYET
+static patricia_node_t *
+try_search_exact(patricia_tree_t * tree, char *string)
+{
+       prefix_t *prefix;
+       patricia_node_t *node;
+       if((prefix = ascii2prefix(AF_INET, string)) != NULL)
+       {
+               node = patricia_search_exact(tree, prefix);
+               Deref_Prefix(prefix);
+               return (node);
+       }
+#ifdef IPV6
+       else if((prefix = ascii2prefix(AF_INET6, string)) != NULL)
+       {
+               node = patricia_search_exact(tree, prefix);
+               Deref_Prefix(prefix);
+               return (node);
+       }
+#endif
+       else
+               return NULL;
+}
+
+void
+lookup_then_remove(patricia_tree_t * tree, char *string)
+{
+       patricia_node_t *node;
+
+       if((node = try_search_exact(tree, string)))
+               patricia_remove(tree, node);
+}
+#endif
+
+patricia_node_t *
+match_ip(patricia_tree_t * tree, struct sockaddr *ip)
+{
+       prefix_t *prefix;
+       patricia_node_t *node;
+       void *ipptr;
+       unsigned int len;
+       int family;
+#ifndef IPV6
+       len = 32;
+       family = AF_INET;
+       ipptr = &((struct sockaddr_in *)ip)->sin_addr;
+#else
+       if(ip->sa_family == AF_INET6)
+       {
+               len = 128;
+               family = AF_INET6;
+               ipptr = &((struct sockaddr_in6 *)ip)->sin6_addr;
+       } else {
+               len = 32;
+               family = AF_INET;
+               ipptr = &((struct sockaddr_in *)ip)->sin_addr;
+       }
+#endif
+       
+       if((prefix = New_Prefix(family, ipptr, len)) != NULL)
+       {
+               node = patricia_search_best(tree, prefix);
+               Deref_Prefix(prefix);
+               return (node);
+       }
+       return NULL;
+}
+
+patricia_node_t *
+match_string(patricia_tree_t * tree, const char *string)
+{
+       patricia_node_t *node;
+       prefix_t *prefix;
+
+       if((prefix = ascii2prefix(AF_INET, string)) != NULL)
+       {
+               node = patricia_search_best(tree, prefix);
+               Deref_Prefix(prefix);
+       }
+       else
+#ifdef IPV6
+       if((prefix = ascii2prefix(AF_INET6, string)) != NULL)
+       {
+               node = patricia_search_best(tree, prefix);
+               Deref_Prefix(prefix);
+       }
+       else
+#endif
+               return NULL;
+       return node;
+}
+
+patricia_node_t *
+match_exact_string(patricia_tree_t * tree, const char *string)
+{
+       prefix_t *prefix;
+       patricia_node_t *node;
+       if((prefix = ascii2prefix(AF_INET, string)) != NULL)
+       {
+               node = patricia_search_exact(tree, prefix);
+               Deref_Prefix(prefix);
+       }
+       else
+#ifdef IPV6
+       if((prefix = ascii2prefix(AF_INET6, string)) != NULL)
+       {
+               node = patricia_search_exact(tree, prefix);
+               Deref_Prefix(prefix);
+       }
+       else
+#endif
+               return NULL;
+       return node;
+}
diff --git a/src/reject.c b/src/reject.c
new file mode 100644 (file)
index 0000000..13d1d31
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd
+ *  reject.c: reject users with prejudice
+ *
+ *  Copyright (C) 2003 Aaron Sethman <androsyn@ratbox.org>
+ *  Copyright (C) 2003-2005 ircd-ratbox development 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: reject.c 849 2006-02-15 01:33:43Z jilles $
+ */
+
+#include "stdinc.h"
+#include "config.h"
+#include "patricia.h"
+#include "client.h"
+#include "s_conf.h"
+#include "event.h"
+#include "tools.h"
+#include "reject.h"
+#include "s_stats.h"
+#include "msg.h"
+
+static patricia_tree_t *reject_tree;
+dlink_list delay_exit;
+static dlink_list reject_list;
+
+struct reject_data
+{
+       dlink_node rnode;
+       time_t time;
+       unsigned int count;
+};
+
+static void
+reject_exit(void *unused)
+{
+       struct Client *client_p;
+       dlink_node *ptr, *ptr_next;
+
+       DLINK_FOREACH_SAFE(ptr, ptr_next, delay_exit.head)
+       {
+               client_p = ptr->data;
+               if(IsDead(client_p))
+                       continue;
+
+               /* this MUST be here, to prevent the possibility
+                * sendto_one() generates a write error, and then a client
+                * ends up on the dead_list and the abort_list --fl
+                *
+                * new disconnect notice stolen from ircu --nenolod
+                * no, this only happens when someone's IP has some
+                * ban on it and rejects them rather longer than the
+                * ircu message suggests --jilles
+                */
+               if(!IsIOError(client_p))
+                       sendto_one(client_p, "ERROR :Closing Link: %s (*** Banned (cache))", client_p->host);
+
+               close_connection(client_p);
+               SetDead(client_p);
+               dlinkAddAlloc(client_p, &dead_list);
+       }
+
+        delay_exit.head = delay_exit.tail = NULL;
+        delay_exit.length = 0;
+}
+
+static void
+reject_expires(void *unused)
+{
+       dlink_node *ptr, *next;
+       patricia_node_t *pnode;
+       struct reject_data *rdata;
+       
+       DLINK_FOREACH_SAFE(ptr, next, reject_list.head)
+       {
+               pnode = ptr->data;
+               rdata = pnode->data;            
+
+               if(rdata->time + ConfigFileEntry.reject_duration > CurrentTime)
+                       continue;
+
+               dlinkDelete(ptr, &reject_list);
+               MyFree(rdata);
+               patricia_remove(reject_tree, pnode);
+       }
+}
+
+void
+init_reject(void)
+{
+       reject_tree = New_Patricia(PATRICIA_BITS);
+       eventAdd("reject_exit", reject_exit, NULL, DELAYED_EXIT_TIME);
+       eventAdd("reject_expires", reject_expires, NULL, 60);
+}
+
+
+void
+add_reject(struct Client *client_p)
+{
+       patricia_node_t *pnode;
+       struct reject_data *rdata;
+
+       /* Reject is disabled */
+       if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_ban_time == 0)
+               return;
+
+       if((pnode = match_ip(reject_tree, (struct sockaddr *)&client_p->localClient->ip)) != NULL)
+       {
+               rdata = pnode->data;
+               rdata->time = CurrentTime;
+               rdata->count++;
+       }
+       else
+       {
+               int bitlen = 32;
+#ifdef IPV6
+               if(client_p->localClient->ip.ss_family == AF_INET6)
+                       bitlen = 128;
+#endif
+               pnode = make_and_lookup_ip(reject_tree, (struct sockaddr *)&client_p->localClient->ip, bitlen);
+               pnode->data = rdata = MyMalloc(sizeof(struct reject_data));
+               dlinkAddTail(pnode, &rdata->rnode, &reject_list);
+               rdata->time = CurrentTime;
+               rdata->count = 1;
+       }
+}
+
+int
+check_reject(struct Client *client_p)
+{
+       patricia_node_t *pnode;
+       struct reject_data *rdata;
+       
+       /* Reject is disabled */
+       if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_ban_time == 0 ||
+          ConfigFileEntry.reject_duration == 0)
+               return 0;
+               
+       pnode = match_ip(reject_tree, (struct sockaddr *)&client_p->localClient->ip);
+       if(pnode != NULL)
+       {
+               rdata = pnode->data;
+
+               rdata->time = CurrentTime;
+               if(rdata->count > ConfigFileEntry.reject_after_count)
+               {
+                       ServerStats->is_rej++;
+                       SetReject(client_p);
+                       comm_setselect(client_p->localClient->fd, FDLIST_NONE, COMM_SELECT_WRITE | COMM_SELECT_READ, NULL, NULL, 0);
+                       SetClosing(client_p);
+                       dlinkMoveNode(&client_p->localClient->tnode, &unknown_list, &delay_exit);
+                       return 1;
+               }
+       }       
+       /* Caller does what it wants */ 
+       return 0;
+}
+
+void 
+flush_reject(void)
+{
+       dlink_node *ptr, *next;
+       patricia_node_t *pnode;
+       struct reject_data *rdata;
+       
+       DLINK_FOREACH_SAFE(ptr, next, reject_list.head)
+       {
+               pnode = ptr->data;
+               rdata = pnode->data;
+               dlinkDelete(ptr, &reject_list);
+               MyFree(rdata);
+               patricia_remove(reject_tree, pnode);
+       }
+}
+
+int 
+remove_reject(const char *ip)
+{
+       patricia_node_t *pnode;
+       
+       /* Reject is disabled */
+       if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_ban_time == 0 ||
+          ConfigFileEntry.reject_duration == 0)
+               return -1;
+
+       if((pnode = match_string(reject_tree, ip)) != NULL)
+       {
+               struct reject_data *rdata = pnode->data;
+               dlinkDelete(&rdata->rnode, &reject_list);
+               MyFree(rdata);
+               patricia_remove(reject_tree, pnode);
+               return 1;
+       }
+       return 0;
+}
+
diff --git a/src/res.c b/src/res.c
new file mode 100644 (file)
index 0000000..88170f0
--- /dev/null
+++ b/src/res.c
@@ -0,0 +1,874 @@
+/*
+ * A rewrite of Darren Reeds original res.c As there is nothing
+ * left of Darrens 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.
+ *
+ * $Id: res.c 2023 2006-09-02 23:47:27Z jilles $
+ * from Hybrid Id: res.c 459 2006-02-12 22:21:37Z db $
+ *
+ * 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
+ *
+ * DNS server flooding lessened, AAAA-or-A lookup removed, ip6.int support
+ * removed, various robustness fixes
+ *
+ * 2006 --jilles and nenolod
+ */
+
+#include "stdinc.h"
+#include "ircd_defs.h"
+#include "common.h"
+#include "ircd.h"
+#include "commio.h"
+#include "res.h"
+#include "reslib.h"
+#include "tools.h"
+#include "event.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "numeric.h"
+#include "client.h" /* SNO_* */
+
+#if (CHAR_BIT != 8)
+#error this code needs to be able to address individual octets
+#endif
+
+static PF res_readreply;
+
+#define MAXPACKET      1024    /* rfc sez 512 but we expand names so ... */
+#define RES_MAXALIASES 35      /* maximum aliases allowed */
+#define RES_MAXADDRS   35      /* maximum addresses allowed */
+#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.
+ */
+#define TYPE_SIZE         (size_t)2
+#define CLASS_SIZE        (size_t)2
+#define TTL_SIZE          (size_t)4
+#define RDLENGTH_SIZE     (size_t)2
+#define ANSWER_FIXED_SIZE (TYPE_SIZE + CLASS_SIZE + TTL_SIZE + RDLENGTH_SIZE)
+
+typedef enum
+{
+       REQ_IDLE,               /* We're doing not much at all */
+       REQ_PTR,                /* Looking up a PTR */
+       REQ_A,                  /* Looking up an A or AAAA */
+       REQ_CNAME               /* We got a CNAME in response, we better get a real answer next */
+} request_state;
+
+struct reslist
+{
+       dlink_node node;
+       int id;
+       int sent;               /* number of requests sent */
+       request_state state;    /* State the resolver machine is in */
+       time_t ttl;
+       char type;
+       char queryname[128];    /* name currently being queried */
+       char retries;           /* retry counter */
+       char sends;             /* number of sends (>1 means resent) */
+       char resend;            /* send flag. 0 == dont resend */
+       time_t sentat;
+       time_t timeout;
+       struct irc_sockaddr_storage addr;
+       char *name;
+       struct DNSQuery *query; /* query callback for this request */
+};
+
+static int res_fd;
+static dlink_list request_list = { NULL, NULL, 0 };
+
+static void rem_request(struct reslist *request);
+static struct reslist *make_request(struct DNSQuery *query);
+static void do_query_name(struct DNSQuery *query, const char *name, struct reslist *request, int);
+static void do_query_number(struct DNSQuery *query, const struct irc_sockaddr_storage *,
+                           struct reslist *request);
+static void query_name(struct reslist *request);
+static int send_res_msg(const char *buf, int len, int count);
+static void resend_query(struct reslist *request);
+static int check_question(struct reslist *request, HEADER * header, char *buf, char *eob);
+static int proc_answer(struct reslist *request, HEADER * header, char *, char *);
+static struct reslist *find_id(int id);
+static struct DNSReply *make_dnsreply(struct reslist *request);
+
+extern struct irc_sockaddr_storage irc_nsaddr_list[IRCD_MAXNS];
+extern int irc_nscount;
+extern char irc_domain[HOSTLEN + 1];
+
+
+/*
+ * int
+ * res_ourserver(inp)
+ *      looks up "inp" in irc_nsaddr_list[]
+ * returns:
+ *      0  : not found
+ *      >0 : found
+ * author:
+ *      paul vixie, 29may94
+ *      revised for ircd, cryogen(stu) may03
+ */
+static int res_ourserver(const struct irc_sockaddr_storage *inp)
+{
+#ifdef IPV6
+       struct sockaddr_in6 *v6;
+       struct sockaddr_in6 *v6in = (struct sockaddr_in6 *)inp;
+#endif
+       struct sockaddr_in *v4;
+       struct sockaddr_in *v4in = (struct sockaddr_in *)inp;
+       int ns;
+
+       for (ns = 0; ns < irc_nscount; ns++)
+       {
+               const struct irc_sockaddr_storage *srv = &irc_nsaddr_list[ns];
+#ifdef IPV6
+               v6 = (struct sockaddr_in6 *)srv;
+#endif
+               v4 = (struct sockaddr_in *)srv;
+
+               /* could probably just memcmp(srv, inp, srv.ss_len) here
+                * but we'll air on the side of caution - stu
+                */
+               switch (srv->ss_family)
+               {
+#ifdef IPV6
+                 case AF_INET6:
+                         if (srv->ss_family == inp->ss_family)
+                                 if (v6->sin6_port == v6in->sin6_port)
+                                         if ((memcmp(&v6->sin6_addr.s6_addr, &v6in->sin6_addr.s6_addr,
+                                               sizeof(struct in6_addr)) == 0) ||
+                                             (memcmp(&v6->sin6_addr.s6_addr, &in6addr_any,
+                                               sizeof(struct in6_addr)) == 0))
+                                                 return 1;
+                         break;
+#endif
+                 case AF_INET:
+                         if (srv->ss_family == inp->ss_family)
+                                 if (v4->sin_port == v4in->sin_port)
+                                         if ((v4->sin_addr.s_addr == INADDR_ANY)
+                                             || (v4->sin_addr.s_addr == v4in->sin_addr.s_addr))
+                                                 return 1;
+                         break;
+                 default:
+                         break;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * timeout_query_list - Remove queries from the list which have been 
+ * there too long without being resolved.
+ */
+static time_t timeout_query_list(time_t now)
+{
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+       struct reslist *request;
+       time_t next_time = 0;
+       time_t timeout = 0;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, request_list.head)
+       {
+               request = ptr->data;
+               timeout = request->sentat + request->timeout;
+
+               if (now >= timeout)
+               {
+                       if (--request->retries <= 0)
+                       {
+                               (*request->query->callback) (request->query->ptr, NULL);
+                               rem_request(request);
+                               continue;
+                       }
+                       else
+                       {
+                               request->sentat = now;
+                               request->timeout += request->timeout;
+                               resend_query(request);
+                       }
+               }
+
+               if ((next_time == 0) || timeout < next_time)
+               {
+                       next_time = timeout;
+               }
+       }
+
+       return (next_time > now) ? next_time : (now + AR_TTL);
+}
+
+/*
+ * timeout_resolver - check request list
+ */
+static void timeout_resolver(void *notused)
+{
+       timeout_query_list(CurrentTime);
+}
+
+/*
+ * start_resolver - do everything we need to read the resolv.conf file
+ * and initialize the resolver file descriptor if needed
+ */
+static void start_resolver(void)
+{
+       irc_res_init();
+
+       if (res_fd <= 0)        /* there isn't any such thing as fd 0, that's just a myth. */
+       {
+               if ((res_fd = comm_socket(irc_nsaddr_list[0].ss_family, SOCK_DGRAM, 0,
+                              "UDP resolver socket")) == -1)
+                       return;
+
+               /* At the moment, the resolver FD data is global .. */
+               comm_setselect(res_fd, FDLIST_NONE, COMM_SELECT_READ, res_readreply, NULL, 0);
+               eventAdd("timeout_resolver", timeout_resolver, NULL, 1);
+       }
+}
+
+/*
+ * init_resolver - initialize resolver and resolver library
+ */
+void init_resolver(void)
+{
+#ifdef HAVE_SRAND48
+       srand48(CurrentTime);
+#endif
+       start_resolver();
+}
+
+/*
+ * restart_resolver - reread resolv.conf, reopen socket
+ */
+void restart_resolver(void)
+{
+       comm_close(res_fd);
+       res_fd = -1;
+       eventDelete(timeout_resolver, NULL);    /* -ddosen */
+       start_resolver();
+}
+
+/*
+ * add_local_domain - Add the domain to hostname, if it is missing
+ * (as suggested by eps@TOASTER.SFSU.EDU)
+ */
+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);
+                       }
+               }
+       }
+}
+
+/*
+ * rem_request - remove a request from the list. 
+ * This must also free any memory that has been allocated for 
+ * temporary storage of DNS results.
+ */
+static void rem_request(struct reslist *request)
+{
+       dlinkDelete(&request->node, &request_list);
+       MyFree(request->name);
+       MyFree(request);
+}
+
+/*
+ * make_request - Create a DNS request record for the server.
+ */
+static struct reslist *make_request(struct DNSQuery *query)
+{
+       struct reslist *request = MyMalloc(sizeof(struct reslist));
+
+       request->sentat = CurrentTime;
+       request->retries = 3;
+       request->resend = 1;
+       request->timeout = 4;   /* start at 4 and exponential inc. */
+       request->query = query;
+       request->state = REQ_IDLE;
+
+       dlinkAdd(request, &request->node, &request_list);
+
+       return request;
+}
+
+/*
+ * delete_resolver_queries - cleanup outstanding queries 
+ * for which there no longer exist clients or conf lines.
+ */
+void delete_resolver_queries(const struct DNSQuery *query)
+{
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+       struct reslist *request;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, request_list.head)
+       {
+               if ((request = ptr->data) != NULL)
+               {
+                       if (query == request->query)
+                               rem_request(request);
+               }
+       }
+}
+
+/*
+ * send_res_msg - sends msg to all nameservers found in the "_res" structure.
+ * This should reflect /etc/resolv.conf. We will get responses
+ * which arent needed but is easier than checking to see if nameserver
+ * isnt present. Returns number of messages successfully sent to 
+ * nameservers or -1 if no successful sends.
+ */
+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++)
+       {
+               if (sendto(res_fd, msg, len, 0,
+                    (struct sockaddr *)&(irc_nsaddr_list[i]), 
+                               GET_SS_LEN(irc_nsaddr_list[i])) == len)
+                       ++sent;
+       }
+
+       return (sent);
+}
+
+/*
+ * find_id - find a dns request id (id is determined by dn_mkquery)
+ */
+static struct reslist *find_id(int id)
+{
+       dlink_node *ptr;
+       struct reslist *request;
+
+       DLINK_FOREACH(ptr, request_list.head)
+       {
+               request = ptr->data;
+
+               if (request->id == id)
+                       return (request);
+       }
+
+       return (NULL);
+}
+
+/* 
+ * gethost_byname_type - get host address from name
+ *
+ */
+void gethost_byname_type(const char *name, struct DNSQuery *query, int type)
+{
+       assert(name != 0);
+       do_query_name(query, name, NULL, type);
+}
+
+/*
+ * gethost_byaddr - get host name from address
+ */
+void gethost_byaddr(const struct irc_sockaddr_storage *addr, struct DNSQuery *query)
+{
+       do_query_number(query, addr, NULL);
+}
+
+/*
+ * do_query_name - nameserver lookup name
+ */
+static void do_query_name(struct DNSQuery *query, const char *name, struct reslist *request,
+                         int type)
+{
+       char host_name[HOSTLEN + 1];
+
+       strlcpy(host_name, name, HOSTLEN);
+       add_local_domain(host_name, HOSTLEN);
+
+       if (request == NULL)
+       {
+               request = make_request(query);
+               request->name = (char *)MyMalloc(strlen(host_name) + 1);
+               strcpy(request->name, host_name);
+               request->state = REQ_A;
+       }
+
+       strlcpy(request->queryname, host_name, sizeof(request->queryname));
+       request->type = type;
+       query_name(request);
+}
+
+/*
+ * do_query_number - Use this to do reverse IP# lookups.
+ */
+static void do_query_number(struct DNSQuery *query, const struct irc_sockaddr_storage *addr,
+                           struct reslist *request)
+{
+       const unsigned char *cp;
+
+       if (request == NULL)
+       {
+               request = make_request(query);
+               memcpy(&request->addr, addr, sizeof(struct irc_sockaddr_storage));
+               request->name = (char *)MyMalloc(HOSTLEN + 1);
+       }
+
+       if (addr->ss_family == AF_INET)
+       {
+               struct sockaddr_in *v4 = (struct sockaddr_in *)addr;
+               cp = (const unsigned char *)&v4->sin_addr.s_addr;
+
+               ircsprintf(request->queryname, "%u.%u.%u.%u.in-addr.arpa", (unsigned int)(cp[3]),
+                          (unsigned int)(cp[2]), (unsigned int)(cp[1]), (unsigned int)(cp[0]));
+       }
+#ifdef IPV6
+       else if (addr->ss_family == AF_INET6)
+       {
+               struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)addr;
+               cp = (const unsigned char *)&v6->sin6_addr.s6_addr;
+
+               (void)sprintf(request->queryname, "%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.arpa",
+                             (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));
+       }
+#endif
+
+       request->type = T_PTR;
+       query_name(request);
+}
+
+/*
+ * query_name - generate a query based on class, type and name.
+ */
+static void query_name(struct reslist *request)
+{
+       char buf[MAXPACKET];
+       int request_len = 0;
+
+       memset(buf, 0, sizeof(buf));
+
+       if ((request_len =
+            irc_res_mkquery(request->queryname, C_IN, request->type, (unsigned char *)buf, sizeof(buf))) > 0)
+       {
+               HEADER *header = (HEADER *) buf;
+#ifndef HAVE_LRAND48
+               int k = 0;
+               struct timeval tv;
+#endif
+               /*
+                * 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
+                */
+#ifdef HAVE_LRAND48
+               do
+               {
+                       header->id = (header->id + lrand48()) & 0xffff;
+               } while (find_id(header->id));
+#else
+               gettimeofday(&tv, NULL);
+               do
+               {
+                       header->id = (header->id + k + tv.tv_usec) & 0xffff;
+                       k++;
+               } while (find_id(header->id));
+#endif /* HAVE_LRAND48 */
+               request->id = header->id;
+               ++request->sends;
+
+               request->sent += send_res_msg(buf, request_len, request->sends);
+       }
+}
+
+static void resend_query(struct reslist *request)
+{
+       if (request->resend == 0)
+               return;
+
+       switch (request->type)
+       {
+         case T_PTR:
+                 do_query_number(NULL, &request->addr, request);
+                 break;
+         case T_A:
+#ifdef IPV6
+         case T_AAAA:
+#endif
+                 do_query_name(NULL, request->name, request, request->type);
+                 break;
+         default:
+                 break;
+       }
+}
+
+/*
+ * check_question - check if the reply really belongs to the
+ * name we queried (to guard against late replies from previous
+ * queries with the same id).
+ */
+static int check_question(struct reslist *request, HEADER * header, char *buf, char *eob)
+{
+       char hostbuf[128];      /* working buffer */
+       unsigned char *current; /* current position in buf */
+       int n;                  /* temp count */
+
+       current = (unsigned char *)buf + sizeof(HEADER);
+       if (header->qdcount != 1)
+               return 0;
+       n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob, current, hostbuf,
+                         sizeof(hostbuf));
+       if (n <= 0)
+               return 0;
+       if (strcasecmp(hostbuf, request->queryname))
+               return 0;
+       return 1;
+}
+
+/*
+ * proc_answer - process name server reply
+ */
+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;
+       struct sockaddr_in *v4; /* conversion */
+#ifdef IPV6
+       struct sockaddr_in6 *v6;
+#endif
+       current = (unsigned char *)buf + sizeof(HEADER);
+
+       for (; header->qdcount > 0; --header->qdcount)
+       {
+               if ((n = irc_dn_skipname(current, (unsigned char *)eob)) < 0)
+                       return 0;
+
+               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;
+
+               request->ttl = irc_ns_get32(current);
+               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);
+                         v4 = (struct sockaddr_in *)&request->addr;
+                         SET_SS_LEN(request->addr, sizeof(struct sockaddr_in));
+                         v4->sin_family = AF_INET;
+                         memcpy(&v4->sin_addr, current, sizeof(struct in_addr));
+                         return (1);
+                         break;
+#ifdef IPV6
+                 case T_AAAA:
+                         if (request->type != T_AAAA)
+                                 return (0);
+                         if (rd_length != sizeof(struct in6_addr))
+                                 return (0);
+                         SET_SS_LEN(request->addr, sizeof(struct sockaddr_in6));
+                         v6 = (struct sockaddr_in6 *)&request->addr;
+                         v6->sin6_family = AF_INET6;
+                         memcpy(&v6->sin6_addr, current, sizeof(struct in6_addr));
+                         return (1);
+                         break;
+#endif
+                 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 */
+
+                         strlcpy(request->name, hostbuf, HOSTLEN);
+
+                         return (1);
+                         break;
+                 case T_CNAME: /* first check we already havent started looking 
+                                          into a cname */
+                         if (request->type != T_PTR)
+                                 return (0);
+
+                         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...
+                          */
+                         ilog(L_MAIN, "irc_res.c bogus type %d", type);
+                         break;
+               }
+       }
+
+       return (1);
+}
+
+/*
+ * res_readreply - read a dns reply from the nameserver and process it.
+ */
+static void res_readreply(int fd, void *data)
+{
+       char buf[sizeof(HEADER) + MAXPACKET]
+               /* Sparc and alpha need 16bit-alignment for accessing header->id 
+                * (which is uint16_t). Because of the header = (HEADER*) buf; 
+                * lateron, this is neeeded. --FaUl
+                */
+#if defined(__sparc__) || defined(__alpha__)
+               __attribute__ ((aligned(16)))
+#endif
+               ;
+       HEADER *header;
+       struct reslist *request = NULL;
+       struct DNSReply *reply = NULL;
+       int rc;
+       int answer_count;
+       socklen_t len = sizeof(struct irc_sockaddr_storage);
+       struct irc_sockaddr_storage lsin;
+
+       rc = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&lsin, &len);
+
+       /* Re-schedule a read *after* recvfrom, or we'll be registering
+        * interest where it'll instantly be ready for read :-) -- adrian
+        */
+       comm_setselect(fd, FDLIST_NONE, COMM_SELECT_READ, res_readreply, NULL, 0);
+       /* Better to cast the sizeof instead of rc */
+       if (rc <= (int)(sizeof(HEADER)))
+               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;
+
+       /*
+        * check against possibly fake replies
+        */
+       if (!res_ourserver(&lsin))
+               return;
+
+       if (!check_question(request, header, buf, buf + rc))
+               return;
+
+       if ((header->rcode != NO_ERRORS) || (header->ancount == 0))
+       {
+               if (NXDOMAIN == header->rcode)
+               {
+                       (*request->query->callback) (request->query->ptr, NULL);
+                       rem_request(request);
+               }
+               else
+               {
+                       /*
+                        * If a bad error was returned, we stop here and dont send
+                        * send any more (no retries granted).
+                        */
+                       (*request->query->callback) (request->query->ptr, NULL);
+                       rem_request(request);
+               }
+               return;
+       }
+       /*
+        * If this fails there was an error decoding the received packet, 
+        * give up. -- jilles
+        */
+       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
+                                */
+                               (*request->query->callback) (request->query->ptr, reply);
+                               rem_request(request);
+                               return;
+                       }
+
+                       /*
+                        * Lookup the 'authoritative' name that we were given for the
+                        * ip#. 
+                        *
+                        */
+#ifdef IPV6
+                       if (request->addr.ss_family == AF_INET6)
+                               gethost_byname_type(request->name, request->query, T_AAAA);
+                       else
+#endif
+                               gethost_byname_type(request->name, request->query, T_A);
+                       rem_request(request);
+               }
+               else
+               {
+                       /*
+                        * got a name and address response, client resolved
+                        */
+                       reply = make_dnsreply(request);
+                       (*request->query->callback) (request->query->ptr, reply);
+                       MyFree(reply);
+                       rem_request(request);
+               }
+       }
+       else
+       {
+               /* couldn't decode, give up -- jilles */
+               (*request->query->callback) (request->query->ptr, NULL);
+               rem_request(request);
+       }
+}
+
+static struct DNSReply *make_dnsreply(struct reslist *request)
+{
+       struct DNSReply *cp;
+       s_assert(request != 0);
+
+       cp = (struct DNSReply *)MyMalloc(sizeof(struct DNSReply));
+
+       cp->h_name = request->name;
+       memcpy(&cp->addr, &request->addr, sizeof(cp->addr));
+       return (cp);
+}
+
+void report_dns_servers(struct Client *source_p)
+{
+       int i;
+       char ipaddr[128];
+
+       for (i = 0; i < irc_nscount; i++)
+       {
+               if (!inetntop_sock((struct sockaddr *)&(irc_nsaddr_list[i]),
+                               ipaddr, sizeof ipaddr))
+                       strlcpy(ipaddr, "?", sizeof ipaddr);
+               sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                               "A %s", ipaddr);
+       }
+}
diff --git a/src/reslib.c b/src/reslib.c
new file mode 100644 (file)
index 0000000..dcc7450
--- /dev/null
@@ -0,0 +1,1185 @@
+/*
+ * 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 orginal files
+ * in bind ...
+ *
+ * res_comp.c
+ * ns_name.c
+ * ns_netint.c
+ * res_init.c
+ * 
+ * - Dianora
+ */
+
+#include "stdinc.h"
+#include "ircd_defs.h"
+#include "common.h"
+#include "ircd.h"
+#include "commio.h"
+#include "res.h"
+#include "reslib.h"
+#include "tools.h"
+#include "event.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+
+#define NS_TYPE_ELT             0x40 /* EDNS0 extended label type */
+#define DNS_LABELTYPE_BITSTRING 0x41
+#define MAXLINE 128
+
+/* $Id: reslib.c 1695 2006-06-27 15:11:23Z jilles $ */
+/* from Hybrid Id: reslib.c 177 2005-10-22 09:05:05Z michael $ */
+
+struct irc_sockaddr_storage irc_nsaddr_list[IRCD_MAXNS];
+int irc_nscount = 0;
+char irc_domain[HOSTLEN + 1];
+
+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);
+static void add_nameserver(const char *);
+
+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 irc_ns_name_uncompress(const unsigned char *, const unsigned char *,
+                                  const unsigned char *, char *, size_t);
+static int irc_ns_name_unpack(const unsigned char *, const unsigned char *,
+                              const unsigned char *, unsigned char *,
+                              size_t);
+static int irc_ns_name_ntop(const char *, char *, size_t);
+static int irc_ns_name_skip(const unsigned char **, const unsigned char *);
+static int mklower(int ch);
+  
+int
+irc_res_init(void)
+{
+  irc_nscount = 0;
+  return parse_resvconf();
+}
+
+/* parse_resvconf()
+ *
+ * inputs - NONE
+ * output - -1 if failure 0 if success
+ * side effects - fills in irc_nsaddr_list
+ */
+static int
+parse_resvconf(void)
+{
+  char *p;
+  char *opt;
+  char *arg;
+  char input[MAXLINE];
+  FILE *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 = fopen("/etc/resolv.conf", "r")) == NULL)
+    return -1;
+
+  while (fgets(input, sizeof(input), file) != NULL)
+  {
+    /* blow away any newline */
+    if ((p = strpbrk(input, "\r\n")) != NULL)
+      *p = '\0';
+
+    p = input;
+    /* skip until something thats not a space is seen */
+    while (IsSpace(*p))
+      p++;
+    /* if at this point, have a '\0' then continue */
+    if (*p == '\0')
+      continue;
+
+    /* Ignore comment lines immediately */
+    if (*p == '#' || *p == ';')
+      continue;
+
+    /* skip until a space is found */
+    opt = p;
+    while (!IsSpace(*p) && *p != '\0')
+      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 (irccmp(opt, "domain") == 0)
+      strlcpy(irc_domain, arg, sizeof(irc_domain));
+    else if (irccmp(opt, "nameserver") == 0)
+      add_nameserver(arg);
+  }
+
+  fclose(file);
+  return 0;
+}
+
+/* add_nameserver()
+ *
+ * input        - either an IPV4 address in dotted quad
+ *                or an IPV6 address in : format
+ * output       - NONE
+ * side effects - entry in irc_nsaddr_list is filled in as needed
+ */
+static void
+add_nameserver(const char *arg)
+{
+  struct addrinfo hints, *res;
+
+  /* Done max number of nameservers? */
+  if (irc_nscount >= IRCD_MAXNS)
+  {
+    ilog (L_MAIN, "Too many nameservers, ignoring %s", arg);
+    return;
+  }
+
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family   = PF_UNSPEC;
+  hints.ai_socktype = SOCK_DGRAM;
+  hints.ai_flags    = AI_PASSIVE | AI_NUMERICHOST;
+
+  if (getaddrinfo(arg, "domain", &hints, &res))
+    return;
+
+  if (res == NULL)
+    return;
+
+  memcpy(&irc_nsaddr_list[irc_nscount], res->ai_addr, res->ai_addrlen);
+  SET_SS_LEN(irc_nsaddr_list[irc_nscount], res->ai_addrlen);
+  irc_nscount++;
+  freeaddrinfo(res);
+}
+
+/*
+ * Expand compressed domain name 'comp_dn' to full domain name.
+ * 'msg' is a pointer to the begining of the message,
+ * 'eomorig' points to the first location after the message,
+ * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
+ * Return size of compressed name or -1 if there was an error.
+ */
+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);
+}
+
+/*
+ * irc_ns_name_uncompress(msg, eom, src, dst, dstsiz)
+ *     Expand compressed domain name to presentation format.
+ * return:
+ *     Number of bytes read out of `src', or -1 (with errno set).
+ * note:
+ *     Root domain returns as "." not "".
+ */
+static 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, dst, dstsiz) == -1)
+    return(-1);
+  return(n);
+}
+/*
+ * irc_ns_name_unpack(msg, eom, src, dst, dstsiz)
+ *     Unpack a domain name from a message, source may be compressed.
+ * return:
+ *     -1 if it fails, or consumed octets if it succeeds.
+ */
+static 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);
+}
+
+/*
+ * irc_ns_name_ntop(src, dst, dstsiz)
+ *     Convert an encoded domain name to printable ascii as per RFC1035.
+ * return:
+ *     Number of bytes written to buffer, or -1 (with errno set)
+ * notes:
+ *     The root is returned as "."
+ *     All other domains are returned in non absolute form
+ */
+static 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((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 'exp_dn' in presentation form into 'comp_dn'.
+ * Return the size of the compressed name or -1.
+ * 'length' is the size of the array pointed to by 'comp_dn'.
+ */
+static 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. Return the size or -1.
+ */
+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);
+}
+
+/*
+ * ns_name_skip(ptrptr, eom)
+ *     Advance *ptrptr to skip over the compressed name it points at.
+ * return:
+ *     0 on success, -1 (with errno set) on failure.
+ */
+static 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);
+}
+
+unsigned int
+irc_ns_get16(const unsigned char *src)
+{
+  unsigned int dst;
+
+  IRC_NS_GET16(dst, src);
+  return(dst);
+}
+
+unsigned long
+irc_ns_get32(const unsigned char *src)
+{
+  unsigned long dst;
+
+  IRC_NS_GET32(dst, src);
+  return(dst);
+}
+
+void
+irc_ns_put16(unsigned int src, unsigned char *dst)
+{
+  IRC_NS_PUT16(src, dst);
+}
+
+void
+irc_ns_put32(unsigned long src, unsigned char *dst)
+{
+  IRC_NS_PUT32(src, dst);
+}
+
+/* From ns_name.c */
+
+/*
+ * special(ch)
+ *      Thinking in noninternationalized USASCII (per the DNS spec),
+ *      is this characted special ("in need of quoting") ?
+ * return:
+ *      boolean.
+ */
+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);
+  }
+}
+
+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); /* unknwon ELT */
+  }
+
+  return(l);
+}
+
+
+/*
+ * printable(ch)
+ *      Thinking in noninternationalized USASCII (per the DNS spec),
+ *      is this character visible and not a space when printed ?
+ * return:
+ *      boolean.
+ */
+static int
+printable(int ch)
+{
+  return(ch > 0x20 && ch < 0x7f);
+}
+
+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);
+}
+
+/*
+ * irc_ns_name_pton(src, dst, dstsiz)
+ *  Convert a ascii string into an encoded domain name as per RFC1035.
+ * return:
+ *  -1 if it fails
+ *  1 if string was fully qualified
+ *  0 is string was not fully qualified
+ * notes:
+ *  Enforces label and domain length limits.
+ */
+static 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);
+}
+
+/*
+ * irc_ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr)
+ *  Pack domain name 'domain' into 'comp_dn'.
+ * return:
+ *  Size of the compressed name, or -1.
+ * notes:
+ *  'dnptrs' is an array of pointers to previous compressed names.
+ *  dnptrs[0] is a pointer to the beginning of the message. The array
+ *  ends with NULL.
+ *  'lastdnptr' is a pointer to the end of the array pointed to
+ *  by 'dnptrs'.
+ * Side effects:
+ *  The list of pointers in dnptrs is updated for labels inserted into
+ *  the message as we compress the name.  If 'dnptr' is NULL, we don't
+ *  try to compress names. If 'lastdnptr' is NULL, we don't update the
+ *  list.
+ */
+static 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);
+}
+
+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));
+}
+
+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 begings 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);
+}
+
+/*
+ * dn_find(domain, msg, dnptrs, lastdnptr)
+ *  Search for the counted-label name in an array of compressed names.
+ * return:
+ *  offset from msg if found, or -1.
+ * notes:
+ *  dnptrs is the pointer to the first name on the list,
+ *  not the pointer to the start of the message.
+ */
+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);
+}
+
+/*
+ *  *  Thinking in noninternationalized USASCII (per the DNS spec),
+ *   *  convert this character to lower case if it's upper case.
+ *    */
+static int
+mklower(int ch) 
+{
+  if (ch >= 0x41 && ch <= 0x5A)
+    return(ch + 0x20);
+
+  return(ch);
+}
+
+/* From resolv/mkquery.c */
+
+/*
+ * Form all types of queries.
+ * Returns the size of the result or -1.
+ */
+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/src/restart.c b/src/restart.c
new file mode 100644 (file)
index 0000000..4ccfb76
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  restart.c: Functions to allow the ircd to restart.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: restart.c 486 2006-01-15 10:36:32Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "restart.h"
+#include "common.h"
+#include "ircd.h"
+#include "send.h"
+#include "s_log.h"
+#include "client.h"            /* for FLAGS_ALL */
+#include "memory.h"
+
+/* external var */
+extern char **myargv;
+
+void
+restart(const char *mesg)
+{
+       static int was_here = NO;       /* redundant due to restarting flag below */
+
+       if(was_here)
+               abort();
+       was_here = YES;
+
+       ilog(L_MAIN, "Restarting Server because: %s, memory data limit: %ld", mesg, get_maxrss());
+
+       server_reboot();
+}
+
+void
+server_reboot(void)
+{
+       int i;
+
+       sendto_realops_snomask(SNO_GENERAL, L_ALL, "Restarting server...");
+
+       ilog(L_MAIN, "Restarting server...");
+       /*
+        * XXX we used to call flush_connections() here. But since this routine
+        * doesn't exist anymore, we won't be flushing. This is ok, since 
+        * when close handlers come into existance, comm_close() will be called
+        * below, and the data flushing will be implicit.
+        *    -- adrian
+        *
+        * bah, for now, the program ain't coming back to here, so forcibly
+        * close everything the "wrong" way for now, and just LEAVE...
+        */
+       for (i = 0; i < MAXCONNECTIONS; ++i)
+               close(i);
+
+       unlink(pidFileName);
+       execv(SPATH, myargv);
+
+       exit(-1);
+}
diff --git a/src/s_auth.c b/src/s_auth.c
new file mode 100644 (file)
index 0000000..3494e5b
--- /dev/null
@@ -0,0 +1,618 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  s_auth.c: Functions for querying a users ident.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: s_auth.c 1683 2006-06-20 14:26:16Z jilles $ */
+
+/*
+ * 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>
+ */
+#include "stdinc.h"
+#include "config.h"
+#include "tools.h"
+#include "s_auth.h"
+#include "s_conf.h"
+#include "client.h"
+#include "common.h"
+#include "event.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "packet.h"
+#include "res.h"
+#include "commio.h"
+#include "s_log.h"
+#include "s_stats.h"
+#include "send.h"
+#include "memory.h"
+#include "hook.h"
+#include "blacklist.h"
+
+/*
+ * a bit different approach
+ * this replaces the original sendheader macros
+ */
+
+static const char *HeaderMessages[] =
+{
+       "NOTICE AUTH :*** Looking up your hostname...",
+       "NOTICE AUTH :*** Found your hostname",
+       "NOTICE AUTH :*** Couldn't look up your hostname",
+       "NOTICE AUTH :*** Checking Ident",
+       "NOTICE AUTH :*** Got Ident response",
+       "NOTICE AUTH :*** No Ident response",
+       "NOTICE AUTH :*** Your hostname is too long, ignoring hostname",
+       "NOTICE AUTH :*** Your forward and reverse DNS do not match, ignoring hostname",
+       "NOTICE AUTH :*** Cannot verify hostname validity, ignoring hostname",
+};
+
+typedef enum
+{
+       REPORT_DO_DNS,
+       REPORT_FIN_DNS,
+       REPORT_FAIL_DNS,
+       REPORT_DO_ID,
+       REPORT_FIN_ID,
+       REPORT_FAIL_ID,
+       REPORT_HOST_TOOLONG,
+       REPORT_HOST_MISMATCH,
+       REPORT_HOST_UNKNOWN
+}
+ReportType;
+
+#define sendheader(c, r) sendto_one(c, HeaderMessages[(r)]) 
+
+static dlink_list auth_poll_list;
+static BlockHeap *auth_heap;
+static EVH timeout_auth_queries_event;
+
+static PF read_auth_reply;
+static CNCB auth_connect_callback;
+
+/*
+ * init_auth()
+ *
+ * Initialise the auth code
+ */
+void
+init_auth(void)
+{
+       /* This hook takes a struct Client for its argument */
+       memset(&auth_poll_list, 0, sizeof(auth_poll_list));
+       eventAddIsh("timeout_auth_queries_event", timeout_auth_queries_event, NULL, 1);
+       auth_heap = BlockHeapCreate(sizeof(struct AuthRequest), LCLIENT_HEAP_SIZE);
+}
+
+/*
+ * make_auth_request - allocate a new auth request
+ */
+static struct AuthRequest *
+make_auth_request(struct Client *client)
+{
+       struct AuthRequest *request = BlockHeapAlloc(auth_heap);
+       client->localClient->auth_request = request;
+       request->fd = -1;
+       request->client = client;
+       request->timeout = CurrentTime + ConfigFileEntry.connect_timeout;
+       return request;
+}
+
+/*
+ * free_auth_request - cleanup auth request allocations
+ */
+static void
+free_auth_request(struct AuthRequest *request)
+{
+       BlockHeapFree(auth_heap, request);
+}
+
+/*
+ * release_auth_client - release auth client from auth system
+ * this adds the client into the local client lists so it can be read by
+ * the main io processing loop
+ */
+static void
+release_auth_client(struct AuthRequest *auth)
+{
+       struct Client *client = auth->client;
+       
+       if(IsDNSPending(auth) || IsDoingAuth(auth))
+               return;
+
+       client->localClient->auth_request = NULL;
+       dlinkDelete(&auth->node, &auth_poll_list);
+       free_auth_request(auth);        
+       if(client->localClient->fd > highest_fd)
+               highest_fd = client->localClient->fd;
+
+       /*
+        * When a client has auth'ed, we want to start reading what it sends
+        * us. This is what read_packet() does.
+        *     -- adrian
+        */
+       client->localClient->allow_read = MAX_FLOOD;
+       comm_setflush(client->localClient->fd, 1000, flood_recalc, client);
+       dlinkAddTail(client, &client->node, &global_client_list);
+       read_packet(client->localClient->fd, client);
+}
+
+/*
+ * auth_dns_callback - called when resolver query finishes
+ * if the query resulted in a successful search, hp will contain
+ * a non-null pointer, otherwise hp will be null.
+ * set the client on it's way to a connection completion, regardless
+ * of success of failure
+ */
+static void
+auth_dns_callback(void *vptr, struct DNSReply *reply)
+{
+        struct AuthRequest *auth = (struct AuthRequest *) vptr;
+        ClearDNSPending(auth);
+
+       /* XXX: this shouldn't happen, but it does. -nenolod */
+       if(auth->client->localClient == NULL)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                       "auth_dns_callback(): auth->client->localClient (%s) is NULL", get_client_name(auth->client, HIDE_IP));
+
+               dlinkDelete(&auth->node, &auth_poll_list);
+               free_auth_request(auth);
+
+               /* and they will silently drop through and all will hopefully be ok... -nenolod */
+               return;
+       }
+
+        if(reply)
+        {
+               int good = 1;
+
+               if(auth->client->localClient->ip.ss_family == AF_INET)
+               {
+                       struct sockaddr_in *ip, *ip_fwd;
+
+                       ip = (struct sockaddr_in *) &auth->client->localClient->ip;
+                       ip_fwd = (struct sockaddr_in *) &reply->addr;
+
+                       if(ip->sin_addr.s_addr != ip_fwd->sin_addr.s_addr)
+                       {
+                               sendheader(auth->client, REPORT_HOST_MISMATCH);
+                               good = 0;
+                       }
+               }
+#ifdef IPV6
+               else if(auth->client->localClient->ip.ss_family == AF_INET6)
+               {
+                       struct sockaddr_in6 *ip, *ip_fwd;
+
+                       ip = (struct sockaddr_in6 *) &auth->client->localClient->ip;
+                       ip_fwd = (struct sockaddr_in6 *) &reply->addr;
+
+                       if(memcmp(&ip->sin6_addr, &ip_fwd->sin6_addr, sizeof(struct in6_addr)) != 0)
+                       {
+                               sendheader(auth->client, REPORT_HOST_MISMATCH);
+                               good = 0;
+                       }
+               }
+#endif
+               else    /* can't verify it, don't know how. reject it. */
+               {
+                       sendheader(auth->client, REPORT_HOST_UNKNOWN);
+                       good = 0;
+               }
+
+                if(good && strlen(reply->h_name) <= HOSTLEN)
+                {
+                        strlcpy(auth->client->host, reply->h_name, sizeof(auth->client->host));
+                        sendheader(auth->client, REPORT_FIN_DNS);
+                }
+                else if (strlen(reply->h_name) > HOSTLEN)
+                        sendheader(auth->client, REPORT_HOST_TOOLONG);
+        }
+       else
+                sendheader(auth->client, REPORT_FAIL_DNS);
+
+        release_auth_client(auth);
+}
+
+/*
+ * authsenderr - handle auth send errors
+ */
+static void
+auth_error(struct AuthRequest *auth)
+{
+       ++ServerStats->is_abad;
+
+       comm_close(auth->fd);
+       auth->fd = -1;
+
+       ClearAuth(auth);
+       sendheader(auth->client, REPORT_FAIL_ID);
+               
+       release_auth_client(auth);
+}
+
+/*
+ * start_auth_query - Flag the client to show that an attempt to 
+ * contact the ident server on
+ * the client's host.  The connect and subsequently the socket are all put
+ * into 'non-blocking' mode.  Should the connect or any later phase of the
+ * identifing process fail, it is aborted and the user is given a username
+ * of "unknown".
+ */
+static int
+start_auth_query(struct AuthRequest *auth)
+{
+       struct irc_sockaddr_storage localaddr;
+       socklen_t locallen = sizeof(struct irc_sockaddr_storage);
+       int fd;
+       int family;
+       
+       if(IsAnyDead(auth->client))
+               return 0;
+       
+       family = auth->client->localClient->ip.ss_family;
+       if((fd = comm_socket(family, SOCK_STREAM, 0, "ident")) == -1)
+       {
+               report_error("creating auth stream socket %s:%s",
+                            get_client_name(auth->client, SHOW_IP), 
+                            log_client_name(auth->client, SHOW_IP), errno);
+               ++ServerStats->is_abad;
+               return 0;
+       }
+       if((MAXCONNECTIONS - 10) < fd)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Can't allocate fd for auth on %s",
+                                    get_client_name(auth->client, SHOW_IP));
+               comm_close(fd);
+               return 0;
+       }
+
+       sendheader(auth->client, REPORT_DO_ID);
+
+       /* 
+        * 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
+        */
+       memset(&localaddr, 0, locallen);
+       getsockname(auth->client->localClient->fd,
+                   (struct sockaddr *) &localaddr, &locallen);
+       
+       mangle_mapped_sockaddr((struct sockaddr *)&localaddr);
+#ifdef IPV6
+       if(localaddr.ss_family == AF_INET6)
+       {
+               ((struct sockaddr_in6 *)&localaddr)->sin6_port = 0;
+       } else
+#endif
+       ((struct sockaddr_in *)&localaddr)->sin_port = 0;
+       
+       auth->fd = fd;
+       SetAuthConnect(auth);
+
+       comm_connect_tcp(fd, auth->client->sockhost, 113,
+                        (struct sockaddr *) &localaddr, GET_SS_LEN(localaddr),
+                        auth_connect_callback, auth, 
+                        localaddr.ss_family, GlobalSetOptions.ident_timeout);
+       return 1;               /* We suceed here for now */
+}
+
+/*
+ * GetValidIdent - parse ident query reply from identd server
+ * 
+ * Inputs        - pointer to ident buf
+ * Output        - NULL if no valid ident found, otherwise pointer to name
+ * Side effects  -
+ */
+static char *
+GetValidIdent(char *buf)
+{
+       int remp = 0;
+       int locp = 0;
+       char *colon1Ptr;
+       char *colon2Ptr;
+       char *colon3Ptr;
+       char *commaPtr;
+       char *remotePortString;
+
+       /* All this to get rid of a sscanf() fun. */
+       remotePortString = buf;
+
+       colon1Ptr = strchr(remotePortString, ':');
+       if(!colon1Ptr)
+               return 0;
+
+       *colon1Ptr = '\0';
+       colon1Ptr++;
+       colon2Ptr = strchr(colon1Ptr, ':');
+       if(!colon2Ptr)
+               return 0;
+
+       *colon2Ptr = '\0';
+       colon2Ptr++;
+       commaPtr = strchr(remotePortString, ',');
+
+       if(!commaPtr)
+               return 0;
+
+       *commaPtr = '\0';
+       commaPtr++;
+
+       remp = atoi(remotePortString);
+       if(!remp)
+               return 0;
+
+       locp = atoi(commaPtr);
+       if(!locp)
+               return 0;
+
+       /* look for USERID bordered by first pair of colons */
+       if(!strstr(colon1Ptr, "USERID"))
+               return 0;
+
+       colon3Ptr = strchr(colon2Ptr, ':');
+       if(!colon3Ptr)
+               return 0;
+
+       *colon3Ptr = '\0';
+       colon3Ptr++;
+       return (colon3Ptr);
+}
+
+/*
+ * start_auth - starts auth (identd) and dns queries for a client
+ */
+void
+start_auth(struct Client *client)
+{
+       struct AuthRequest *auth = 0;
+       s_assert(0 != client);
+       if(client == NULL)
+               return;
+
+       /* to aid bopm which needs something unique to match against */
+       sendto_one(client, "NOTICE AUTH :*** Processing connection to %s",
+                       me.name);
+
+       auth = make_auth_request(client);
+
+       auth->dns_query.ptr = auth;
+       auth->dns_query.callback = auth_dns_callback;
+
+       sendheader(client, REPORT_DO_DNS);
+
+       /* No DNS cache now, remember? -- adrian */
+       gethost_byaddr(&client->localClient->ip, &auth->dns_query);
+
+       SetDNSPending(auth);
+
+       if(ConfigFileEntry.disable_auth == 0)
+               start_auth_query(auth);
+
+       dlinkAdd(auth, &auth->node, &auth_poll_list);
+}
+
+/*
+ * timeout_auth_queries - timeout resolver and identd requests
+ * allow clients through if requests failed
+ */
+static void
+timeout_auth_queries_event(void *notused)
+{
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+       struct AuthRequest *auth;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, auth_poll_list.head)
+       {
+               auth = ptr->data;
+
+               if(auth->timeout < CurrentTime)
+               {
+                       if(auth->fd >= 0)
+                               comm_close(auth->fd);
+
+                       if(IsDoingAuth(auth))
+                       {
+                               ClearAuth(auth);
+                               ++ServerStats->is_abad;
+                               sendheader(auth->client, REPORT_FAIL_ID);
+                               auth->client->localClient->auth_request = NULL;
+                       }
+                       if(IsDNSPending(auth))
+                       {
+                               ClearDNSPending(auth);
+                               delete_resolver_queries(&auth->dns_query);
+                               sendheader(auth->client, REPORT_FAIL_DNS);
+                       }
+
+                       auth->client->localClient->lasttime = CurrentTime;
+                       release_auth_client(auth);
+               }
+       }
+}
+
+/*
+ * auth_connect_callback() - deal with the result of comm_connect_tcp()
+ *
+ * If the connection failed, we simply close the auth fd and report
+ * a failure. If the connection suceeded 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 shouldnt be a problem since the socket should have
+ * a write buffer far greater than this message to store it in should
+ * problems arise. -avalon
+ */
+static void
+auth_connect_callback(int fd, int error, void *data)
+{
+       struct AuthRequest *auth = data;
+       struct sockaddr_in us;
+       struct sockaddr_in them;
+       char authbuf[32];
+       socklen_t ulen = sizeof(struct sockaddr_in);
+       socklen_t tlen = sizeof(struct sockaddr_in);
+
+       /* Check the error */
+       if(error != COMM_OK)
+       {
+               /* We had an error during connection :( */
+               auth_error(auth);
+               return;
+       }
+
+       if(getsockname
+          (auth->client->localClient->fd, (struct sockaddr *) &us,
+           (socklen_t *) & ulen)
+          || getpeername(auth->client->localClient->fd,
+                         (struct sockaddr *) &them, (socklen_t *) & tlen))
+       {
+               ilog(L_IOERROR, "auth get{sock,peer}name error for %s:%m",
+                    log_client_name(auth->client, SHOW_IP));
+               auth_error(auth);
+               return;
+       }
+       ircsnprintf(authbuf, sizeof(authbuf), "%u , %u\r\n",
+                  (unsigned int) ntohs(them.sin_port), (unsigned int) ntohs(us.sin_port));
+
+       if(write(auth->fd, authbuf, strlen(authbuf)) == -1)
+       {
+               auth_error(auth);
+               return;
+       }
+       ClearAuthConnect(auth);
+       SetAuthPending(auth);
+       read_auth_reply(auth->fd, auth);
+}
+
+
+/*
+ * read_auth_reply - 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
+ */
+#define AUTH_BUFSIZ 128
+
+static void
+read_auth_reply(int fd, void *data)
+{
+       struct AuthRequest *auth = data;
+       char *s = NULL;
+       char *t = NULL;
+       int len;
+       int count;
+       char buf[AUTH_BUFSIZ + 1];      /* buffer to read auth reply into */
+
+       len = read(auth->fd, buf, AUTH_BUFSIZ);
+
+       if(len < 0 && ignoreErrno(errno))
+       {
+               comm_setselect(fd, FDLIST_IDLECLIENT, COMM_SELECT_READ, read_auth_reply, auth, 0);
+               return;
+       }
+
+       if(len > 0)
+       {
+               buf[len] = '\0';
+
+               if((s = GetValidIdent(buf)))
+               {
+                       t = auth->client->username;
+
+                       while (*s == '~' || *s == '^')
+                               s++;
+
+                       for (count = USERLEN; *s && count; s++)
+                       {
+                               if(*s == '@')
+                               {
+                                       break;
+                               }
+                               if(!IsSpace(*s) && *s != ':' && *s != '[')
+                               {
+                                       *t++ = *s;
+                                       count--;
+                               }
+                       }
+                       *t = '\0';
+               }
+       }
+
+       comm_close(auth->fd);
+       auth->fd = -1;
+       ClearAuth(auth);
+
+       if(s == NULL)
+       {
+               ++ServerStats->is_abad;
+               strcpy(auth->client->username, "unknown");
+               sendheader(auth->client, REPORT_FAIL_ID);
+       }
+       else
+       {
+               sendheader(auth->client, REPORT_FIN_ID);
+               ++ServerStats->is_asuc;
+               SetGotId(auth->client);
+       }
+
+       release_auth_client(auth);
+}
+
+
+
+/*
+ * delete_auth_queries()
+ *
+ */
+void
+delete_auth_queries(struct Client *target_p)
+{
+       struct AuthRequest *auth;
+
+       if(target_p == NULL || target_p->localClient == NULL ||
+          target_p->localClient->auth_request == NULL)
+               return;
+       
+       auth = target_p->localClient->auth_request;
+       target_p->localClient->auth_request = NULL;
+
+       if(IsDNSPending(auth))
+               delete_resolver_queries(&auth->dns_query);
+
+       if(auth->fd >= 0)
+               comm_close(auth->fd);
+               
+       dlinkDelete(&auth->node, &auth_poll_list);
+       free_auth_request(auth);
+}
diff --git a/src/s_conf.c b/src/s_conf.c
new file mode 100644 (file)
index 0000000..6ca336a
--- /dev/null
@@ -0,0 +1,1552 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  s_conf.c: Configuration file functions.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: s_conf.c 3131 2007-01-21 15:36:31Z jilles $
+ */
+
+#include "stdinc.h"
+#include "ircd_defs.h"
+#include "tools.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "s_serv.h"
+#include "s_stats.h"
+#include "channel.h"
+#include "class.h"
+#include "client.h"
+#include "common.h"
+#include "event.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "listener.h"
+#include "hostmask.h"
+#include "modules.h"
+#include "numeric.h"
+#include "commio.h"
+#include "s_log.h"
+#include "send.h"
+#include "s_gline.h"
+#include "memory.h"
+#include "balloc.h"
+#include "patricia.h"
+#include "reject.h"
+#include "cache.h"
+#include "blacklist.h"
+
+struct config_server_hide ConfigServerHide;
+
+extern int yyparse();          /* defined in y.tab.c */
+extern char linebuf[];
+
+#ifndef INADDR_NONE
+#define INADDR_NONE ((unsigned int) 0xffffffff)
+#endif
+
+static BlockHeap *confitem_heap = NULL;
+
+dlink_list temp_klines[LAST_TEMP_TYPE];
+dlink_list temp_dlines[LAST_TEMP_TYPE];
+dlink_list service_list;
+
+/* internally defined functions */
+static void set_default_conf(void);
+static void validate_conf(void);
+static void read_conf(FILE *);
+static void clear_out_old_conf(void);
+
+static void expire_temp_kd(void *list);
+static void reorganise_temp_kd(void *list);
+
+FILE *conf_fbfile_in;
+extern char yytext[];
+
+static int verify_access(struct Client *client_p, const char *username);
+static int attach_iline(struct Client *, struct ConfItem *);
+
+void
+init_s_conf(void)
+{
+       confitem_heap = BlockHeapCreate(sizeof(struct ConfItem), CONFITEM_HEAP_SIZE);
+
+       eventAddIsh("expire_temp_klines", expire_temp_kd, &temp_klines[TEMP_MIN], 60);
+       eventAddIsh("expire_temp_dlines", expire_temp_kd, &temp_dlines[TEMP_MIN], 60);
+
+       eventAddIsh("expire_temp_klines_hour", reorganise_temp_kd,
+                       &temp_klines[TEMP_HOUR], 3600);
+       eventAddIsh("expire_temp_dlines_hour", reorganise_temp_kd,
+                       &temp_dlines[TEMP_HOUR], 3600);
+       eventAddIsh("expire_temp_klines_day", reorganise_temp_kd,
+                       &temp_klines[TEMP_DAY], 86400);
+       eventAddIsh("expire_temp_dlines_day", reorganise_temp_kd,
+                       &temp_dlines[TEMP_DAY], 86400);
+       eventAddIsh("expire_temp_klines_week", reorganise_temp_kd,
+                       &temp_klines[TEMP_WEEK], 604800);
+       eventAddIsh("expire_temp_dlines_week", reorganise_temp_kd,
+                       &temp_dlines[TEMP_WEEK], 604800);
+}
+
+/*
+ * make_conf
+ *
+ * inputs      - none
+ * output      - pointer to new conf entry
+ * side effects        - none
+ */
+struct ConfItem *
+make_conf()
+{
+       struct ConfItem *aconf;
+
+       aconf = BlockHeapAlloc(confitem_heap);
+       aconf->status = CONF_ILLEGAL;
+       return (aconf);
+}
+
+/*
+ * free_conf
+ *
+ * inputs      - pointer to conf to free
+ * output      - none
+ * side effects        - crucial password fields are zeroed, conf is freed
+ */
+void
+free_conf(struct ConfItem *aconf)
+{
+       s_assert(aconf != NULL);
+       if(aconf == NULL)
+               return;
+
+       /* security.. */
+       if(aconf->passwd)
+               memset(aconf->passwd, 0, strlen(aconf->passwd));
+       if(aconf->spasswd)
+               memset(aconf->spasswd, 0, strlen(aconf->spasswd));
+
+       MyFree(aconf->passwd);
+       MyFree(aconf->spasswd);
+       MyFree(aconf->name);
+       MyFree(aconf->className);
+       MyFree(aconf->user);
+       MyFree(aconf->host);
+
+       BlockHeapFree(confitem_heap, aconf);
+}
+
+/*
+ * check_client
+ *
+ * inputs      - pointer to client
+ * output      - 0 = Success
+ *               NOT_AUTHORISED (-1) = Access denied (no I line match)
+ *               SOCKET_ERROR   (-2) = Bad socket.
+ *               I_LINE_FULL    (-3) = I-line is full
+ *               TOO_MANY       (-4) = Too many connections from hostname
+ *               BANNED_CLIENT  (-5) = K-lined
+ * side effects - Ordinary client access check.
+ *               Look for conf lines which have the same
+ *               status as the flags passed.
+ */
+int
+check_client(struct Client *client_p, struct Client *source_p, const char *username)
+{
+       int i;
+
+       ClearAccess(source_p);
+
+       if((i = verify_access(source_p, username)))
+       {
+               ilog(L_FUSER, "Access denied: %s[%s]", 
+                    source_p->name, source_p->sockhost);
+       }
+       
+       switch (i)
+       {
+       case SOCKET_ERROR:
+               exit_client(client_p, source_p, &me, "Socket Error");
+               break;
+
+       case TOO_MANY_LOCAL:
+               sendto_realops_snomask(SNO_FULL, L_NETWIDE,
+                               "Too many local connections for %s!%s%s@%s",
+                               source_p->name, IsGotId(source_p) ? "" : "~",
+                               source_p->username, source_p->sockhost);
+
+               ilog(L_FUSER, "Too many local connections from %s!%s%s@%s",
+                       source_p->name, IsGotId(source_p) ? "" : "~",
+                       source_p->username, source_p->sockhost);        
+
+               ServerStats->is_ref++;
+               exit_client(client_p, source_p, &me, "Too many host connections (local)");
+               break;
+
+       case TOO_MANY_GLOBAL:
+               sendto_realops_snomask(SNO_FULL, L_NETWIDE,
+                               "Too many global connections for %s!%s%s@%s",
+                               source_p->name, IsGotId(source_p) ? "" : "~",
+                               source_p->username, source_p->sockhost);
+               ilog(L_FUSER, "Too many global connections from %s!%s%s@%s",
+                       source_p->name, IsGotId(source_p) ? "" : "~",
+                       source_p->username, source_p->sockhost);
+
+               ServerStats->is_ref++;
+               exit_client(client_p, source_p, &me, "Too many host connections (global)");
+               break;
+
+       case TOO_MANY_IDENT:
+               sendto_realops_snomask(SNO_FULL, L_NETWIDE,
+                               "Too many user connections for %s!%s%s@%s",
+                               source_p->name, IsGotId(source_p) ? "" : "~",
+                               source_p->username, source_p->sockhost);
+               ilog(L_FUSER, "Too many user connections from %s!%s%s@%s",
+                       source_p->name, IsGotId(source_p) ? "" : "~",
+                       source_p->username, source_p->sockhost);
+
+               ServerStats->is_ref++;
+               exit_client(client_p, source_p, &me, "Too many user connections (global)");
+               break;
+
+       case I_LINE_FULL:
+               sendto_realops_snomask(SNO_FULL, L_NETWIDE,
+                               "I-line is full for %s!%s%s@%s (%s).",
+                               source_p->name, IsGotId(source_p) ? "" : "~",
+                               source_p->username, source_p->host,
+                               source_p->sockhost);
+
+               ilog(L_FUSER, "Too many connections from %s!%s%s@%s.", 
+                       source_p->name, IsGotId(source_p) ? "" : "~",
+                       source_p->username, source_p->sockhost);
+
+               ServerStats->is_ref++;
+               exit_client(client_p, source_p, &me,
+                           "No more connections allowed in your connection class");
+               break;
+
+       case NOT_AUTHORISED:
+               {
+                       int port = -1;
+#ifdef IPV6
+                       if(source_p->localClient->ip.ss_family == AF_INET6)
+                               port = ntohs(((struct sockaddr_in6 *)&source_p->localClient->listener->addr)->sin6_port);
+                       else
+#endif
+                               port = ntohs(((struct sockaddr_in *)&source_p->localClient->listener->addr)->sin_port);
+                       
+                       ServerStats->is_ref++;
+                       /* jdc - lists server name & port connections are on */
+                       /*       a purely cosmetical change */
+                       /* why ipaddr, and not just source_p->sockhost? --fl */
+#if 0
+                       static char ipaddr[HOSTIPLEN];
+                       inetntop_sock(&source_p->localClient->ip, ipaddr, sizeof(ipaddr));
+#endif
+                       sendto_realops_snomask(SNO_UNAUTH, L_ALL,
+                                       "Unauthorised client connection from "
+                                       "%s!%s%s@%s [%s] on [%s/%u].",
+                                       source_p->name, IsGotId(source_p) ? "" : "~",
+                                       source_p->username, source_p->host,
+                                       source_p->sockhost,
+                                       source_p->localClient->listener->name, port);
+
+                       ilog(L_FUSER,
+                               "Unauthorised client connection from %s!%s%s@%s on [%s/%u].",
+                               source_p->name, IsGotId(source_p) ? "" : "~",
+                               source_p->username, source_p->sockhost,
+                               source_p->localClient->listener->name, port);
+                       add_reject(client_p);
+                       exit_client(client_p, source_p, &me,
+                                   "You are not authorised to use this server");
+                       break;
+               }
+       case BANNED_CLIENT:
+               add_reject(client_p);
+               exit_client(client_p, client_p, &me, "*** Banned ");
+               ServerStats->is_ref++;
+               break;
+
+       case 0:
+       default:
+               break;
+       }
+       return (i);
+}
+
+/*
+ * verify_access
+ *
+ * inputs      - pointer to client to verify
+ *             - pointer to proposed username
+ * output      - 0 if success -'ve if not
+ * side effect - find the first (best) I line to attach.
+ */
+static int
+verify_access(struct Client *client_p, const char *username)
+{
+       struct ConfItem *aconf;
+       char non_ident[USERLEN + 1];
+
+       if(IsGotId(client_p))
+       {
+               aconf = find_address_conf(client_p->host, client_p->sockhost, 
+                                       client_p->username, client_p->username,
+                                       (struct sockaddr *) &client_p->localClient->ip,
+                                       client_p->localClient->ip.ss_family);
+       }
+       else
+       {
+               strlcpy(non_ident, "~", sizeof(non_ident));
+               strlcat(non_ident, username, sizeof(non_ident));
+               aconf = find_address_conf(client_p->host, client_p->sockhost,
+                                       non_ident, client_p->username,
+                                       (struct sockaddr *) &client_p->localClient->ip,
+                                       client_p->localClient->ip.ss_family);
+       }
+
+       if(aconf == NULL)
+               return NOT_AUTHORISED;
+
+       if(aconf->status & CONF_CLIENT)
+       {
+               if(aconf->flags & CONF_FLAGS_REDIR)
+               {
+                       sendto_one(client_p, form_str(RPL_REDIR),
+                                       me.name, client_p->name,
+                                       aconf->name ? aconf->name : "", aconf->port);
+                       return (NOT_AUTHORISED);
+               }
+
+
+               if(IsConfDoIdentd(aconf))
+                       SetNeedId(client_p);
+
+               /* Thanks for spoof idea amm */
+               if(IsConfDoSpoofIp(aconf))
+               {
+                       char *p;
+
+                       /* show_ip() depends on this --fl */
+                       SetIPSpoof(client_p);
+
+                       if(IsConfSpoofNotice(aconf))
+                       {
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                               "%s spoofing: %s as %s",
+                                               client_p->name,
+                                               show_ip(NULL, client_p) ? client_p->host : aconf->name,
+                                               aconf->name);
+                       }
+
+                       /* user@host spoof */
+                       if((p = strchr(aconf->name, '@')) != NULL)
+                       {
+                               char *host = p+1;
+                               *p = '\0';
+
+                               strlcpy(client_p->username, aconf->name,
+                                       sizeof(client_p->username));
+                               strlcpy(client_p->host, host,
+                                       sizeof(client_p->host));
+                               *p = '@';
+                       }
+                       else
+                               strlcpy(client_p->host, aconf->name, sizeof(client_p->host));
+               }
+               return (attach_iline(client_p, aconf));
+       }
+       else if(aconf->status & CONF_KILL)
+       {
+               if(ConfigFileEntry.kline_with_reason)
+               {
+                       sendto_one(client_p,
+                                       ":%s NOTICE %s :*** Banned %s",
+                                       me.name, client_p->name, aconf->passwd);
+               }
+               return (BANNED_CLIENT);
+       }
+       else if(aconf->status & CONF_GLINE)
+       {
+               sendto_one(client_p, ":%s NOTICE %s :*** G-lined", me.name, client_p->name);
+
+               if(ConfigFileEntry.kline_with_reason)
+                       sendto_one(client_p,
+                                       ":%s NOTICE %s :*** Banned %s",
+                                       me.name, client_p->name, aconf->passwd);
+
+               return (BANNED_CLIENT);
+       }
+
+       return NOT_AUTHORISED;
+}
+
+
+/*
+ * add_ip_limit
+ * 
+ * Returns 1 if successful 0 if not
+ *
+ * This checks if the user has exceed the limits for their class
+ * unless of course they are exempt..
+ */
+
+static int
+add_ip_limit(struct Client *client_p, struct ConfItem *aconf)
+{
+       patricia_node_t *pnode;
+
+       /* If the limits are 0 don't do anything.. */
+       if(ConfCidrAmount(aconf) == 0 || ConfCidrBitlen(aconf) == 0)
+               return -1;
+
+       pnode = match_ip(ConfIpLimits(aconf), (struct sockaddr *)&client_p->localClient->ip);
+
+       if(pnode == NULL)
+               pnode = make_and_lookup_ip(ConfIpLimits(aconf), (struct sockaddr *)&client_p->localClient->ip, ConfCidrBitlen(aconf));
+
+       s_assert(pnode != NULL);
+
+       if(pnode != NULL)
+       {
+               if(((long) pnode->data) >= ConfCidrAmount(aconf)
+                  && !IsConfExemptLimits(aconf))
+               {
+                       /* This should only happen if the limits are set to 0 */
+                       if((unsigned long) pnode->data == 0)
+                       {
+                               patricia_remove(ConfIpLimits(aconf), pnode);
+                       }
+                       return (0);
+               }
+
+               pnode->data++;
+       }
+       return 1;
+}
+
+static void
+remove_ip_limit(struct Client *client_p, struct ConfItem *aconf)
+{
+       patricia_node_t *pnode;
+
+       /* If the limits are 0 don't do anything.. */
+       if(ConfCidrAmount(aconf) == 0 || ConfCidrBitlen(aconf) == 0)
+               return;
+
+       pnode = match_ip(ConfIpLimits(aconf), (struct sockaddr *)&client_p->localClient->ip);
+       if(pnode == NULL)
+               return;
+
+       pnode->data--;
+       if(((unsigned long) pnode->data) == 0)
+       {
+               patricia_remove(ConfIpLimits(aconf), pnode);
+       }
+
+}
+
+/*
+ * attach_iline
+ *
+ * inputs      - client pointer
+ *             - conf pointer
+ * output      -
+ * side effects        - do actual attach
+ */
+static int
+attach_iline(struct Client *client_p, struct ConfItem *aconf)
+{
+       struct Client *target_p;
+       dlink_node *ptr;
+       int local_count = 0;
+       int global_count = 0;
+       int ident_count = 0;
+       int unidented = 0;
+
+       if(IsConfExemptLimits(aconf))
+               return (attach_conf(client_p, aconf));
+
+       if(*client_p->username == '~')
+               unidented = 1;
+
+
+       /* find_hostname() returns the head of the list to search */
+       DLINK_FOREACH(ptr, find_hostname(client_p->host))
+       {
+               target_p = ptr->data;
+
+               if(irccmp(client_p->host, target_p->orighost) != 0)
+                       continue;
+
+               if(MyConnect(target_p))
+                       local_count++;
+
+               global_count++;
+
+               if(unidented)
+               {
+                       if(*target_p->username == '~')
+                               ident_count++;
+               }
+               else if(irccmp(target_p->username, client_p->username) == 0)
+                       ident_count++;
+
+               if(ConfMaxLocal(aconf) && local_count >= ConfMaxLocal(aconf))
+                       return (TOO_MANY_LOCAL);
+               else if(ConfMaxGlobal(aconf) && global_count >= ConfMaxGlobal(aconf))
+                       return (TOO_MANY_GLOBAL);
+               else if(ConfMaxIdent(aconf) && ident_count >= ConfMaxIdent(aconf))
+                       return (TOO_MANY_IDENT);
+       }
+
+
+       return (attach_conf(client_p, aconf));
+}
+
+/*
+ * detach_conf
+ *
+ * inputs      - pointer to client to detach
+ * output      - 0 for success, -1 for failure
+ * side effects        - Disassociate configuration from the client.
+ *               Also removes a class from the list if marked for deleting.
+ */
+int
+detach_conf(struct Client *client_p)
+{
+       struct ConfItem *aconf;
+
+       aconf = client_p->localClient->att_conf;
+
+       if(aconf != NULL)
+       {
+               if(ClassPtr(aconf))
+               {
+                       remove_ip_limit(client_p, aconf);
+
+                       if(ConfCurrUsers(aconf) > 0)
+                               --ConfCurrUsers(aconf);
+
+                       if(ConfMaxUsers(aconf) == -1 && ConfCurrUsers(aconf) == 0)
+                       {
+                               free_class(ClassPtr(aconf));
+                               ClassPtr(aconf) = NULL;
+                       }
+
+               }
+
+               aconf->clients--;
+               if(!aconf->clients && IsIllegal(aconf))
+                       free_conf(aconf);
+
+               client_p->localClient->att_conf = NULL;
+               return 0;
+       }
+
+       return -1;
+}
+
+/*
+ * attach_conf
+ * 
+ * inputs      - client pointer
+ *             - conf pointer
+ * output      -
+ * side effects - 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...
+ */
+int
+attach_conf(struct Client *client_p, struct ConfItem *aconf)
+{
+       if(IsIllegal(aconf))
+               return (NOT_AUTHORISED);
+
+       if(ClassPtr(aconf))
+       {
+               if(!add_ip_limit(client_p, aconf))
+                       return (TOO_MANY_LOCAL);
+       }
+
+       if((aconf->status & CONF_CLIENT) &&
+          ConfCurrUsers(aconf) >= ConfMaxUsers(aconf) && ConfMaxUsers(aconf) > 0)
+       {
+               if(!IsConfExemptLimits(aconf))
+               {
+                       return (I_LINE_FULL);
+               }
+               else
+               {
+                       sendto_one(client_p, ":%s NOTICE %s :*** I: line is full, but you have an >I: line!", 
+                                             me.name, client_p->name);
+                       SetExemptLimits(client_p);
+               }
+
+       }
+
+       if(client_p->localClient->att_conf != NULL)
+               detach_conf(client_p);
+
+       client_p->localClient->att_conf = aconf;
+
+       aconf->clients++;
+       ConfCurrUsers(aconf)++;
+       return (0);
+}
+
+/*
+ * rehash
+ *
+ * Actual REHASH service routine. Called with sig == 0 if it has been called
+ * as a result of an operator issuing this command, else assume it has been
+ * called as a result of the server receiving a HUP signal.
+ */
+int
+rehash(int sig)
+{
+       if(sig != 0)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Got signal SIGHUP, reloading ircd conf. file");
+       }
+
+       restart_resolver();
+       /* don't close listeners until we know we can go ahead with the rehash */
+       read_conf_files(NO);
+
+       if(ServerInfo.description != NULL)
+               strlcpy(me.info, ServerInfo.description, sizeof(me.info));
+       else
+               strlcpy(me.info, "unknown", sizeof(me.info));
+
+       open_logfiles();
+       return (0);
+}
+
+static struct banconf_entry
+{
+       const char **filename;
+       void (*func) (FILE *);
+       int perm;
+} banconfs[] = {
+       { &ConfigFileEntry.klinefile,   parse_k_file,   0 },
+       { &ConfigFileEntry.klinefile,   parse_k_file,   1 },
+       { &ConfigFileEntry.dlinefile,   parse_d_file,   0 },
+       { &ConfigFileEntry.dlinefile,   parse_d_file,   1 },
+       { &ConfigFileEntry.xlinefile,   parse_x_file,   0 },
+       { &ConfigFileEntry.xlinefile,   parse_x_file,   1 },
+       { &ConfigFileEntry.resvfile,    parse_resv_file,0 },
+       { &ConfigFileEntry.resvfile,    parse_resv_file,1 },
+       { NULL,                         NULL,           0 }
+};
+
+void
+rehash_bans(int sig)
+{
+       FILE *file;
+       char buf[MAXPATHLEN];
+       int i;
+
+       if(sig != 0)
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                               "Got signal SIGUSR2, reloading ban confs");
+
+       clear_out_address_conf_bans();
+       clear_s_newconf_bans();
+
+       for(i = 0; banconfs[i].filename; i++)
+       {
+               if(banconfs[i].perm)
+                       snprintf(buf, sizeof(buf), "%s.perm", *banconfs[i].filename);
+               else
+                       snprintf(buf, sizeof(buf), "%s", *banconfs[i].filename);
+
+               if((file = fopen(buf, "r")) == NULL)
+               {
+                       if(banconfs[i].perm)
+                               continue;
+
+                       ilog(L_MAIN, "Failed reading ban file %s",
+                               *banconfs[i].filename);
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                       "Can't open %s file bans could be missing!",
+                                       *banconfs[i].filename);
+               }
+               else
+               {
+                       (banconfs[i].func)(file);
+                       fclose(file);
+               }
+       }
+
+       check_banned_lines();
+}
+
+/*
+ * set_default_conf()
+ *
+ * inputs      - NONE
+ * output      - NONE
+ * side effects        - Set default values here.
+ *               This is called **PRIOR** to parsing the
+ *               configuration file.  If you want to do some validation
+ *               of values later, put them in validate_conf().
+ */
+
+#define YES     1
+#define NO      0
+#define UNSET  -1
+
+static void
+set_default_conf(void)
+{
+       /* ServerInfo.name is not rehashable */
+       /* ServerInfo.name = ServerInfo.name; */
+       ServerInfo.description = NULL;
+       DupString(ServerInfo.network_name, NETWORK_NAME_DEFAULT);
+       DupString(ServerInfo.network_desc, NETWORK_DESC_DEFAULT);
+
+       memset(&ServerInfo.ip, 0, sizeof(ServerInfo.ip));
+       ServerInfo.specific_ipv4_vhost = 0;
+#ifdef IPV6
+       memset(&ServerInfo.ip6, 0, sizeof(ServerInfo.ip6));
+       ServerInfo.specific_ipv6_vhost = 0;
+#endif
+       ServerInfo.use_ts6 = YES;
+
+       /* Don't reset hub, as that will break lazylinks */
+       /* ServerInfo.hub = NO; */
+       AdminInfo.name = NULL;
+       AdminInfo.email = NULL;
+       AdminInfo.description = NULL;
+
+       DupString(ConfigFileEntry.default_operstring, "is an IRC operator");
+       DupString(ConfigFileEntry.default_adminstring, "is a Server Administrator");
+       DupString(ConfigFileEntry.servicestring, "is a Network Service");
+
+       ConfigFileEntry.default_umodes = UMODE_INVISIBLE;       
+       ConfigFileEntry.failed_oper_notice = YES;
+       ConfigFileEntry.anti_nick_flood = NO;
+       ConfigFileEntry.disable_fake_channels = NO;
+       ConfigFileEntry.max_nick_time = 20;
+       ConfigFileEntry.max_nick_changes = 5;
+       ConfigFileEntry.max_accept = 20;
+       ConfigFileEntry.max_monitor = 60;
+       ConfigFileEntry.nick_delay = 900;       /* 15 minutes */
+       ConfigFileEntry.target_change = YES;
+       ConfigFileEntry.anti_spam_exit_message_time = 0;
+       ConfigFileEntry.ts_warn_delta = TS_WARN_DELTA_DEFAULT;
+       ConfigFileEntry.ts_max_delta = TS_MAX_DELTA_DEFAULT;
+       ConfigFileEntry.client_exit = YES;
+       ConfigFileEntry.dline_with_reason = YES;
+       ConfigFileEntry.kline_with_reason = YES;
+       ConfigFileEntry.kline_delay = 0;
+       ConfigFileEntry.warn_no_nline = YES;
+       ConfigFileEntry.non_redundant_klines = YES;
+       ConfigFileEntry.stats_e_disabled = NO;
+       ConfigFileEntry.stats_o_oper_only = NO;
+       ConfigFileEntry.stats_k_oper_only = 1;  /* masked */
+       ConfigFileEntry.stats_i_oper_only = 1;  /* masked */
+       ConfigFileEntry.stats_P_oper_only = NO;
+       ConfigFileEntry.stats_c_oper_only = NO;
+       ConfigFileEntry.stats_y_oper_only = NO;
+       ConfigFileEntry.stats_h_oper_only = NO;
+       ConfigFileEntry.map_oper_only = YES;
+       ConfigFileEntry.operspy_admin_only = NO;
+       ConfigFileEntry.pace_wait = 10;
+       ConfigFileEntry.caller_id_wait = 60;
+       ConfigFileEntry.pace_wait_simple = 1;
+       ConfigFileEntry.short_motd = NO;
+       ConfigFileEntry.no_oper_flood = NO;
+       ConfigFileEntry.fname_userlog = NULL;
+       ConfigFileEntry.fname_fuserlog = NULL;
+       ConfigFileEntry.fname_operlog = NULL;
+       ConfigFileEntry.fname_foperlog = NULL;
+       ConfigFileEntry.fname_serverlog = NULL;
+       ConfigFileEntry.fname_glinelog = NULL;
+       ConfigFileEntry.fname_klinelog = NULL;
+       ConfigFileEntry.fname_operspylog = NULL;
+       ConfigFileEntry.fname_ioerrorlog = NULL;
+       ConfigFileEntry.glines = NO;
+       ConfigFileEntry.use_egd = NO;
+       ConfigFileEntry.gline_time = 12 * 3600;
+       ConfigFileEntry.gline_min_cidr = 16;
+       ConfigFileEntry.gline_min_cidr6 = 48;
+       ConfigFileEntry.hide_spoof_ips = YES;
+       ConfigFileEntry.hide_error_messages = 1;
+       ConfigFileEntry.idletime = 0;
+       ConfigFileEntry.dots_in_ident = 0;
+       ConfigFileEntry.max_targets = MAX_TARGETS_DEFAULT;
+       DupString(ConfigFileEntry.servlink_path, SLPATH);
+       ConfigFileEntry.egdpool_path = NULL;
+       ConfigFileEntry.use_whois_actually = YES;
+       ConfigFileEntry.burst_away = NO;
+       ConfigFileEntry.collision_fnc = YES;
+       ConfigFileEntry.global_snotices = YES;
+       ConfigFileEntry.operspy_dont_care_user_info = NO;
+
+#ifdef HAVE_LIBZ
+       ConfigFileEntry.compression_level = 4;
+#endif
+
+       ConfigFileEntry.oper_umodes = UMODE_LOCOPS | UMODE_SERVNOTICE |
+               UMODE_OPERWALL | UMODE_WALLOP;
+       ConfigFileEntry.oper_only_umodes = UMODE_SERVNOTICE;
+       ConfigFileEntry.oper_snomask = SNO_GENERAL;
+
+       ConfigChannel.use_except = YES;
+       ConfigChannel.use_invex = YES;
+       ConfigChannel.use_knock = YES;
+       ConfigChannel.use_forward = YES;
+       ConfigChannel.knock_delay = 300;
+       ConfigChannel.knock_delay_channel = 60;
+       ConfigChannel.max_chans_per_user = 15;
+       ConfigChannel.max_bans = 25;
+       ConfigChannel.max_bans_large = 500;
+       ConfigChannel.burst_topicwho = NO;
+       ConfigChannel.invite_ops_only = YES;
+       ConfigChannel.kick_on_split_riding = NO;
+
+       ConfigChannel.default_split_user_count = 15000;
+       ConfigChannel.default_split_server_count = 10;
+       ConfigChannel.no_join_on_split = NO;
+       ConfigChannel.no_create_on_split = YES;
+
+       ConfigServerHide.flatten_links = 0;
+       ConfigServerHide.links_delay = 300;
+       ConfigServerHide.hidden = 0;
+       ConfigServerHide.disable_hidden = 0;
+
+       ConfigFileEntry.min_nonwildcard = 4;
+       ConfigFileEntry.min_nonwildcard_simple = 3;
+       ConfigFileEntry.default_floodcount = 8;
+       ConfigFileEntry.client_flood = CLIENT_FLOOD_DEFAULT;
+       ConfigFileEntry.tkline_expire_notices = 0;
+
+        ConfigFileEntry.reject_after_count = 5;
+       ConfigFileEntry.reject_ban_time = 300;  
+       ConfigFileEntry.reject_duration = 120;
+                        
+}
+
+#undef YES
+#undef NO
+
+/*
+ * read_conf() 
+ *
+ *
+ * inputs       - file descriptor pointing to config file to use
+ * output       - None
+ * side effects        - Read configuration file.
+ */
+static void
+read_conf(FILE * file)
+{
+       lineno = 0;
+
+       set_default_conf();     /* Set default values prior to conf parsing */
+       yyparse();              /* Load the values from the conf */
+       validate_conf();        /* Check to make sure some values are still okay. */
+       /* Some global values are also loaded here. */
+       check_class();          /* Make sure classes are valid */
+}
+
+static void
+validate_conf(void)
+{
+       if(ConfigFileEntry.ts_warn_delta < TS_WARN_DELTA_MIN)
+               ConfigFileEntry.ts_warn_delta = TS_WARN_DELTA_DEFAULT;
+
+       if(ConfigFileEntry.ts_max_delta < TS_MAX_DELTA_MIN)
+               ConfigFileEntry.ts_max_delta = TS_MAX_DELTA_DEFAULT;
+
+       if(ConfigFileEntry.servlink_path == NULL)
+               DupString(ConfigFileEntry.servlink_path, SLPATH);
+
+       if(ServerInfo.network_name == NULL)
+               DupString(ServerInfo.network_name, NETWORK_NAME_DEFAULT);
+
+       if(ServerInfo.network_desc == NULL)
+               DupString(ServerInfo.network_desc, NETWORK_DESC_DEFAULT);
+
+       if((ConfigFileEntry.client_flood < CLIENT_FLOOD_MIN) ||
+          (ConfigFileEntry.client_flood > CLIENT_FLOOD_MAX))
+               ConfigFileEntry.client_flood = CLIENT_FLOOD_MAX;
+
+       GlobalSetOptions.idletime = (ConfigFileEntry.idletime * 60);
+
+       if(!split_users || !split_servers ||
+          (!ConfigChannel.no_create_on_split && !ConfigChannel.no_join_on_split))
+       {
+               eventDelete(check_splitmode, NULL);
+               splitmode = 0;
+               splitchecking = 0;
+       }
+}
+
+/*
+ * lookup_confhost - start DNS lookups of all hostnames in the conf
+ * line and convert an IP addresses in a.b.c.d number for to IP#s.
+ *
+ */
+
+/*
+ * conf_connect_allowed
+ *
+ * inputs      - pointer to inaddr
+ *             - int type ipv4 or ipv6
+ * output      - ban info or NULL
+ * side effects        - none
+ */
+struct ConfItem *
+conf_connect_allowed(struct sockaddr *addr, int aftype)
+{
+       struct ConfItem *aconf = find_dline(addr, aftype);
+
+       /* DLINE exempt also gets you out of static limits/pacing... */
+       if(aconf && (aconf->status & CONF_EXEMPTDLINE))
+               return NULL;
+
+       if(aconf != NULL)
+               return aconf;
+
+       return NULL;
+}
+
+/* add_temp_kline()
+ *
+ * inputs        - pointer to struct ConfItem
+ * output        - none
+ * Side effects  - links in given struct ConfItem into 
+ *                 temporary kline link list
+ */
+void
+add_temp_kline(struct ConfItem *aconf)
+{
+       if(aconf->hold >= CurrentTime + (10080 * 60))
+       {
+               dlinkAddAlloc(aconf, &temp_klines[TEMP_WEEK]);
+               aconf->port = TEMP_WEEK;
+       }
+       else if(aconf->hold >= CurrentTime + (1440 * 60))
+       {
+               dlinkAddAlloc(aconf, &temp_klines[TEMP_DAY]);
+               aconf->port = TEMP_DAY;
+       }
+       else if(aconf->hold >= CurrentTime + (60 * 60))
+       {
+               dlinkAddAlloc(aconf, &temp_klines[TEMP_HOUR]);
+               aconf->port = TEMP_HOUR;
+       }
+       else
+       {
+               dlinkAddAlloc(aconf, &temp_klines[TEMP_MIN]);
+               aconf->port = TEMP_MIN;
+       }
+
+       aconf->flags |= CONF_FLAGS_TEMPORARY;
+       add_conf_by_address(aconf->host, CONF_KILL, aconf->user, aconf);
+}
+
+/* add_temp_dline()
+ *
+ * input       - pointer to struct ConfItem
+ * output      - none
+ * side effects - added to tdline link list and address hash
+ */
+void
+add_temp_dline(struct ConfItem *aconf)
+{
+       if(aconf->hold >= CurrentTime + (10080 * 60))
+       {
+               dlinkAddAlloc(aconf, &temp_dlines[TEMP_WEEK]);
+               aconf->port = TEMP_WEEK;
+       }
+       else if(aconf->hold >= CurrentTime + (1440 * 60))
+       {
+               dlinkAddAlloc(aconf, &temp_dlines[TEMP_DAY]);
+               aconf->port = TEMP_DAY;
+       }
+       else if(aconf->hold >= CurrentTime + (60 * 60))
+       {
+               dlinkAddAlloc(aconf, &temp_dlines[TEMP_HOUR]);
+               aconf->port = TEMP_HOUR;
+       }
+       else
+       {
+               dlinkAddAlloc(aconf, &temp_dlines[TEMP_MIN]);
+               aconf->port = TEMP_MIN;
+       }
+
+       aconf->flags |= CONF_FLAGS_TEMPORARY;
+       add_conf_by_address(aconf->host, CONF_DLINE, aconf->user, aconf);
+}
+
+/* expire_tkline()
+ *
+ * inputs       - list pointer
+ *             - type
+ * output       - NONE
+ * side effects - expire tklines and moves them between lists
+ */
+static void
+expire_temp_kd(void *list)
+{
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+       struct ConfItem *aconf;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, ((dlink_list *) list)->head)
+       {
+               aconf = ptr->data;
+
+               if(aconf->hold <= CurrentTime)
+               {
+                       /* Alert opers that a TKline expired - Hwy */
+                       if(ConfigFileEntry.tkline_expire_notices)
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                                    "Temporary K-line for [%s@%s] expired",
+                                                    (aconf->user) ? aconf->
+                                                    user : "*", (aconf->host) ? aconf->host : "*");
+
+                       delete_one_address_conf(aconf->host, aconf);
+                       dlinkDestroy(ptr, list);
+               }
+       }
+}
+
+static void
+reorganise_temp_kd(void *list)
+{
+       struct ConfItem *aconf;
+       dlink_node *ptr, *next_ptr;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, ((dlink_list *) list)->head)
+       {
+               aconf = ptr->data;
+
+               if(aconf->hold < (CurrentTime + (60 * 60)))
+               {
+                       dlinkMoveNode(ptr, list, (aconf->status == CONF_KILL) ? 
+                                       &temp_klines[TEMP_MIN] : &temp_dlines[TEMP_MIN]);
+                       aconf->port = TEMP_MIN;
+               }
+               else if(aconf->port > TEMP_HOUR)
+               {
+                       if(aconf->hold < (CurrentTime + (1440 * 60)))
+                       {
+                               dlinkMoveNode(ptr, list, (aconf->status == CONF_KILL) ? 
+                                               &temp_klines[TEMP_HOUR] : &temp_dlines[TEMP_HOUR]);
+                               aconf->port = TEMP_HOUR;
+                       }
+                       else if(aconf->port > TEMP_DAY && 
+                               (aconf->hold < (CurrentTime + (10080 * 60))))
+                       {
+                               dlinkMoveNode(ptr, list, (aconf->status == CONF_KILL) ? 
+                                               &temp_klines[TEMP_DAY] : &temp_dlines[TEMP_DAY]);
+                               aconf->port = TEMP_DAY;
+                       }
+               }
+       }
+}
+
+
+/* const char* get_oper_name(struct Client *client_p)
+ * Input: A client to find the active oper{} name for.
+ * Output: The nick!user@host{oper} of the oper.
+ *         "oper" is server name for remote opers
+ * Side effects: None.
+ */
+char *
+get_oper_name(struct Client *client_p)
+{
+       /* +5 for !,@,{,} and null */
+       static char buffer[NICKLEN + USERLEN + HOSTLEN + HOSTLEN + 5];
+
+       if(MyOper(client_p))
+       {
+               ircsnprintf(buffer, sizeof(buffer), "%s!%s@%s{%s}",
+                               client_p->name, client_p->username,
+                               client_p->host, client_p->localClient->opername);
+               return buffer;
+       }
+
+       ircsnprintf(buffer, sizeof(buffer), "%s!%s@%s{%s}",
+                  client_p->name, client_p->username, 
+                  client_p->host, client_p->servptr->name);
+       return buffer;
+}
+
+/*
+ * get_printable_conf
+ *
+ * inputs        - struct ConfItem
+ *
+ * output         - name 
+ *                - host
+ *                - pass
+ *                - user
+ *                - port
+ *
+ * side effects        -
+ * Examine the struct struct ConfItem, setting the values
+ * of name, host, pass, user to values either
+ * in aconf, or "<NULL>" port is set to aconf->port in all cases.
+ */
+void
+get_printable_conf(struct ConfItem *aconf, char **name, char **host,
+                  char **pass, char **user, int *port, char **classname)
+{
+       static char null[] = "<NULL>";
+       static char zero[] = "default";
+
+       *name = EmptyString(aconf->name) ? null : aconf->name;
+       *host = EmptyString(aconf->host) ? null : aconf->host;
+       *pass = EmptyString(aconf->passwd) ? null : aconf->passwd;
+       *user = EmptyString(aconf->user) ? null : aconf->user;
+       *classname = EmptyString(aconf->className) ? zero : aconf->className;
+       *port = (int) aconf->port;
+}
+
+void
+get_printable_kline(struct Client *source_p, struct ConfItem *aconf, 
+                   char **host, char **reason,
+                   char **user, char **oper_reason)
+{
+       static char null[] = "<NULL>";
+
+       *host = EmptyString(aconf->host) ? null : aconf->host;
+       *reason = EmptyString(aconf->passwd) ? null : aconf->passwd;
+       *user = EmptyString(aconf->user) ? null : aconf->user;
+
+       if(EmptyString(aconf->spasswd) || !IsOper(source_p))
+               *oper_reason = NULL;
+       else
+               *oper_reason = aconf->spasswd;
+}
+
+/*
+ * read_conf_files
+ *
+ * inputs       - cold start YES or NO
+ * output       - none
+ * side effects - read all conf files needed, ircd.conf kline.conf etc.
+ */
+void
+read_conf_files(int cold)
+{
+       const char *filename;
+
+       conf_fbfile_in = NULL;
+
+       filename = get_conf_name(CONF_TYPE);
+
+       /* We need to know the initial filename for the yyerror() to report
+          FIXME: The full path is in conffilenamebuf first time since we
+          dont know anything else
+
+          - Gozem 2002-07-21 
+        */
+       strlcpy(conffilebuf, filename, sizeof(conffilebuf));
+
+       if((conf_fbfile_in = fopen(filename, "r")) == NULL)
+       {
+               if(cold)
+               {
+                       ilog(L_MAIN, "Failed in reading configuration file %s", filename);
+                       exit(-1);
+               }
+               else
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "Can't open file '%s' - aborting rehash!", filename);
+                       return;
+               }
+       }
+
+       if(!cold)
+       {
+               clear_out_old_conf();
+       }
+
+       read_conf(conf_fbfile_in);
+       fclose(conf_fbfile_in);
+}
+
+/*
+ * clear_out_old_conf
+ *
+ * inputs       - none
+ * output       - none
+ * side effects - Clear out the old configuration
+ */
+static void
+clear_out_old_conf(void)
+{
+       struct Class *cltmp;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+       int i;
+
+       /*
+        * don't delete the class table, rather mark all entries
+        * for deletion. The table is cleaned up by check_class. - avalon
+        */
+       DLINK_FOREACH(ptr, class_list.head)
+       {
+               cltmp = ptr->data;
+               MaxUsers(cltmp) = -1;
+       }
+
+       clear_out_address_conf();
+       clear_s_newconf();
+
+       /* clean out module paths */
+#ifndef STATIC_MODULES
+       mod_clear_paths();
+       mod_add_path(MODULE_DIR);
+       mod_add_path(MODULE_DIR  "/autoload");
+#endif
+
+       /* clean out ServerInfo */
+       MyFree(ServerInfo.description);
+       ServerInfo.description = NULL;
+       MyFree(ServerInfo.network_name);
+       ServerInfo.network_name = NULL;
+       MyFree(ServerInfo.network_desc);
+       ServerInfo.network_desc = NULL;
+
+       /* clean out AdminInfo */
+       MyFree(AdminInfo.name);
+       AdminInfo.name = NULL;
+       MyFree(AdminInfo.email);
+       AdminInfo.email = NULL;
+       MyFree(AdminInfo.description);
+       AdminInfo.description = NULL;
+
+       /* operator{} and class{} blocks are freed above */
+       /* clean out listeners */
+       close_listeners();
+
+       /* auth{}, quarantine{}, shared{}, connect{}, kill{}, deny{}, exempt{}
+        * and gecos{} blocks are freed above too
+        */
+
+       /* clean out general */
+       MyFree(ConfigFileEntry.servlink_path);
+       ConfigFileEntry.servlink_path = NULL;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, service_list.head)
+       {
+               MyFree(ptr->data);
+               dlinkDestroy(ptr, &service_list);
+       }
+
+       /* remove any aliases... -- nenolod */
+       for (i = 0; i < MAX_MSG_HASH; i++)
+       {
+               DLINK_FOREACH_SAFE(ptr, next_ptr, alias_hash_table[i].head)
+               {
+                       struct alias_entry *aptr = ptr->data;
+
+                       MyFree(aptr->name);
+                       MyFree(aptr->target);
+                       MyFree(aptr);
+
+                       dlinkDestroy(ptr, &alias_hash_table[i]);
+               }
+       }
+
+       destroy_blacklists();
+
+       /* OK, that should be everything... */
+}
+
+
+/* write_confitem()
+ *
+ * inputs       - kline, dline or resv type flag
+ *              - client pointer to report to
+ *              - user name of target
+ *              - host name of target
+ *              - reason for target
+ *              - time string
+ *              - type of xline
+ * output       - NONE
+ * side effects - This function takes care of finding the right conf
+ *                file and adding the line to it, as well as notifying
+ *                opers and the user.
+ */
+void
+write_confitem(KlineType type, struct Client *source_p, char *user,
+              char *host, const char *reason, const char *oper_reason,
+              const char *current_date, int xtype)
+{
+       char buffer[1024];
+       FILE *out;
+       const char *filename;   /* filename to use for kline */
+
+       filename = get_conf_name(type);
+
+       if(type == KLINE_TYPE)
+       {
+               if(EmptyString(oper_reason))
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                       "%s added K-Line for [%s@%s] [%s]",
+                                       get_oper_name(source_p), user, 
+                                       host, reason);
+                       ilog(L_KLINE, "K %s 0 %s %s %s",
+                               get_oper_name(source_p), user, host, reason);
+               }
+               else
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                       "%s added K-Line for [%s@%s] [%s|%s]",
+                                       get_oper_name(source_p), user,
+                                       host, reason, oper_reason);
+                       ilog(L_KLINE, "K %s 0 %s %s %s|%s",
+                               get_oper_name(source_p), user, host,
+                               reason, oper_reason);
+               }
+
+               sendto_one_notice(source_p, ":Added K-Line [%s@%s]",
+                                 user, host);
+       }
+       else if(type == DLINE_TYPE)
+       {
+               if(EmptyString(oper_reason))
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                       "%s added D-Line for [%s] [%s]",
+                                       get_oper_name(source_p), host, reason);
+                       ilog(L_KLINE, "D %s 0 %s %s",
+                               get_oper_name(source_p), host, reason);
+               }
+               else
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                       "%s added D-Line for [%s] [%s|%s]",
+                                       get_oper_name(source_p), host, 
+                                       reason, oper_reason);
+                       ilog(L_KLINE, "D %s 0 %s %s|%s",
+                               get_oper_name(source_p), host, 
+                               reason, oper_reason);
+               }
+
+               sendto_one(source_p,
+                          ":%s NOTICE %s :Added D-Line [%s] to %s", me.name,
+                          source_p->name, host, filename);
+
+       }
+       else if(type == RESV_TYPE)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                               "%s added RESV for [%s] [%s]",
+                               get_oper_name(source_p), host, reason);
+               ilog(L_KLINE, "R %s 0 %s %s",
+                       get_oper_name(source_p), host, reason);
+
+               sendto_one_notice(source_p, ":Added RESV for [%s] [%s]",
+                                 host, reason);
+       }
+
+       if((out = fopen(filename, "a")) == NULL)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "*** Problem opening %s ", filename);
+               sendto_one_notice(source_p, ":*** Problem opening file, added temporarily only");
+               return;
+       }
+
+       if(oper_reason == NULL)
+               oper_reason = "";
+
+       if(type == KLINE_TYPE)
+       {
+               ircsnprintf(buffer, sizeof(buffer),
+                          "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",%ld\n",
+                          user, host, reason, oper_reason, current_date,
+                          get_oper_name(source_p), CurrentTime);
+       }
+       else if(type == DLINE_TYPE)
+       {
+               ircsnprintf(buffer, sizeof(buffer),
+                          "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",%ld\n", host,
+                          reason, oper_reason, current_date, get_oper_name(source_p), CurrentTime);
+       }
+       else if(type == RESV_TYPE)
+       {
+               ircsnprintf(buffer, sizeof(buffer), "\"%s\",\"%s\",\"%s\",%ld\n",
+                          host, reason, get_oper_name(source_p), CurrentTime);
+       }
+
+       if(fputs(buffer, out) == -1)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "*** Problem writing to %s", filename);
+               sendto_one_notice(source_p, ":*** Problem writing to file, added temporarily only");
+               fclose(out);
+               return;
+       }
+
+       if (fclose(out))
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "*** Problem writing to %s", filename);
+               sendto_one_notice(source_p, ":*** Problem writing to file, added temporarily only");
+               return;
+       }
+}
+
+/* get_conf_name
+ *
+ * inputs       - type of conf file to return name of file for
+ * output       - pointer to filename for type of conf
+ * side effects - none
+ */
+const char *
+get_conf_name(KlineType type)
+{
+       if(type == CONF_TYPE)
+       {
+               return (ConfigFileEntry.configfile);
+       }
+       else if(type == DLINE_TYPE)
+       {
+               return (ConfigFileEntry.dlinefile);
+       }
+       else if(type == RESV_TYPE)
+       {
+               return (ConfigFileEntry.resvfile);
+       }
+
+       return ConfigFileEntry.klinefile;
+}
+
+/*
+ * conf_add_class_to_conf
+ * inputs       - pointer to config item
+ * output       - NONE
+ * side effects - Add a class pointer to a conf 
+ */
+
+void
+conf_add_class_to_conf(struct ConfItem *aconf)
+{
+       if(aconf->className == NULL)
+       {
+               DupString(aconf->className, "default");
+               ClassPtr(aconf) = default_class;
+               return;
+       }
+
+       ClassPtr(aconf) = find_class(aconf->className);
+
+       if(ClassPtr(aconf) == default_class)
+       {
+               if(aconf->status == CONF_CLIENT)
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "Warning -- Using default class for missing class \"%s\" in auth{} for %s@%s",
+                                            aconf->className, aconf->user, aconf->host);
+               }
+
+               MyFree(aconf->className);
+               DupString(aconf->className, "default");
+               return;
+       }
+
+       if(ConfMaxUsers(aconf) < 0)
+       {
+               ClassPtr(aconf) = default_class;
+               MyFree(aconf->className);
+               DupString(aconf->className, "default");
+               return;
+       }
+}
+
+/*
+ * conf_add_d_conf
+ * inputs       - pointer to config item
+ * output       - NONE
+ * side effects - Add a d/D line
+ */
+void
+conf_add_d_conf(struct ConfItem *aconf)
+{
+       if(aconf->host == NULL)
+               return;
+
+       aconf->user = NULL;
+
+       /* XXX - Should 'd' ever be in the old conf? For new conf we don't
+        *       need this anyway, so I will disable it for now... -A1kmm
+        */
+
+       if(parse_netmask(aconf->host, NULL, NULL) == HM_HOST)
+       {
+               ilog(L_MAIN, "Invalid Dline %s ignored", aconf->host);
+               free_conf(aconf);
+       }
+       else
+       {
+               add_conf_by_address(aconf->host, CONF_DLINE, NULL, aconf);
+       }
+}
+
+
+/*
+ * yyerror
+ *
+ * inputs      - message from parser
+ * output      - none
+ * side effects        - message to opers and log file entry is made
+ */
+void
+yyerror(const char *msg)
+{
+       char newlinebuf[BUFSIZE];
+
+       strip_tabs(newlinebuf, (const unsigned char *) linebuf, strlen(linebuf));
+
+       sendto_realops_snomask(SNO_GENERAL, L_ALL, "\"%s\", line %d: %s at '%s'",
+                            conffilebuf, lineno + 1, msg, newlinebuf);
+
+       ilog(L_MAIN, "\"%s\", line %d: %s at '%s'", conffilebuf, lineno + 1, msg, newlinebuf);
+}
+
+int
+conf_fgets(char *lbuf, int max_size, FILE * fb)
+{
+       char *buff;
+
+       if((buff = fgets(lbuf, max_size, fb)) == NULL)
+               return (0);
+
+       return (strlen(lbuf));
+}
+
+int
+conf_yy_fatal_error(const char *msg)
+{
+       return (0);
+}
diff --git a/src/s_gline.c b/src/s_gline.c
new file mode 100644 (file)
index 0000000..4eca0e7
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  s_gline.c: GLine global ban functions.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: s_gline.c 254 2005-09-21 23:35:12Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "channel.h"
+#include "client.h"
+#include "common.h"
+#include "config.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "hostmask.h"
+#include "numeric.h"
+#include "commio.h"
+#include "s_conf.h"
+#include "scache.h"
+#include "send.h"
+#include "msg.h"
+#include "s_serv.h"
+#include "s_gline.h"
+#include "hash.h"
+#include "event.h"
+#include "memory.h"
+
+dlink_list glines;
+
+static void expire_glines(void);
+static void expire_pending_glines(void);
+
+/* add_gline
+ *
+ * inputs       - pointer to struct ConfItem
+ * output       - none
+ * Side effects - links in given struct ConfItem into gline link list
+ */
+void
+add_gline(struct ConfItem *aconf)
+{
+       dlinkAddTailAlloc(aconf, &glines);
+       add_conf_by_address(aconf->host, CONF_GLINE, aconf->user, aconf);
+}
+
+/*
+ * find_is_glined
+ * inputs       - hostname
+ *              - username
+ * output       - pointer to struct ConfItem if user@host glined
+ * side effects -
+ */
+struct ConfItem *
+find_is_glined(const char *host, const char *user)
+{
+       dlink_node *gline_node;
+       struct ConfItem *kill_ptr;
+
+       DLINK_FOREACH(gline_node, glines.head)
+       {
+               kill_ptr = gline_node->data;
+               if((kill_ptr->user && (!user || match(kill_ptr->user, user)))
+                  && (kill_ptr->host && (!host || match(kill_ptr->host, host))))
+               {
+                       return (kill_ptr);
+               }
+       }
+
+       return (NULL);
+}
+
+/*
+ * cleanup_glines
+ *
+ * inputs      - NONE
+ * output      - NONE
+ * side effects - expire gline lists
+ *                This is an event started off in ircd.c
+ */
+void
+cleanup_glines(void *unused)
+{
+       expire_glines();
+       expire_pending_glines();
+}
+
+/*
+ * expire_glines
+ * 
+ * inputs       - NONE
+ * output       - NONE
+ * side effects -
+ *
+ * Go through the gline list, expire any needed.
+ */
+static void
+expire_glines()
+{
+       dlink_node *gline_node;
+       dlink_node *next_node;
+       struct ConfItem *kill_ptr;
+
+       DLINK_FOREACH_SAFE(gline_node, next_node, glines.head)
+       {
+               kill_ptr = gline_node->data;
+
+               /* these are in chronological order */
+               if(kill_ptr->hold > CurrentTime)
+                       break;
+
+               dlinkDestroy(gline_node, &glines);
+               delete_one_address_conf(kill_ptr->host, kill_ptr);
+       }
+}
+
+/*
+ * expire_pending_glines
+ * 
+ * inputs       - NONE
+ * output       - NONE
+ * side effects -
+ *
+ * Go through the pending gline list, expire any that haven't had
+ * enough "votes" in the time period allowed
+ */
+static void
+expire_pending_glines()
+{
+       dlink_node *pending_node;
+       dlink_node *next_node;
+       struct gline_pending *glp_ptr;
+
+       DLINK_FOREACH_SAFE(pending_node, next_node, pending_glines.head)
+       {
+               glp_ptr = pending_node->data;
+
+               if(((glp_ptr->last_gline_time + GLINE_PENDING_EXPIRE) <=
+                   CurrentTime) || find_is_glined(glp_ptr->host, glp_ptr->user))
+
+               {
+                       MyFree(glp_ptr->reason1);
+                       MyFree(glp_ptr->reason2);
+                       MyFree(glp_ptr);
+                       dlinkDestroy(pending_node, &pending_glines);
+               }
+       }
+}
diff --git a/src/s_log.c b/src/s_log.c
new file mode 100644 (file)
index 0000000..129d224
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * ircd-ratbox: an advanced Internet Relay Chat Daemon(ircd).
+ *
+ * Copyright (C) 2003 Lee H <lee@leeh.co.uk>
+ * Copyright (C) 2003-2005 ircd-ratbox development team
+ *
+ * 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.The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: s_log.c 1563 2006-06-02 00:43:35Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "ircd_defs.h"
+#include "s_log.h"
+#include "s_conf.h"
+#include "sprintf_irc.h"
+#include "send.h"
+#include "client.h"
+#include "s_serv.h"
+
+static FILE *log_main;
+static FILE *log_user;
+static FILE *log_fuser;
+static FILE *log_oper;
+static FILE *log_foper;
+static FILE *log_server;
+static FILE *log_kill;
+static FILE *log_gline;
+static FILE *log_kline;
+static FILE *log_operspy;
+static FILE *log_ioerror;
+
+struct log_struct
+{
+       char **name;
+       FILE **logfile;
+};
+
+static struct log_struct log_table[LAST_LOGFILE] =
+{
+       { NULL,                                 &log_main       },
+       { &ConfigFileEntry.fname_userlog,       &log_user       },
+       { &ConfigFileEntry.fname_fuserlog,      &log_fuser      },
+       { &ConfigFileEntry.fname_operlog,       &log_oper       },
+       { &ConfigFileEntry.fname_foperlog,      &log_foper      },
+       { &ConfigFileEntry.fname_serverlog,     &log_server     },
+       { &ConfigFileEntry.fname_killlog,       &log_kill       },
+       { &ConfigFileEntry.fname_klinelog,      &log_kline      },
+       { &ConfigFileEntry.fname_glinelog,      &log_gline      },
+       { &ConfigFileEntry.fname_operspylog,    &log_operspy    },
+       { &ConfigFileEntry.fname_ioerrorlog,    &log_ioerror    }
+};
+
+void
+init_main_logfile(void)
+{
+       if(log_main == NULL)
+               log_main = fopen(LPATH, "a");
+}
+
+void
+open_logfiles(void)
+{
+       int i;
+
+       if(log_main != NULL)
+               fclose(log_main);
+
+       log_main = fopen(LPATH, "a");
+
+       /* log_main is handled above, so just do the rest */
+       for(i = 1; i < LAST_LOGFILE; i++)
+       {
+               /* close open logfiles */
+               if(*log_table[i].logfile != NULL)
+               {
+                       fclose(*log_table[i].logfile);
+                       *log_table[i].logfile = NULL;
+               }
+
+               /* reopen those with paths */
+               if(!EmptyString(*log_table[i].name))
+                       *log_table[i].logfile = fopen(*log_table[i].name, "a");
+       }
+}                      
+
+void
+ilog(ilogfile dest, const char *format, ...)
+{
+       FILE *logfile = *log_table[dest].logfile;
+       char buf[BUFSIZE];
+       char buf2[BUFSIZE];
+       va_list args;
+
+       if(logfile == NULL)
+               return;
+
+       va_start(args, format);
+       ircvsnprintf(buf, sizeof(buf), format, args);
+       va_end(args);
+
+       ircsnprintf(buf2, sizeof(buf2), "%s %s\n", smalldate(), buf);
+
+       if(fputs(buf2, logfile) < 0)
+       {
+               fclose(logfile);
+               *log_table[dest].logfile = NULL;
+       }
+
+       fflush(logfile);
+}
+
+static void
+_iprint(const char *domain, char *buf)
+{
+       if (domain == NULL || buf == NULL)
+               return;
+
+       fprintf(stderr, "%8s: %s\n", domain, buf);
+}
+
+void
+inotice(const char *format, ...)
+{
+       char buf[BUFSIZE];
+       va_list args;
+
+       va_start(args, format);
+       ircvsnprintf(buf, sizeof(buf), format, args);
+       va_end(args);
+
+       _iprint("notice", buf);
+
+       ilog(L_MAIN, "%s", buf);
+}
+
+void
+iwarn(const char *format, ...)
+{
+       char buf[BUFSIZE];
+       va_list args;
+
+       va_start(args, format);
+       ircvsnprintf(buf, sizeof(buf), format, args);
+       va_end(args);
+
+       _iprint("warning", buf);
+
+       ilog(L_MAIN, "%s", buf);
+}
+
+void
+ierror(const char *format, ...)
+{
+       char buf[BUFSIZE];
+       va_list args;
+
+       va_start(args, format);
+       ircvsnprintf(buf, sizeof(buf), format, args);
+       va_end(args);
+
+       _iprint("error", buf);
+
+       ilog(L_MAIN, "%s", buf);
+}
+
+void
+report_operspy(struct Client *source_p, const char *token, const char *arg)
+{
+       /* if its not my client its already propagated */
+       if(MyClient(source_p))
+               sendto_match_servs(source_p, "*", CAP_ENCAP, NOCAPS,
+                                  "ENCAP * OPERSPY %s %s",
+                                  token, arg ? arg : "");
+
+       sendto_realops_snomask(SNO_OPERSPY,
+                            ConfigFileEntry.operspy_admin_only ? L_ADMIN : L_ALL,
+                            "OPERSPY %s %s %s",
+                            get_oper_name(source_p), token,
+                            arg ? arg : "");
+
+       ilog(L_OPERSPY, "OPERSPY %s %s %s",
+            get_oper_name(source_p), token, arg ? arg : "");
+}
+
+const char *
+smalldate(void)
+{
+       static char buf[MAX_DATE_STRING];
+       struct tm *lt;
+       time_t ltime = CurrentTime;
+
+       lt = localtime(&ltime);
+
+       ircsnprintf(buf, sizeof(buf), "%d/%d/%d %02d.%02d",
+                   lt->tm_year + 1900, lt->tm_mon + 1,
+                   lt->tm_mday, lt->tm_hour, lt->tm_min);
+
+       return buf;
+}
+
+/*
+ * report_error - report an error from an errno. 
+ * Record error to log and also send a copy to all *LOCAL* opers online.
+ *
+ *        text        is a *format* string for outputing error. It must
+ *                contain only two '%s', the first will be replaced
+ *                by the sockhost from the client_p, and the latter will
+ *                be taken from sys_errlist[errno].
+ *
+ *        client_p        if not NULL, is the *LOCAL* client associated with
+ *                the error.
+ *
+ * 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...
+ * 
+ * Actually stderr is still there IFF ircd was run with -s --Rodder
+ */
+
+void
+report_error(const char *text, const char *who, const char *wholog, int error)
+{
+       who = (who) ? who : "";
+       wholog = (wholog) ? wholog : "";
+
+       sendto_realops_snomask(SNO_DEBUG, L_ALL, text, who, strerror(error));
+
+       ilog(L_IOERROR, text, wholog, strerror(error));
+}
diff --git a/src/s_newconf.c b/src/s_newconf.c
new file mode 100644 (file)
index 0000000..97cd475
--- /dev/null
@@ -0,0 +1,787 @@
+/*
+ * ircd-ratbox: an advanced Internet Relay Chat Daemon(ircd).
+ * s_newconf.c - code for dealing with conf stuff
+ *
+ * Copyright (C) 2004 Lee Hardy <lee@leeh.co.uk>
+ * Copyright (C) 2004-2005 ircd-ratbox development team
+ *
+ * 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.The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: s_newconf.c 1747 2006-07-25 21:22:45Z jilles $
+ */
+
+#include "stdinc.h"
+#include "ircd_defs.h"
+#include "common.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "tools.h"
+#include "client.h"
+#include "memory.h"
+#include "s_serv.h"
+#include "send.h"
+#include "hostmask.h"
+#include "newconf.h"
+#include "hash.h"
+#include "balloc.h"
+#include "event.h"
+#include "sprintf_irc.h"
+
+dlink_list shared_conf_list;
+dlink_list cluster_conf_list;
+dlink_list oper_conf_list;
+dlink_list hubleaf_conf_list;
+dlink_list server_conf_list;
+dlink_list xline_conf_list;
+dlink_list resv_conf_list;     /* nicks only! */
+dlink_list nd_list;            /* nick delay */
+dlink_list tgchange_list;
+
+patricia_tree_t *tgchange_tree;
+
+static BlockHeap *nd_heap = NULL;
+
+static void expire_temp_rxlines(void *unused);
+static void expire_nd_entries(void *unused);
+
+void
+init_s_newconf(void)
+{
+       tgchange_tree = New_Patricia(PATRICIA_BITS);
+       nd_heap = BlockHeapCreate(sizeof(struct nd_entry), ND_HEAP_SIZE);
+       eventAddIsh("expire_nd_entries", expire_nd_entries, NULL, 30);
+       eventAddIsh("expire_temp_rxlines", expire_temp_rxlines, NULL, 60);
+}
+
+void
+clear_s_newconf(void)
+{
+       struct server_conf *server_p;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, shared_conf_list.head)
+       {
+               /* ptr here is ptr->data->node */
+               dlinkDelete(ptr, &shared_conf_list);
+               free_remote_conf(ptr->data);
+       }
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, cluster_conf_list.head)
+       {
+               dlinkDelete(ptr, &cluster_conf_list);
+               free_remote_conf(ptr->data);
+       }
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, hubleaf_conf_list.head)
+       {
+               dlinkDelete(ptr, &hubleaf_conf_list);
+               free_remote_conf(ptr->data);
+       }
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, oper_conf_list.head)
+       {
+               free_oper_conf(ptr->data);
+               dlinkDestroy(ptr, &oper_conf_list);
+       }
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, server_conf_list.head)
+       {
+               server_p = ptr->data;
+
+               if(!server_p->servers)
+               {
+                       dlinkDelete(ptr, &server_conf_list);
+                       free_server_conf(ptr->data);
+               }
+               else
+                       server_p->flags |= SERVER_ILLEGAL;
+       }
+}
+
+void
+clear_s_newconf_bans(void)
+{
+       struct ConfItem *aconf;
+       dlink_node *ptr, *next_ptr;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, xline_conf_list.head)
+       {
+               aconf = ptr->data;
+
+               if(aconf->hold)
+                       continue;
+
+               free_conf(aconf);
+               dlinkDestroy(ptr, &xline_conf_list);
+       }
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, resv_conf_list.head)
+       {
+               aconf = ptr->data;
+
+               /* temporary resv */
+               if(aconf->hold)
+                       continue;
+
+               free_conf(aconf);
+               dlinkDestroy(ptr, &resv_conf_list);
+       }
+
+       clear_resv_hash();
+}
+
+struct remote_conf *
+make_remote_conf(void)
+{
+       struct remote_conf *remote_p = MyMalloc(sizeof(struct remote_conf));
+       return remote_p;
+}
+
+void
+free_remote_conf(struct remote_conf *remote_p)
+{
+       s_assert(remote_p != NULL);
+       if(remote_p == NULL)
+               return;
+
+       MyFree(remote_p->username);
+       MyFree(remote_p->host);
+       MyFree(remote_p->server);
+       MyFree(remote_p);
+}
+
+int
+find_shared_conf(const char *username, const char *host, 
+               const char *server, int flags)
+{
+       struct remote_conf *shared_p;
+       dlink_node *ptr;
+
+       DLINK_FOREACH(ptr, shared_conf_list.head)
+       {
+               shared_p = ptr->data;
+
+               if(match(shared_p->username, username) &&
+                  match(shared_p->host, host) &&
+                  match(shared_p->server, server))
+               {
+                       if(shared_p->flags & flags)
+                               return YES;
+                       else
+                               return NO;
+               }
+       }
+
+       return NO;
+}
+
+void
+propagate_generic(struct Client *source_p, const char *command,
+               const char *target, int cap, const char *format, ...)
+{
+       char buffer[BUFSIZE];
+       va_list args;
+
+       va_start(args, format);
+       ircvsnprintf(buffer, sizeof(buffer), format, args);
+       va_end(args);
+
+       sendto_match_servs(source_p, target, cap, NOCAPS,
+                       "%s %s %s",
+                       command, target, buffer);
+       sendto_match_servs(source_p, target, CAP_ENCAP, cap,
+                       "ENCAP %s %s %s",
+                       target, command, buffer);
+}
+                       
+void
+cluster_generic(struct Client *source_p, const char *command,
+               int cltype, int cap, const char *format, ...)
+{
+       char buffer[BUFSIZE];
+       struct remote_conf *shared_p;
+       va_list args;
+       dlink_node *ptr;
+
+       va_start(args, format);
+       ircvsnprintf(buffer, sizeof(buffer), format, args);
+       va_end(args);
+
+       DLINK_FOREACH(ptr, cluster_conf_list.head)
+       {
+               shared_p = ptr->data;
+
+               if(!(shared_p->flags & cltype))
+                       continue;
+
+               sendto_match_servs(source_p, shared_p->server, cap, NOCAPS,
+                               "%s %s %s",
+                               command, shared_p->server, buffer);
+               sendto_match_servs(source_p, shared_p->server, CAP_ENCAP, cap,
+                               "ENCAP %s %s %s",
+                               shared_p->server, command, buffer);
+       }
+}
+
+struct oper_conf *
+make_oper_conf(void)
+{
+       struct oper_conf *oper_p = MyMalloc(sizeof(struct oper_conf));
+       return oper_p;
+}
+
+void
+free_oper_conf(struct oper_conf *oper_p)
+{
+       s_assert(oper_p != NULL);
+       if(oper_p == NULL)
+               return;
+
+       MyFree(oper_p->username);
+       MyFree(oper_p->host);
+       MyFree(oper_p->name);
+
+       if(oper_p->passwd)
+       {
+               memset(oper_p->passwd, 0, strlen(oper_p->passwd));
+               MyFree(oper_p->passwd);
+       }
+
+#ifdef HAVE_LIBCRYPTO
+       MyFree(oper_p->rsa_pubkey_file);
+
+       if(oper_p->rsa_pubkey)
+               RSA_free(oper_p->rsa_pubkey);
+#endif
+
+       MyFree(oper_p);
+}
+
+struct oper_conf *
+find_oper_conf(const char *username, const char *host, const char *locip, const char *name)
+{
+       struct oper_conf *oper_p;
+       struct irc_sockaddr_storage ip, cip;
+       char addr[HOSTLEN+1];
+       int bits, cbits;
+       dlink_node *ptr;
+
+       parse_netmask(locip, (struct sockaddr *)&cip, &cbits);
+
+       DLINK_FOREACH(ptr, oper_conf_list.head)
+       {
+               oper_p = ptr->data;
+
+               /* name/username doesnt match.. */
+               if(irccmp(oper_p->name, name) || !match(oper_p->username, username))
+                       continue;
+
+               strlcpy(addr, oper_p->host, sizeof(addr));
+
+               if(parse_netmask(addr, (struct sockaddr *)&ip, &bits) != HM_HOST)
+               {
+                       if(ip.ss_family == cip.ss_family &&
+                          comp_with_mask_sock((struct sockaddr *)&ip, (struct sockaddr *)&cip, bits))
+                               return oper_p;
+               }
+
+               /* we have to compare against the host as well, because its
+                * valid to set a spoof to an IP, which if we only compare
+                * in ip form to sockhost will not necessarily match --anfl
+                */
+               if(match(oper_p->host, host))
+                       return oper_p;
+       }
+
+       return NULL;
+}
+
+struct oper_flags
+{
+       int flag;
+       char has;
+       char hasnt;
+};
+static struct oper_flags oper_flagtable[] =
+{
+       { OPER_GLINE,           'G', 'g' },
+       { OPER_KLINE,           'K', 'k' },
+       { OPER_XLINE,           'X', 'x' },
+       { OPER_GLOBKILL,        'O', 'o' },
+       { OPER_LOCKILL,         'C', 'c' },
+       { OPER_REMOTE,          'R', 'r' },
+       { OPER_UNKLINE,         'U', 'u' },
+       { OPER_REHASH,          'H', 'h' },
+       { OPER_DIE,             'D', 'd' },
+       { OPER_ADMIN,           'A', 'a' },
+       { OPER_NICKS,           'N', 'n' },
+       { OPER_OPERWALL,        'L', 'l' },
+       { OPER_SPY,             'S', 's' },
+       { OPER_INVIS,           'P', 'p' },
+       { OPER_REMOTEBAN,       'B', 'b' },
+       { 0,                    '\0', '\0' }
+};
+
+const char *
+get_oper_privs(int flags)
+{
+       static char buf[20];
+       char *p;
+       int i;
+
+       p = buf;
+
+       for(i = 0; oper_flagtable[i].flag; i++)
+       {
+               if(flags & oper_flagtable[i].flag)
+                       *p++ = oper_flagtable[i].has;
+               else
+                       *p++ = oper_flagtable[i].hasnt;
+       }
+
+       *p = '\0';
+
+       return buf;
+}
+
+struct server_conf *
+make_server_conf(void)
+{
+       struct server_conf *server_p = MyMalloc(sizeof(struct server_conf));
+       server_p->aftype = AF_INET;
+       return server_p;
+}
+
+void
+free_server_conf(struct server_conf *server_p)
+{
+       s_assert(server_p != NULL);
+       if(server_p == NULL)
+               return;
+
+       if(!EmptyString(server_p->passwd))
+       {
+               memset(server_p->passwd, 0, strlen(server_p->passwd));
+               MyFree(server_p->passwd);
+       }
+
+       if(!EmptyString(server_p->spasswd))
+       {
+               memset(server_p->spasswd, 0, strlen(server_p->spasswd));
+               MyFree(server_p->spasswd);
+       }
+
+       MyFree(server_p->name);
+       MyFree(server_p->host);
+       MyFree(server_p->class_name);
+       MyFree(server_p);
+}
+
+void
+add_server_conf(struct server_conf *server_p)
+{
+       if(EmptyString(server_p->class_name))
+       {
+               DupString(server_p->class_name, "default");
+               server_p->class = default_class;
+               return;
+       }
+
+       server_p->class = find_class(server_p->class_name);
+
+       if(server_p->class == default_class)
+       {
+               conf_report_error("Warning connect::class invalid for %s",
+                               server_p->name);
+
+               MyFree(server_p->class_name);
+               DupString(server_p->class_name, "default");
+       }
+
+       if(strchr(server_p->host, '*') || strchr(server_p->host, '?'))
+               return;
+}
+
+struct server_conf *
+find_server_conf(const char *name)
+{
+       struct server_conf *server_p;
+       dlink_node *ptr;
+
+       DLINK_FOREACH(ptr, server_conf_list.head)
+       {
+               server_p = ptr->data;
+
+               if(ServerConfIllegal(server_p))
+                       continue;
+
+               if(match(name, server_p->name))
+                       return server_p;
+       }
+
+       return NULL;
+}
+
+void
+attach_server_conf(struct Client *client_p, struct server_conf *server_p)
+{
+       /* already have an attached conf */
+       if(client_p->localClient->att_sconf)
+       {
+               /* short circuit this special case :) */
+               if(client_p->localClient->att_sconf == server_p)
+                       return;
+
+               detach_server_conf(client_p);
+       }
+
+       CurrUsers(server_p->class)++;
+
+       client_p->localClient->att_sconf = server_p;
+       server_p->servers++;
+}
+
+void
+detach_server_conf(struct Client *client_p)
+{
+       struct server_conf *server_p = client_p->localClient->att_sconf;
+
+       if(server_p == NULL)
+               return;
+
+       client_p->localClient->att_sconf = NULL;
+       server_p->servers--;
+       CurrUsers(server_p->class)--;
+
+       if(ServerConfIllegal(server_p) && !server_p->servers)
+       {
+               /* the class this one is using may need destroying too */
+               if(MaxUsers(server_p->class) < 0 && CurrUsers(server_p->class) <= 0)
+                       free_class(server_p->class);
+
+               dlinkDelete(&server_p->node, &server_conf_list);
+               free_server_conf(server_p);
+       }
+}
+
+void
+set_server_conf_autoconn(struct Client *source_p, char *name, int newval)
+{
+       struct server_conf *server_p;
+
+       if((server_p = find_server_conf(name)) != NULL)
+       {
+               if(newval)
+                       server_p->flags |= SERVER_AUTOCONN;
+               else
+                       server_p->flags &= ~SERVER_AUTOCONN;
+
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                               "%s has changed AUTOCONN for %s to %i",
+                               get_oper_name(source_p), name, newval);
+       }
+       else
+               sendto_one(source_p, ":%s NOTICE %s :Can't find %s",
+                               me.name, source_p->name, name);
+}
+
+struct ConfItem *
+find_xline(const char *gecos, int counter)
+{
+       struct ConfItem *aconf;
+       dlink_node *ptr;
+
+       DLINK_FOREACH(ptr, xline_conf_list.head)
+       {
+               aconf = ptr->data;
+
+               if(match_esc(aconf->name, gecos))
+               {
+                       if(counter)
+                               aconf->port++;
+                       return aconf;
+               }
+       }
+
+       return NULL;
+}
+
+struct ConfItem *
+find_nick_resv(const char *name)
+{
+       struct ConfItem *aconf;
+       dlink_node *ptr;
+
+       DLINK_FOREACH(ptr, resv_conf_list.head)
+       {
+               aconf = ptr->data;
+
+               if(match_esc(aconf->name, name))
+               {
+                       aconf->port++;
+                       return aconf;
+               }
+       }
+
+       return NULL;
+}
+
+/* clean_resv_nick()
+ *
+ * inputs      - nick
+ * outputs     - 1 if nick is vaild resv, 0 otherwise
+ * side effects -
+ */
+int
+clean_resv_nick(const char *nick)
+{
+       char tmpch;
+       int as = 0;
+       int q = 0;
+       int ch = 0;
+
+       if(*nick == '-' || IsDigit(*nick))
+               return 0;
+
+       while ((tmpch = *nick++))
+       {
+               if(tmpch == '?' || tmpch == '@' || tmpch == '#')
+                       q++;
+               else if(tmpch == '*')
+                       as++;
+               else if(IsNickChar(tmpch))
+                       ch++;
+               else
+                       return 0;
+       }
+
+       if(!ch && as)
+               return 0;
+
+       return 1;
+}
+
+/* valid_wild_card_simple()
+ *
+ * inputs      - "thing" to test
+ * outputs     - 1 if enough wildcards, else 0
+ * side effects -
+ */
+int
+valid_wild_card_simple(const char *data)
+{
+       const char *p;
+       char tmpch;
+       int nonwild = 0;
+
+       /* check the string for minimum number of nonwildcard chars */
+       p = data;
+
+       while((tmpch = *p++))
+       {
+               /* found an escape, p points to the char after it, so skip
+                * that and move on.
+                */
+               if(tmpch == '\\')
+               {
+                       p++;
+               }
+               else if(!IsMWildChar(tmpch))
+               {
+                       /* if we have enough nonwildchars, return */
+                       if(++nonwild >= ConfigFileEntry.min_nonwildcard_simple)
+                               return 1;
+               }
+       }
+
+       return 0;
+}
+
+time_t
+valid_temp_time(const char *p)
+{
+       time_t result = 0;
+
+       while(*p)
+       {
+               if(IsDigit(*p))
+               {
+                       result *= 10;
+                       result += ((*p) & 0xF);
+                       p++;
+               }
+               else
+                       return -1;
+       }
+
+       if(result > (60 * 24 * 7 * 52))
+               result = (60 * 24 * 7 * 52);
+
+       return(result * 60);
+}
+
+static void
+expire_temp_rxlines(void *unused)
+{
+       struct ConfItem *aconf;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+       int i;
+
+       HASH_WALK_SAFE(i, R_MAX, ptr, next_ptr, resvTable)
+       {
+               aconf = ptr->data;
+
+               if(aconf->hold && aconf->hold <= CurrentTime)
+               {
+                       if(ConfigFileEntry.tkline_expire_notices)
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                               "Temporary RESV for [%s] expired",
+                                               aconf->name);
+
+                       free_conf(aconf);
+                       dlinkDestroy(ptr, &resvTable[i]);
+               }
+       }
+       HASH_WALK_END
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, resv_conf_list.head)
+       {
+               aconf = ptr->data;
+
+               if(aconf->hold && aconf->hold <= CurrentTime)
+               {
+                       if(ConfigFileEntry.tkline_expire_notices)
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                               "Temporary RESV for [%s] expired",
+                                               aconf->name);
+                       free_conf(aconf);
+                       dlinkDestroy(ptr, &resv_conf_list);
+               }
+       }
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, xline_conf_list.head)
+       {
+               aconf = ptr->data;
+
+               if(aconf->hold && aconf->hold <= CurrentTime)
+               {
+                       if(ConfigFileEntry.tkline_expire_notices)
+                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                               "Temporary X-line for [%s] expired",
+                                               aconf->name);
+                       free_conf(aconf);
+                       dlinkDestroy(ptr, &xline_conf_list);
+               }
+       }
+}
+
+unsigned long
+get_nd_count(void)
+{
+       return(dlink_list_length(&nd_list));
+}
+
+
+void
+add_nd_entry(const char *name)
+{
+       struct nd_entry *nd;
+
+       if(hash_find_nd(name) != NULL)
+               return;
+
+       nd = BlockHeapAlloc(nd_heap);
+       
+       strlcpy(nd->name, name, sizeof(nd->name));
+       nd->expire = CurrentTime + ConfigFileEntry.nick_delay;
+
+       /* this list is ordered */
+       dlinkAddTail(nd, &nd->lnode, &nd_list);
+       add_to_nd_hash(name, nd);
+}
+
+void
+free_nd_entry(struct nd_entry *nd)
+{
+       dlinkDelete(&nd->lnode, &nd_list);
+       dlinkDelete(&nd->hnode, &ndTable[nd->hashv]);
+       BlockHeapFree(nd_heap, nd);
+}
+
+void
+expire_nd_entries(void *unused)
+{
+       struct nd_entry *nd;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, nd_list.head)
+       {
+               nd = ptr->data;
+
+               /* this list is ordered - we can stop when we hit the first
+                * entry that doesnt expire..
+                */
+               if(nd->expire > CurrentTime)
+                       return;
+
+               free_nd_entry(nd);
+       }
+}
+
+void
+add_tgchange(const char *host)
+{
+       tgchange *target;
+       patricia_node_t *pnode;
+
+       if(find_tgchange(host))
+               return;
+
+       target = MyMalloc(sizeof(tgchange));
+       pnode = make_and_lookup(tgchange_tree, host);
+
+       pnode->data = target;
+       target->pnode = pnode;
+
+       DupString(target->ip, host);
+       target->expiry = CurrentTime + (60*60*12);
+
+       dlinkAdd(target, &target->node, &tgchange_list);
+}
+
+tgchange *
+find_tgchange(const char *host)
+{
+       patricia_node_t *pnode;
+
+       if((pnode = match_exact_string(tgchange_tree, host)))
+               return pnode->data;
+
+       return NULL;
+}
+
diff --git a/src/s_serv.c b/src/s_serv.c
new file mode 100644 (file)
index 0000000..e4869dc
--- /dev/null
@@ -0,0 +1,1812 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  s_serv.c: Server related functions.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: s_serv.c 2723 2006-11-09 23:35:48Z jilles $
+ */
+
+#include "stdinc.h"
+
+#ifdef HAVE_LIBCRYPTO
+#include <openssl/rsa.h>
+#endif
+
+#include "tools.h"
+#include "s_serv.h"
+#include "class.h"
+#include "client.h"
+#include "common.h"
+#include "event.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "ircd_defs.h"
+#include "numeric.h"
+#include "packet.h"
+#include "res.h"
+#include "commio.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "s_log.h"
+#include "s_stats.h"
+#include "s_user.h"
+#include "scache.h"
+#include "send.h"
+#include "client.h"
+#include "memory.h"
+#include "channel.h"           /* chcap_usage_counts stuff... */
+#include "hook.h"
+#include "msg.h"
+
+extern char *crypt();
+
+#ifndef INADDR_NONE
+#define INADDR_NONE ((unsigned int) 0xffffffff)
+#endif
+
+#ifndef HAVE_SOCKETPAIR
+static int inet_socketpair(int d, int type, int protocol, int sv[2]);
+#endif
+
+int MaxConnectionCount = 1;
+int MaxClientCount = 1;
+int refresh_user_links = 0;
+
+static char buf[BUFSIZE];
+
+static void start_io(struct Client *server);
+
+static SlinkRplHnd slink_error;
+static SlinkRplHnd slink_zipstats;
+/*
+ * list of recognized server capabilities.  "TS" is not on the list
+ * because all servers that we talk to already do TS, and the kludged
+ * extra argument to "PASS" takes care of checking that.  -orabidoo
+ */
+struct Capability captab[] = {
+/*  name     cap     */
+       { "QS",         CAP_QS },
+       { "EX",         CAP_EX },
+       { "CHW",        CAP_CHW},
+       { "IE",         CAP_IE},
+       { "KLN",        CAP_KLN},
+       { "GLN",        CAP_GLN},
+       { "KNOCK",      CAP_KNOCK},
+       { "ZIP",        CAP_ZIP},
+       { "TB",         CAP_TB},
+       { "UNKLN",      CAP_UNKLN},
+       { "CLUSTER",    CAP_CLUSTER},
+       { "ENCAP",      CAP_ENCAP },
+       { "SERVICES",   CAP_SERVICE },
+       { "RSFNC",      CAP_RSFNC },
+       { "SAVE",       CAP_SAVE },
+       { "EUID",       CAP_EUID },
+       {0, 0}
+};
+
+struct SlinkRplDef slinkrpltab[] = {
+       {SLINKRPL_ERROR, slink_error, SLINKRPL_FLAG_DATA},
+       {SLINKRPL_ZIPSTATS, slink_zipstats, SLINKRPL_FLAG_DATA},
+       {0, 0, 0},
+};
+
+static int fork_server(struct Client *client_p);
+
+static CNCB serv_connect_callback;
+
+void
+slink_error(unsigned int rpl, unsigned int len, unsigned char *data, struct Client *server_p)
+{
+       char squitreason[256];
+
+       s_assert(rpl == SLINKRPL_ERROR);
+
+       s_assert(len < 256);
+       data[len - 1] = '\0';
+
+       sendto_realops_snomask(SNO_GENERAL, L_ALL, "SlinkError for %s: %s", server_p->name, data);
+       snprintf(squitreason, sizeof squitreason, "servlink error: %s", data);
+       exit_client(server_p, server_p, &me, squitreason);
+}
+
+void
+slink_zipstats(unsigned int rpl, unsigned int len, unsigned char *data, struct Client *server_p)
+{
+       struct ZipStats zipstats;
+       u_int32_t in = 0, in_wire = 0, out = 0, out_wire = 0;
+       int i = 0;
+
+       s_assert(rpl == SLINKRPL_ZIPSTATS);
+       s_assert(len == 16);
+       s_assert(IsCapable(server_p, CAP_ZIP));
+
+       /* Yes, it needs to be done this way, no we cannot let the compiler
+        * work with the pointer to the structure.  This works around a GCC
+        * bug on SPARC that affects all versions at the time of this writing.
+        * I will feed you to the creatures living in RMS's beard if you do
+        * not leave this as is, without being sure that you are not causing
+        * regression for most of our installed SPARC base.
+        * -jmallett, 04/27/2002
+        */
+       memcpy(&zipstats, &server_p->localClient->zipstats, sizeof(struct ZipStats));
+
+       in |= (data[i++] << 24);
+       in |= (data[i++] << 16);
+       in |= (data[i++] << 8);
+       in |= (data[i++]);
+
+       in_wire |= (data[i++] << 24);
+       in_wire |= (data[i++] << 16);
+       in_wire |= (data[i++] << 8);
+       in_wire |= (data[i++]);
+
+       out |= (data[i++] << 24);
+       out |= (data[i++] << 16);
+       out |= (data[i++] << 8);
+       out |= (data[i++]);
+
+       out_wire |= (data[i++] << 24);
+       out_wire |= (data[i++] << 16);
+       out_wire |= (data[i++] << 8);
+       out_wire |= (data[i++]);
+
+       zipstats.in += in;
+       zipstats.inK += zipstats.in >> 10;
+       zipstats.in &= 0x03ff;
+
+       zipstats.in_wire += in_wire;
+       zipstats.inK_wire += zipstats.in_wire >> 10;
+       zipstats.in_wire &= 0x03ff;
+
+       zipstats.out += out;
+       zipstats.outK += zipstats.out >> 10;
+       zipstats.out &= 0x03ff;
+
+       zipstats.out_wire += out_wire;
+       zipstats.outK_wire += zipstats.out_wire >> 10;
+       zipstats.out_wire &= 0x03ff;
+
+       if(zipstats.inK > 0)
+               zipstats.in_ratio =
+                       (((double) (zipstats.inK - zipstats.inK_wire) /
+                         (double) zipstats.inK) * 100.00);
+       else
+               zipstats.in_ratio = 0;
+
+       if(zipstats.outK > 0)
+               zipstats.out_ratio =
+                       (((double) (zipstats.outK - zipstats.outK_wire) /
+                         (double) zipstats.outK) * 100.00);
+       else
+               zipstats.out_ratio = 0;
+
+       memcpy(&server_p->localClient->zipstats, &zipstats, sizeof(struct ZipStats));
+}
+
+void
+collect_zipstats(void *unused)
+{
+       dlink_node *ptr;
+       struct Client *target_p;
+
+       DLINK_FOREACH(ptr, serv_list.head)
+       {
+               target_p = ptr->data;
+               if(IsCapable(target_p, CAP_ZIP))
+               {
+                       /* only bother if we haven't already got something queued... */
+                       if(!target_p->localClient->slinkq)
+                       {
+                               target_p->localClient->slinkq = MyMalloc(1);    /* sigh.. */
+                               target_p->localClient->slinkq[0] = SLINKCMD_ZIPSTATS;
+                               target_p->localClient->slinkq_ofs = 0;
+                               target_p->localClient->slinkq_len = 1;
+                               send_queued_slink_write(target_p->localClient->ctrlfd, target_p);
+                       }
+               }
+       }
+}
+
+/*
+ * hunt_server - Do the basic thing in delivering the message (command)
+ *      across the relays to the specific server (server) for
+ *      actions.
+ *
+ *      Note:   The command is a format string and *MUST* be
+ *              of prefixed style (e.g. ":%s COMMAND %s ...").
+ *              Command can have only max 8 parameters.
+ *
+ *      server  parv[server] is the parameter identifying the
+ *              target server.
+ *
+ *      *WARNING*
+ *              parv[server] is replaced with the pointer to the
+ *              real servername from the matched client (I'm lazy
+ *              now --msa).
+ *
+ *      returns: (see #defines)
+ */
+int
+hunt_server(struct Client *client_p, struct Client *source_p,
+           const char *command, int server, int parc, const char *parv[])
+{
+       struct Client *target_p;
+       int wilds;
+       dlink_node *ptr;
+       const char *old;
+       char *new;
+
+       /*
+        * Assume it's me, if no server
+        */
+       if(parc <= server || EmptyString(parv[server]) ||
+          match(me.name, parv[server]) || match(parv[server], me.name) ||
+          (strcmp(parv[server], me.id) == 0))
+               return (HUNTED_ISME);
+       
+       new = LOCAL_COPY(parv[server]);
+
+       /*
+        * These are to pickup matches that would cause the following
+        * message to go in the wrong direction while doing quick fast
+        * non-matching lookups.
+        */
+       if(MyClient(source_p))
+               target_p = find_named_client(new);
+       else
+               target_p = find_client(new);
+
+       if(target_p)
+               if(target_p->from == source_p->from && !MyConnect(target_p))
+                       target_p = NULL;
+
+       if(target_p == NULL && (target_p = find_server(source_p, new)))
+               if(target_p->from == source_p->from && !MyConnect(target_p))
+                       target_p = NULL;
+
+       collapse(new);
+       wilds = (strchr(new, '?') || strchr(new, '*'));
+
+       /*
+        * Again, if there are no wild cards involved in the server
+        * name, use the hash lookup
+        */
+       if(!target_p)
+       {
+               if(!wilds)
+               {
+                       if(MyClient(source_p) || !IsDigit(parv[server][0]))
+                               sendto_one_numeric(source_p, ERR_NOSUCHSERVER,
+                                                  form_str(ERR_NOSUCHSERVER),
+                                                  parv[server]);
+                       return (HUNTED_NOSUCH);
+               }
+               else
+               {
+                       target_p = NULL;
+
+                       DLINK_FOREACH(ptr, global_client_list.head)
+                       {
+                               if(match(new, ((struct Client *) (ptr->data))->name))
+                               {
+                                       target_p = ptr->data;
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       if(target_p)
+       {
+               if(!IsRegistered(target_p))
+               {
+                       sendto_one_numeric(source_p, ERR_NOSUCHSERVER,
+                                          form_str(ERR_NOSUCHSERVER),
+                                          parv[server]);
+                       return HUNTED_NOSUCH;
+               }
+
+               if(IsMe(target_p) || MyClient(target_p))
+                       return HUNTED_ISME;
+
+               old = parv[server];
+               parv[server] = get_id(target_p, target_p);
+
+               sendto_one(target_p, command, get_id(source_p, target_p),
+                          parv[1], parv[2], parv[3], parv[4], parv[5], parv[6], parv[7], parv[8]);
+               parv[server] = old;
+               return (HUNTED_PASS);
+       }
+
+       if(!IsDigit(parv[server][0]))
+               sendto_one_numeric(source_p, ERR_NOSUCHSERVER,
+                                  form_str(ERR_NOSUCHSERVER), parv[server]);
+       return (HUNTED_NOSUCH);
+}
+
+/*
+ * try_connections - scan through configuration and try new connections.
+ * Returns the calendar time when the next call to this
+ * function should be made latest. (No harm done if this
+ * is called earlier or later...)
+ */
+void
+try_connections(void *unused)
+{
+       struct Client *client_p;
+       struct server_conf *server_p = NULL;
+       struct server_conf *tmp_p;
+       struct Class *cltmp;
+       dlink_node *ptr;
+       int connecting = FALSE;
+       int confrq = 0;
+       time_t next = 0;
+
+       DLINK_FOREACH(ptr, server_conf_list.head)
+       {
+               tmp_p = ptr->data;
+
+               if(ServerConfIllegal(tmp_p) || !ServerConfAutoconn(tmp_p))
+                       continue;
+
+               cltmp = tmp_p->class;
+
+               /*
+                * Skip this entry if the use of it is still on hold until
+                * future. Otherwise handle this entry (and set it on hold
+                * until next time). Will reset only hold times, if already
+                * made one successfull connection... [this algorithm is
+                * a bit fuzzy... -- msa >;) ]
+                */
+               if(tmp_p->hold > CurrentTime)
+               {
+                       if(next > tmp_p->hold || next == 0)
+                               next = tmp_p->hold;
+                       continue;
+               }
+
+               confrq = get_con_freq(cltmp);
+               tmp_p->hold = CurrentTime + confrq;
+
+               /*
+                * Found a CONNECT config with port specified, scan clients
+                * and see if this server is already connected?
+                */
+               client_p = find_server(NULL, tmp_p->name);
+
+               if(!client_p && (CurrUsers(cltmp) < MaxUsers(cltmp)) && !connecting)
+               {
+                       server_p = tmp_p;
+
+                       /* We connect only one at time... */
+                       connecting = TRUE;
+               }
+
+               if((next > tmp_p->hold) || (next == 0))
+                       next = tmp_p->hold;
+       }
+
+       /* TODO: change this to set active flag to 0 when added to event! --Habeeb */
+       if(GlobalSetOptions.autoconn == 0)
+               return;
+
+       if(!connecting)
+               return;
+
+       /* move this connect entry to end.. */
+       dlinkDelete(&server_p->node, &server_conf_list);
+       dlinkAddTail(server_p, &server_p->node, &server_conf_list);
+
+       /*
+        * We used to only print this if serv_connect() actually
+        * suceeded, but since comm_tcp_connect() can call the callback
+        * immediately if there is an error, we were getting error messages
+        * in the wrong order. SO, we just print out the activated line,
+        * and let serv_connect() / serv_connect_callback() print an
+        * error afterwards if it fails.
+        *   -- adrian
+        */
+#ifndef HIDE_SERVERS_IPS
+       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                       "Connection to %s[%s] activated.",
+                       server_p->name, server_p->host);
+#else
+       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                       "Connection to %s activated",
+                       server_p->name);
+#endif
+
+       serv_connect(server_p, 0);
+}
+
+int
+check_server(const char *name, struct Client *client_p)
+{
+       struct server_conf *server_p = NULL;
+       struct server_conf *tmp_p;
+       dlink_node *ptr;
+       int error = -1;
+
+       s_assert(NULL != client_p);
+       if(client_p == NULL)
+               return error;
+
+       if(!(client_p->localClient->passwd))
+               return -2;
+
+       if(strlen(name) > HOSTLEN)
+               return -4;
+
+       DLINK_FOREACH(ptr, server_conf_list.head)
+       {
+               tmp_p = ptr->data;
+
+               if(ServerConfIllegal(tmp_p))
+                       continue;
+
+               if(!match(tmp_p->name, name))
+                       continue;
+
+               error = -3;
+
+               /* XXX: Fix me for IPv6 */
+               /* XXX sockhost is the IPv4 ip as a string */
+               if(match(tmp_p->host, client_p->host) ||
+                  match(tmp_p->host, client_p->sockhost))
+               {
+                       error = -2;
+
+                       if(ServerConfEncrypted(tmp_p))
+                       {
+                               if(!strcmp(tmp_p->passwd, crypt(client_p->localClient->passwd,
+                                                               tmp_p->passwd)))
+                               {
+                                       server_p = tmp_p;
+                                       break;
+                               }
+                       }
+                       else if(!strcmp(tmp_p->passwd, client_p->localClient->passwd))
+                       {
+                               server_p = tmp_p;
+                               break;
+                       }
+               }
+       }
+
+       if(server_p == NULL)
+               return error;
+
+       attach_server_conf(client_p, server_p);
+
+       /* clear ZIP/TB if they support but we dont want them */
+#ifdef HAVE_LIBZ
+       if(!ServerConfCompressed(server_p))
+#endif
+               ClearCap(client_p, CAP_ZIP);
+
+       if(!ServerConfTb(server_p))
+               ClearCap(client_p, CAP_TB);
+
+       return 0;
+}
+
+/*
+ * send_capabilities
+ *
+ * inputs      - Client pointer to send to
+ *             - int flag of capabilities that this server has
+ * output      - NONE
+ * side effects        - send the CAPAB line to a server  -orabidoo
+ *
+ */
+void
+send_capabilities(struct Client *client_p, int cap_can_send)
+{
+       struct Capability *cap;
+       char msgbuf[BUFSIZE];
+       char *t;
+       int tl;
+
+       t = msgbuf;
+
+       for (cap = captab; cap->name; ++cap)
+       {
+               if(cap->cap & cap_can_send)
+               {
+                       tl = ircsprintf(t, "%s ", cap->name);
+                       t += tl;
+               }
+       }
+
+       t--;
+       *t = '\0';
+
+       sendto_one(client_p, "CAPAB :%s", msgbuf);
+}
+
+/* burst_modes_TS5()
+ *
+ * input       - client to burst to, channel name, list to burst, mode flag
+ * output      -
+ * side effects - client is sent a list of +b, or +e, or +I modes
+ */
+static void
+burst_modes_TS5(struct Client *client_p, char *chname, dlink_list *list, char flag)
+{
+       dlink_node *ptr;
+       struct Ban *banptr;
+       char mbuf[MODEBUFLEN];
+       char pbuf[BUFSIZE];
+       int tlen;
+       int mlen;
+       int cur_len;
+       char *mp;
+       char *pp;
+       int count = 0;
+
+       mlen = ircsprintf(buf, ":%s MODE %s +", me.name, chname);
+       cur_len = mlen;
+
+       mp = mbuf;
+       pp = pbuf;
+
+       DLINK_FOREACH(ptr, list->head)
+       {
+               banptr = ptr->data;
+               tlen = strlen(banptr->banstr) + 3;
+
+               /* uh oh */
+               if(tlen > MODEBUFLEN)
+                       continue;
+
+               if((count >= MAXMODEPARAMS) || ((cur_len + tlen + 2) > (BUFSIZE - 3)))
+               {
+                       sendto_one(client_p, "%s%s %s", buf, mbuf, pbuf);
+
+                       mp = mbuf;
+                       pp = pbuf;
+                       cur_len = mlen;
+                       count = 0;
+               }
+
+               *mp++ = flag;
+               *mp = '\0';
+               pp += ircsprintf(pp, "%s ", banptr->banstr);
+               cur_len += tlen;
+               count++;
+       }
+
+       if(count != 0)
+               sendto_one(client_p, "%s%s %s", buf, mbuf, pbuf);
+}
+
+/* burst_modes_TS6()
+ *
+ * input       - client to burst to, channel name, list to burst, mode flag
+ * output      -
+ * side effects - client is sent a list of +b, +e, or +I modes
+ */
+static void
+burst_modes_TS6(struct Client *client_p, struct Channel *chptr, 
+               dlink_list *list, char flag)
+{
+       dlink_node *ptr;
+       struct Ban *banptr;
+       char *t;
+       int tlen;
+       int mlen;
+       int cur_len;
+
+       cur_len = mlen = ircsprintf(buf, ":%s BMASK %ld %s %c :",
+                                   me.id, (long) chptr->channelts, chptr->chname, flag);
+       t = buf + mlen;
+
+       DLINK_FOREACH(ptr, list->head)
+       {
+               banptr = ptr->data;
+
+               tlen = strlen(banptr->banstr) + 1;
+
+               /* uh oh */
+               if(cur_len + tlen > BUFSIZE - 3)
+               {
+                       /* the one we're trying to send doesnt fit at all! */
+                       if(cur_len == mlen)
+                       {
+                               s_assert(0);
+                               continue;
+                       }
+
+                       /* chop off trailing space and send.. */
+                       *(t-1) = '\0';
+                       sendto_one(client_p, "%s", buf);
+                       cur_len = mlen;
+                       t = buf + mlen;
+               }
+
+               ircsprintf(t, "%s ", banptr->banstr);
+               t += tlen;
+               cur_len += tlen;
+       }
+
+       /* cant ever exit the loop above without having modified buf,
+        * chop off trailing space and send.
+        */
+       *(t-1) = '\0';
+       sendto_one(client_p, "%s", buf);
+}
+
+/*
+ * burst_TS5
+ * 
+ * inputs      - client (server) to send nick towards
+ *             - client to send nick for
+ * output      - NONE
+ * side effects        - NICK message is sent towards given client_p
+ */
+static void
+burst_TS5(struct Client *client_p)
+{
+       static char ubuf[12];
+       struct Client *target_p;
+       struct Channel *chptr;
+       struct membership *msptr;
+       hook_data_client hclientinfo;
+       hook_data_channel hchaninfo;
+       dlink_node *ptr;
+       dlink_node *uptr;
+       char *t;
+       int tlen, mlen;
+       int cur_len = 0;
+
+       hclientinfo.client = hchaninfo.client = client_p;
+
+       DLINK_FOREACH(ptr, global_client_list.head)
+       {
+               target_p = ptr->data;
+
+               if(!IsPerson(target_p))
+                       continue;
+
+               send_umode(NULL, target_p, 0, 0, ubuf);
+               if(!*ubuf)
+               {
+                       ubuf[0] = '+';
+                       ubuf[1] = '\0';
+               }
+
+               sendto_one(client_p, "NICK %s %d %ld %s %s %s %s :%s",
+                          target_p->name, target_p->hopcount + 1,
+                          (long) target_p->tsinfo, ubuf,
+                          target_p->username, target_p->host,
+                          target_p->user->server, target_p->info);
+
+               if(IsDynSpoof(target_p))
+                       sendto_one(client_p, ":%s ENCAP * REALHOST %s",
+                                       target_p->name, target_p->orighost);
+               if(!EmptyString(target_p->user->suser))
+                       sendto_one(client_p, ":%s ENCAP * LOGIN %s",
+                                       target_p->name, target_p->user->suser);
+
+               if(ConfigFileEntry.burst_away && !EmptyString(target_p->user->away))
+                       sendto_one(client_p, ":%s AWAY :%s",
+                                  target_p->name, target_p->user->away);
+
+               hclientinfo.target = target_p;
+               call_hook(h_burst_client, &hclientinfo);
+       }
+
+       DLINK_FOREACH(ptr, global_channel_list.head)
+       {
+               chptr = ptr->data;
+
+               if(*chptr->chname != '#')
+                       continue;
+
+               cur_len = mlen = ircsprintf(buf, ":%s SJOIN %ld %s %s :", me.name,
+                               (long) chptr->channelts, chptr->chname, 
+                               channel_modes(chptr, client_p));
+
+               t = buf + mlen;
+
+               DLINK_FOREACH(uptr, chptr->members.head)
+               {
+                       msptr = uptr->data;
+
+                       tlen = strlen(msptr->client_p->name) + 1;
+                       if(is_chanop(msptr))
+                               tlen++;
+                       if(is_voiced(msptr))
+                               tlen++;
+
+                       if(cur_len + tlen >= BUFSIZE - 3)
+                       {
+                               t--;
+                               *t = '\0';
+                               sendto_one(client_p, "%s", buf);
+                               cur_len = mlen;
+                               t = buf + mlen;
+                       }
+
+                       ircsprintf(t, "%s%s ", find_channel_status(msptr, 1), 
+                                  msptr->client_p->name);
+
+                       cur_len += tlen;
+                       t += tlen;
+               }
+
+               if (dlink_list_length(&chptr->members) > 0)
+               {
+                       /* remove trailing space */
+                       t--;
+                       *t = '\0';
+               }
+               sendto_one(client_p, "%s", buf);
+
+               burst_modes_TS5(client_p, chptr->chname, &chptr->banlist, 'b');
+
+               if(IsCapable(client_p, CAP_EX))
+                       burst_modes_TS5(client_p, chptr->chname, &chptr->exceptlist, 'e');
+
+               if(IsCapable(client_p, CAP_IE))
+                       burst_modes_TS5(client_p, chptr->chname, &chptr->invexlist, 'I');
+
+               burst_modes_TS5(client_p, chptr->chname, &chptr->quietlist, 'q');
+
+               if(IsCapable(client_p, CAP_TB) && chptr->topic != NULL)
+                       sendto_one(client_p, ":%s TB %s %ld %s%s:%s",
+                                  me.name, chptr->chname, (long) chptr->topic_time,
+                                  ConfigChannel.burst_topicwho ? chptr->topic_info : "",
+                                  ConfigChannel.burst_topicwho ? " " : "",
+                                  chptr->topic);
+
+               hchaninfo.chptr = chptr;
+               call_hook(h_burst_channel, &hchaninfo);
+       }
+
+       hclientinfo.target = NULL;
+       call_hook(h_burst_finished, &hclientinfo);
+}
+
+/*
+ * burst_TS6
+ * 
+ * inputs      - client (server) to send nick towards
+ *             - client to send nick for
+ * output      - NONE
+ * side effects        - NICK message is sent towards given client_p
+ */
+static void
+burst_TS6(struct Client *client_p)
+{
+       static char ubuf[12];
+       struct Client *target_p;
+       struct Channel *chptr;
+       struct membership *msptr;
+       hook_data_client hclientinfo;
+       hook_data_channel hchaninfo;
+       dlink_node *ptr;
+       dlink_node *uptr;
+       char *t;
+       int tlen, mlen;
+       int cur_len = 0;
+
+       hclientinfo.client = hchaninfo.client = client_p;
+
+       DLINK_FOREACH(ptr, global_client_list.head)
+       {
+               target_p = ptr->data;
+
+               if(!IsPerson(target_p))
+                       continue;
+
+               send_umode(NULL, target_p, 0, 0, ubuf);
+               if(!*ubuf)
+               {
+                       ubuf[0] = '+';
+                       ubuf[1] = '\0';
+               }
+
+               if(has_id(target_p) && IsCapable(client_p, CAP_EUID))
+                       sendto_one(client_p, ":%s EUID %s %d %ld %s %s %s %s %s %s %s :%s",
+                                  target_p->servptr->id, target_p->name,
+                                  target_p->hopcount + 1, 
+                                  (long) target_p->tsinfo, ubuf,
+                                  target_p->username, target_p->host,
+                                  IsIPSpoof(target_p) ? "0" : target_p->sockhost,
+                                  target_p->id,
+                                  IsDynSpoof(target_p) ? target_p->orighost : "*",
+                                  EmptyString(target_p->user->suser) ? "*" : target_p->user->suser,
+                                  target_p->info);
+               else if(has_id(target_p))
+                       sendto_one(client_p, ":%s UID %s %d %ld %s %s %s %s %s :%s",
+                                  target_p->servptr->id, target_p->name,
+                                  target_p->hopcount + 1, 
+                                  (long) target_p->tsinfo, ubuf,
+                                  target_p->username, target_p->host,
+                                  IsIPSpoof(target_p) ? "0" : target_p->sockhost,
+                                  target_p->id, target_p->info);
+               else
+                       sendto_one(client_p, "NICK %s %d %ld %s %s %s %s :%s",
+                                       target_p->name,
+                                       target_p->hopcount + 1,
+                                       (long) target_p->tsinfo,
+                                       ubuf,
+                                       target_p->username, target_p->host,
+                                       target_p->user->server, target_p->info);
+
+               if(!has_id(target_p) || !IsCapable(client_p, CAP_EUID))
+               {
+                       if(IsDynSpoof(target_p))
+                               sendto_one(client_p, ":%s ENCAP * REALHOST %s",
+                                               use_id(target_p), target_p->orighost);
+                       if(!EmptyString(target_p->user->suser))
+                               sendto_one(client_p, ":%s ENCAP * LOGIN %s",
+                                               use_id(target_p), target_p->user->suser);
+               }
+
+               if(ConfigFileEntry.burst_away && !EmptyString(target_p->user->away))
+                       sendto_one(client_p, ":%s AWAY :%s",
+                                  use_id(target_p),
+                                  target_p->user->away);
+
+               hclientinfo.target = target_p;
+               call_hook(h_burst_client, &hclientinfo);
+       }
+
+       DLINK_FOREACH(ptr, global_channel_list.head)
+       {
+               chptr = ptr->data;
+
+               if(*chptr->chname != '#')
+                       continue;
+
+               cur_len = mlen = ircsprintf(buf, ":%s SJOIN %ld %s %s :", me.id,
+                               (long) chptr->channelts, chptr->chname,
+                               channel_modes(chptr, client_p));
+
+               t = buf + mlen;
+
+               DLINK_FOREACH(uptr, chptr->members.head)
+               {
+                       msptr = uptr->data;
+
+                       tlen = strlen(use_id(msptr->client_p)) + 1;
+                       if(is_chanop(msptr))
+                               tlen++;
+                       if(is_voiced(msptr))
+                               tlen++;
+
+                       if(cur_len + tlen >= BUFSIZE - 3)
+                       {
+                               *(t-1) = '\0';
+                               sendto_one(client_p, "%s", buf);
+                               cur_len = mlen;
+                               t = buf + mlen;
+                       }
+
+                       ircsprintf(t, "%s%s ", find_channel_status(msptr, 1), 
+                                  use_id(msptr->client_p));
+
+                       cur_len += tlen;
+                       t += tlen;
+               }
+
+               if (dlink_list_length(&chptr->members) > 0)
+               {
+                       /* remove trailing space */
+                       *(t-1) = '\0';
+               }
+               sendto_one(client_p, "%s", buf);
+
+               if(dlink_list_length(&chptr->banlist) > 0)
+                       burst_modes_TS6(client_p, chptr, &chptr->banlist, 'b');
+
+               if(IsCapable(client_p, CAP_EX) &&
+                  dlink_list_length(&chptr->exceptlist) > 0)
+                       burst_modes_TS6(client_p, chptr, &chptr->exceptlist, 'e');
+
+               if(IsCapable(client_p, CAP_IE) &&
+                  dlink_list_length(&chptr->invexlist) > 0)
+                       burst_modes_TS6(client_p, chptr, &chptr->invexlist, 'I');
+
+               if(dlink_list_length(&chptr->quietlist) > 0)
+                       burst_modes_TS6(client_p, chptr, &chptr->quietlist, 'q');
+
+               if(IsCapable(client_p, CAP_TB) && chptr->topic != NULL)
+                       sendto_one(client_p, ":%s TB %s %ld %s%s:%s",
+                                  me.id, chptr->chname, (long) chptr->topic_time,
+                                  ConfigChannel.burst_topicwho ? chptr->topic_info : "",
+                                  ConfigChannel.burst_topicwho ? " " : "",
+                                  chptr->topic);
+
+               hchaninfo.chptr = chptr;
+               call_hook(h_burst_channel, &hchaninfo);
+       }
+
+       hclientinfo.target = NULL;
+       call_hook(h_burst_finished, &hclientinfo);
+}
+
+/*
+ * show_capabilities - show current server capabilities
+ *
+ * inputs       - pointer to an struct Client
+ * output       - pointer to static string
+ * side effects - build up string representing capabilities of server listed
+ */
+const char *
+show_capabilities(struct Client *target_p)
+{
+       static char msgbuf[BUFSIZE];
+       struct Capability *cap;
+       char *t;
+       int tl;
+
+       t = msgbuf;
+       tl = ircsprintf(msgbuf, "TS ");
+       t += tl;
+
+       if(!IsServer(target_p) || !target_p->serv->caps)        /* short circuit if no caps */
+       {
+               msgbuf[2] = '\0';
+               return msgbuf;
+       }
+
+       for (cap = captab; cap->cap; ++cap)
+       {
+               if(cap->cap & target_p->serv->caps)
+               {
+                       tl = ircsprintf(t, "%s ", cap->name);
+                       t += tl;
+               }
+       }
+
+       t--;
+       *t = '\0';
+
+       return msgbuf;
+}
+
+/*
+ * server_estab
+ *
+ * inputs       - pointer to a struct Client
+ * output       -
+ * side effects -
+ */
+int
+server_estab(struct Client *client_p)
+{
+       struct Client *target_p;
+       struct server_conf *server_p;
+       hook_data_client hdata;
+       char *host;
+       dlink_node *ptr;
+
+       s_assert(NULL != client_p);
+       if(client_p == NULL)
+               return -1;
+       ClearAccess(client_p);
+
+       host = client_p->name;
+
+       if((server_p = client_p->localClient->att_sconf) == NULL)
+       {
+               /* This shouldn't happen, better tell the ops... -A1kmm */
+               sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) ? L_NETWIDE : L_ALL,
+                                    "Warning: Lost connect{} block for server %s!", host);
+               return exit_client(client_p, client_p, client_p, "Lost connect{} block!");
+       }
+
+       /* We shouldn't have to check this, it should already done before
+        * server_estab is called. -A1kmm
+        */
+       if(client_p->localClient->passwd)
+       {
+               memset(client_p->localClient->passwd, 0, strlen(client_p->localClient->passwd));
+               MyFree(client_p->localClient->passwd);
+               client_p->localClient->passwd = NULL;
+       }
+
+       /* Its got identd , since its a server */
+       SetGotId(client_p);
+
+       /* If there is something in the serv_list, it might be this
+        * connecting server..
+        */
+       if(!ServerInfo.hub && serv_list.head)
+       {
+               if(client_p != serv_list.head->data || serv_list.head->next)
+               {
+                       ServerStats->is_ref++;
+                       sendto_one(client_p, "ERROR :I'm a leaf not a hub");
+                       return exit_client(client_p, client_p, client_p, "I'm a leaf");
+               }
+       }
+
+       if(IsUnknown(client_p))
+       {
+               /*
+                * jdc -- 1.  Use EmptyString(), not [0] index reference.
+                *        2.  Check ->spasswd, not ->passwd.
+                */
+               if(!EmptyString(server_p->spasswd))
+               {
+                       /* kludge, if we're not using TS6, dont ever send
+                        * ourselves as being TS6 capable.
+                        */
+                       if(ServerInfo.use_ts6)
+                               sendto_one(client_p, "PASS %s TS %d :%s", 
+                                          server_p->spasswd, TS_CURRENT, me.id);
+                       else
+                               sendto_one(client_p, "PASS %s :TS",
+                                          server_p->spasswd);
+               }
+
+               /* pass info to new server */
+               send_capabilities(client_p, default_server_capabs
+                                 | (ServerConfCompressed(server_p) ? CAP_ZIP_SUPPORTED : 0)
+                                 | (ServerConfTb(server_p) ? CAP_TB : 0));
+
+               sendto_one(client_p, "SERVER %s 1 :%s%s",
+                          me.name,
+                          ConfigServerHide.hidden ? "(H) " : "",
+                          (me.info[0]) ? (me.info) : "IRCers United");
+       }
+
+       if(!comm_set_buffers(client_p->localClient->fd, READBUF_SIZE))
+               report_error(SETBUF_ERROR_MSG, 
+                            get_server_name(client_p, SHOW_IP), 
+                            log_client_name(client_p, SHOW_IP), errno);
+
+       /* Hand the server off to servlink now */
+       if(IsCapable(client_p, CAP_ZIP))
+       {
+               if(fork_server(client_p) < 0)
+               {
+                       sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) ? L_NETWIDE : L_ALL,
+                                            "Warning: fork failed for server %s -- check servlink_path (%s)",
+                                            get_server_name(client_p, HIDE_IP),
+                                            ConfigFileEntry.servlink_path);
+                       return exit_client(client_p, client_p, client_p, "Fork failed");
+               }
+               start_io(client_p);
+               SetServlink(client_p);
+       }
+
+       sendto_one(client_p, "SVINFO %d %d 0 :%ld", TS_CURRENT, TS_MIN, CurrentTime);
+
+       client_p->servptr = &me;
+
+       if(IsAnyDead(client_p))
+               return CLIENT_EXITED;
+
+       SetServer(client_p);
+
+       /* Update the capability combination usage counts */
+       set_chcap_usage_counts(client_p);
+
+       dlinkAdd(client_p, &client_p->lnode, &me.serv->servers);
+       dlinkMoveNode(&client_p->localClient->tnode, &unknown_list, &serv_list);
+       dlinkAddTailAlloc(client_p, &global_serv_list);
+
+       if(has_id(client_p))
+               add_to_id_hash(client_p->id, client_p);
+
+       add_to_client_hash(client_p->name, client_p);
+       /* doesnt duplicate client_p->serv if allocated this struct already */
+       make_server(client_p);
+       client_p->serv->up = me.name;
+       client_p->serv->upid = me.id;
+
+       client_p->serv->caps = client_p->localClient->caps;
+
+       if(client_p->localClient->fullcaps)
+       {
+               DupString(client_p->serv->fullcaps, client_p->localClient->fullcaps);
+               MyFree(client_p->localClient->fullcaps);
+               client_p->localClient->fullcaps = NULL;
+       }
+
+       /* add it to scache */
+       find_or_add(client_p->name);
+       client_p->localClient->firsttime = CurrentTime;
+       /* fixing eob timings.. -gnp */
+
+       /* Show the real host/IP to admins */
+       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                       "Link with %s established: (%s) link",
+                       get_server_name(client_p, SHOW_IP),
+                       show_capabilities(client_p));
+
+       ilog(L_SERVER, "Link with %s established: (%s) link",
+            log_client_name(client_p, SHOW_IP), show_capabilities(client_p));
+
+       hdata.client = &me;
+       hdata.target = client_p;
+       call_hook(h_server_introduced, &hdata);
+
+       if(HasServlink(client_p))
+       {
+               /* we won't overflow FD_DESC_SZ here, as it can hold
+                * client_p->name + 64
+                */
+               comm_note(client_p->localClient->fd, "slink data: %s", client_p->name);
+               comm_note(client_p->localClient->ctrlfd, "slink ctrl: %s", client_p->name);
+       }
+       else
+               comm_note(client_p->localClient->fd, "Server: %s", client_p->name);
+
+       /*
+        ** 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.
+        */
+       DLINK_FOREACH(ptr, serv_list.head)
+       {
+               target_p = ptr->data;
+
+               if(target_p == client_p)
+                       continue;
+
+               if(has_id(target_p) && has_id(client_p))
+               {
+                       sendto_one(target_p, ":%s SID %s 2 %s :%s%s",
+                                  me.id, client_p->name, client_p->id,
+                                  IsHidden(client_p) ? "(H) " : "", client_p->info);
+
+                       if(IsCapable(target_p, CAP_ENCAP) &&
+                          !EmptyString(client_p->serv->fullcaps))
+                               sendto_one(target_p, ":%s ENCAP * GCAP :%s",
+                                       client_p->id, client_p->serv->fullcaps);
+               }
+               else
+               {
+                       sendto_one(target_p, ":%s SERVER %s 2 :%s%s",
+                                  me.name, client_p->name,
+                                  IsHidden(client_p) ? "(H) " : "", client_p->info);
+
+                       if(IsCapable(target_p, CAP_ENCAP) &&
+                          !EmptyString(client_p->serv->fullcaps))
+                               sendto_one(target_p, ":%s ENCAP * GCAP :%s",
+                                       client_p->name, client_p->serv->fullcaps);
+               }
+       }
+
+       /*
+        ** Pass on my client information to the new server
+        **
+        ** First, pass only servers (idea is that if the link gets
+        ** cancelled beacause the server was already there,
+        ** there are no NICK's to be cancelled...). 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...
+        **
+        ** ALSO NOTE: using the get_client_name for server names--
+        **    see previous *WARNING*!!! (Also, original inpath
+        **    is destroyed...)
+        */
+       DLINK_FOREACH(ptr, global_serv_list.head)
+       {
+               target_p = ptr->data;
+
+               /* target_p->from == target_p for target_p == client_p */
+               if(IsMe(target_p) || target_p->from == client_p)
+                       continue;
+
+               /* presumption, if target has an id, so does its uplink */
+               if(has_id(client_p) && has_id(target_p))
+                       sendto_one(client_p, ":%s SID %s %d %s :%s%s",
+                                  target_p->serv->upid, target_p->name,
+                                  target_p->hopcount + 1, target_p->id,
+                                  IsHidden(target_p) ? "(H) " : "", target_p->info);
+               else
+                       sendto_one(client_p, ":%s SERVER %s %d :%s%s",
+                                  target_p->serv->up,
+                                  target_p->name, target_p->hopcount + 1,
+                                  IsHidden(target_p) ? "(H) " : "", target_p->info);
+
+               if(IsCapable(client_p, CAP_ENCAP) && 
+                  !EmptyString(target_p->serv->fullcaps))
+                       sendto_one(client_p, ":%s ENCAP * GCAP :%s",
+                                       get_id(target_p, client_p),
+                                       target_p->serv->fullcaps);
+       }
+
+       if(has_id(client_p))
+               burst_TS6(client_p);
+       else
+               burst_TS5(client_p);
+
+       /* Always send a PING after connect burst is done */
+       sendto_one(client_p, "PING :%s", get_id(&me, client_p));
+
+       free_pre_client(client_p);
+
+       return 0;
+}
+
+static void
+start_io(struct Client *server)
+{
+       unsigned char *iobuf;
+       int c = 0;
+       int linecount = 0;
+       int linelen;
+
+       iobuf = MyMalloc(256);  /* XXX: This seems arbitrary. Perhaps make it IRCD_BUFSIZE? --nenolod */
+
+       if(IsCapable(server, CAP_ZIP))
+       {
+               /* ziplink */
+               iobuf[c++] = SLINKCMD_SET_ZIP_OUT_LEVEL;
+               iobuf[c++] = 0; /* |          */
+               iobuf[c++] = 1; /* \ len is 1 */
+               iobuf[c++] = ConfigFileEntry.compression_level;
+               iobuf[c++] = SLINKCMD_START_ZIP_IN;
+               iobuf[c++] = SLINKCMD_START_ZIP_OUT;
+       }
+
+       while (MyConnect(server))
+       {
+               linecount++;
+
+               iobuf = MyRealloc(iobuf, (c + READBUF_SIZE + 64));
+
+               /* store data in c+3 to allow for SLINKCMD_INJECT_RECVQ and len u16 */
+               linelen = linebuf_get(&server->localClient->buf_recvq, (char *) (iobuf + c + 3), READBUF_SIZE, LINEBUF_PARTIAL, LINEBUF_RAW);   /* include partial lines */
+
+               if(linelen)
+               {
+                       iobuf[c++] = SLINKCMD_INJECT_RECVQ;
+                       iobuf[c++] = (linelen >> 8);
+                       iobuf[c++] = (linelen & 0xff);
+                       c += linelen;
+               }
+               else
+                       break;
+       }
+
+       while (MyConnect(server))
+       {
+               linecount++;
+
+               iobuf = MyRealloc(iobuf, (c + BUF_DATA_SIZE + 64));
+
+               /* store data in c+3 to allow for SLINKCMD_INJECT_RECVQ and len u16 */
+               linelen = linebuf_get(&server->localClient->buf_sendq, 
+                                     (char *) (iobuf + c + 3), READBUF_SIZE, 
+                                     LINEBUF_PARTIAL, LINEBUF_PARSED); /* include partial lines */
+
+               if(linelen)
+               {
+                       iobuf[c++] = SLINKCMD_INJECT_SENDQ;
+                       iobuf[c++] = (linelen >> 8);
+                       iobuf[c++] = (linelen & 0xff);
+                       c += linelen;
+               }
+               else
+                       break;
+       }
+
+       /* start io */
+       iobuf[c++] = SLINKCMD_INIT;
+
+       server->localClient->slinkq = iobuf;
+       server->localClient->slinkq_ofs = 0;
+       server->localClient->slinkq_len = c;
+
+       /* schedule a write */
+       send_queued_slink_write(server->localClient->ctrlfd, server);
+}
+
+/*
+ * fork_server
+ *
+ * inputs       - struct Client *server
+ * output       - success: 0 / failure: -1
+ * side effect  - fork, and exec SERVLINK to handle this connection
+ */
+static int
+fork_server(struct Client *server)
+{
+       int ret;
+       int i;
+       int ctrl_fds[2];
+       int data_fds[2];
+
+       char fd_str[4][6];
+       char *kid_argv[7];
+       char slink[] = "-slink";
+
+
+       /* ctrl */
+#ifdef HAVE_SOCKETPAIR
+       if(socketpair(AF_UNIX, SOCK_STREAM, 0, ctrl_fds) < 0)
+#else
+       if(inet_socketpair(AF_INET,SOCK_STREAM, 0, ctrl_fds) < 0)
+#endif
+               goto fork_error;
+
+       
+
+       /* data */
+#ifdef HAVE_SOCKETPAIR
+       if(socketpair(AF_UNIX, SOCK_STREAM, 0, data_fds) < 0)
+#else
+       if(inet_socketpair(AF_INET,SOCK_STREAM, 0, data_fds) < 0)
+#endif
+               goto fork_error;
+
+
+#ifdef __CYGWIN__
+       if((ret = vfork()) < 0)
+#else
+       if((ret = fork()) < 0)
+#endif
+               goto fork_error;
+       else if(ret == 0)
+       {
+               /* set our fds as non blocking and close everything else */
+               for (i = 0; i < HARD_FDLIMIT; i++)
+               {
+                               
+
+                       if((i == ctrl_fds[1]) || (i == data_fds[1]) || (i == server->localClient->fd)) 
+                       {
+                               comm_set_nb(i);
+                       }
+                       else
+                       {
+#ifdef __CYGWIN__
+                               if(i > 2)       /* don't close std* */
+#endif
+                                       close(i);
+                       }
+               }
+
+               ircsnprintf(fd_str[0], sizeof(fd_str[0]), "%d", ctrl_fds[1]);
+               ircsnprintf(fd_str[1], sizeof(fd_str[1]), "%d", data_fds[1]);
+               ircsnprintf(fd_str[2], sizeof(fd_str[2]), "%d", server->localClient->fd);
+               kid_argv[0] = slink;
+               kid_argv[1] = fd_str[0];
+               kid_argv[2] = fd_str[1];
+               kid_argv[3] = fd_str[2];
+               kid_argv[4] = NULL;
+
+               /* exec servlink program */
+               execv(ConfigFileEntry.servlink_path, kid_argv);
+
+               /* We're still here, abort. */
+               _exit(1);
+       }
+       else
+       {
+               comm_close(server->localClient->fd);
+
+               /* close the childs end of the pipes */
+               close(ctrl_fds[1]);
+               close(data_fds[1]);
+               
+               s_assert(server->localClient);
+               server->localClient->ctrlfd = ctrl_fds[0];
+               server->localClient->fd = data_fds[0];
+
+               if(!comm_set_nb(server->localClient->fd))
+               {
+                       report_error(NONB_ERROR_MSG,
+                                       get_server_name(server, SHOW_IP),
+                                       log_client_name(server, SHOW_IP),
+                                       errno);
+               }
+
+               if(!comm_set_nb(server->localClient->ctrlfd))
+               {
+                       report_error(NONB_ERROR_MSG,
+                                       get_server_name(server, SHOW_IP),
+                                       log_client_name(server, SHOW_IP),
+                                       errno);
+               }
+
+               comm_open(server->localClient->ctrlfd, FD_SOCKET, NULL);
+               comm_open(server->localClient->fd, FD_SOCKET, NULL);
+
+               read_ctrl_packet(server->localClient->ctrlfd, server);
+               read_packet(server->localClient->fd, server);
+       }
+
+       return 0;
+
+      fork_error:
+       /* this is ugly, but nicer than repeating
+        * about 50 close() statements everywhre... */
+       close(data_fds[0]);
+       close(data_fds[1]);
+       close(ctrl_fds[0]);
+       close(ctrl_fds[1]);
+       return -1;
+}
+
+/*
+ * New server connection code
+ * Based upon the stuff floating about in s_bsd.c
+ *   -- adrian
+ */
+
+/*
+ * serv_connect() - initiate a server connection
+ *
+ * inputs      - pointer to conf 
+ *             - pointer to client doing the connet
+ * output      -
+ * side effects        -
+ *
+ * This code initiates a connection to a server. It first checks to make
+ * sure the given server exists. If this is the case, it creates a socket,
+ * creates a client, saves the socket information in the client, and
+ * initiates a connection to the server through comm_connect_tcp(). The
+ * completion of this goes through serv_completed_connection().
+ *
+ * We return 1 if the connection is attempted, since we don't know whether
+ * it suceeded or not, and 0 if it fails in here somewhere.
+ */
+int
+serv_connect(struct server_conf *server_p, struct Client *by)
+{
+       struct Client *client_p;
+       struct irc_sockaddr_storage myipnum; 
+       int fd;
+
+       s_assert(server_p != NULL);
+       if(server_p == NULL)
+               return 0;
+
+       /*
+        * Make sure this server isn't already connected
+        */
+       if((client_p = find_server(NULL, server_p->name)))
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Server %s already present from %s",
+                                    server_p->name, get_server_name(client_p, SHOW_IP));
+               if(by && IsPerson(by) && !MyClient(by))
+                       sendto_one_notice(by, ":Server %s already present from %s",
+                                         server_p->name, get_server_name(client_p, SHOW_IP));
+               return 0;
+       }
+
+       /* create a socket for the server connection */
+       if((fd = comm_socket(server_p->aftype, SOCK_STREAM, 0, NULL)) < 0)
+       {
+               /* Eek, failure to create the socket */
+               report_error("opening stream socket to %s: %s", 
+                            server_p->name, server_p->name, errno);
+               return 0;
+       }
+
+       /* servernames are always guaranteed under HOSTLEN chars */
+       comm_note(fd, "Server: %s", server_p->name);
+
+       /* Create a local client */
+       client_p = make_client(NULL);
+
+       /* Copy in the server, hostname, fd
+        * The sockhost may be a hostname, this will be corrected later
+        * -- jilles
+        */
+       strlcpy(client_p->name, server_p->name, sizeof(client_p->name));
+       strlcpy(client_p->host, server_p->host, sizeof(client_p->host));
+       strlcpy(client_p->sockhost, server_p->host, sizeof(client_p->sockhost));
+       client_p->localClient->fd = fd;
+
+       /*
+        * Set up the initial server evilness, ripped straight from
+        * connect_server(), so don't blame me for it being evil.
+        *   -- adrian
+        */
+
+       if(!comm_set_buffers(client_p->localClient->fd, READBUF_SIZE))
+       {
+               report_error(SETBUF_ERROR_MSG,
+                               get_server_name(client_p, SHOW_IP),
+                               log_client_name(client_p, SHOW_IP),
+                               errno);
+       }
+
+       /*
+        * Attach config entries to client here rather than in
+        * serv_connect_callback(). This to avoid null pointer references.
+        */
+       attach_server_conf(client_p, server_p);
+
+       /*
+        * at this point we have a connection in progress and C/N lines
+        * attached to the client, the socket info should be saved in the
+        * client and it should either be resolved or have a valid address.
+        *
+        * The socket has been connected or connect is in progress.
+        */
+       make_server(client_p);
+       if(by && IsPerson(by))
+       {
+               strcpy(client_p->serv->by, by->name);
+               if(client_p->serv->user)
+                       free_user(client_p->serv->user, NULL);
+               client_p->serv->user = by->user;
+               by->user->refcnt++;
+       }
+       else
+       {
+               strcpy(client_p->serv->by, "AutoConn.");
+               if(client_p->serv->user)
+                       free_user(client_p->serv->user, NULL);
+               client_p->serv->user = NULL;
+       }
+       client_p->serv->up = me.name;
+       client_p->serv->upid = me.id;
+       SetConnecting(client_p);
+       dlinkAddTail(client_p, &client_p->node, &global_client_list);
+
+       /* log */
+       ilog(L_SERVER, "Connecting to %s[%s] port %d (%s)", server_p->name, server_p->host, server_p->port,
+#ifdef IPV6
+                       server_p->aftype == AF_INET6 ? "IPv6" :
+#endif
+                       (server_p->aftype == AF_INET ? "IPv4" : "?"));
+
+       if(ServerConfVhosted(server_p))
+       {
+               memcpy(&myipnum, &server_p->my_ipnum, sizeof(myipnum));
+               ((struct sockaddr_in *)&myipnum)->sin_port = 0;
+               myipnum.ss_family = server_p->aftype;
+                               
+       }
+       else if(server_p->aftype == AF_INET && ServerInfo.specific_ipv4_vhost)
+       {
+               memcpy(&myipnum, &ServerInfo.ip, sizeof(myipnum));
+               ((struct sockaddr_in *)&myipnum)->sin_port = 0;
+               myipnum.ss_family = AF_INET;
+               SET_SS_LEN(myipnum, sizeof(struct sockaddr_in));
+       }
+       
+#ifdef IPV6
+       else if((server_p->aftype == AF_INET6) && ServerInfo.specific_ipv6_vhost)
+       {
+               memcpy(&myipnum, &ServerInfo.ip6, sizeof(myipnum));
+               ((struct sockaddr_in6 *)&myipnum)->sin6_port = 0;
+               myipnum.ss_family = AF_INET6;
+               SET_SS_LEN(myipnum, sizeof(struct sockaddr_in6));
+       }
+#endif
+       else
+       {
+               comm_connect_tcp(client_p->localClient->fd, server_p->host,
+                                server_p->port, NULL, 0, serv_connect_callback, 
+                                client_p, server_p->aftype, 
+                                ConfigFileEntry.connect_timeout);
+                return 1;
+       }
+
+       comm_connect_tcp(client_p->localClient->fd, server_p->host,
+                        server_p->port, (struct sockaddr *) &myipnum,
+                        GET_SS_LEN(myipnum), serv_connect_callback, client_p,
+                        myipnum.ss_family, ConfigFileEntry.connect_timeout);
+
+       return 1;
+}
+
+/*
+ * serv_connect_callback() - complete a server connection.
+ * 
+ * This routine is called after the server connection attempt has
+ * completed. If unsucessful, an error is sent to ops and the client
+ * is closed. If sucessful, it goes through the initialisation/check
+ * procedures, the capabilities are sent, and the socket is then
+ * marked for reading.
+ */
+static void
+serv_connect_callback(int fd, int status, void *data)
+{
+       struct Client *client_p = data;
+       struct server_conf *server_p;
+       char *errstr;
+
+       /* First, make sure its a real client! */
+       s_assert(client_p != NULL);
+       s_assert(client_p->localClient->fd == fd);
+
+       if(client_p == NULL)
+               return;
+
+       /* while we were waiting for the callback, its possible this already
+        * linked in.. --fl
+        */
+       if(find_server(NULL, client_p->name) != NULL)
+       {
+               exit_client(client_p, client_p, &me, "Server Exists");
+               return;
+       }
+
+       /* Next, for backward purposes, record the ip of the server */
+       memcpy(&client_p->localClient->ip, &fd_table[fd].connect.hostaddr, sizeof client_p->localClient->ip);
+       /* Set sockhost properly now -- jilles */
+       inetntop_sock((struct sockaddr *)&fd_table[fd].connect.hostaddr,
+                       client_p->sockhost, sizeof client_p->sockhost);
+       
+       /* Check the status */
+       if(status != COMM_OK)
+       {
+               /* COMM_ERR_TIMEOUT wont have an errno associated with it,
+                * the others will.. --fl
+                */
+               if(status == COMM_ERR_TIMEOUT)
+               {
+                       sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) ? L_NETWIDE : L_ALL,
+                                       "Error connecting to %s[%s]: %s",
+                                       client_p->name, 
+#ifdef HIDE_SERVERS_IPS
+                                       "255.255.255.255",
+#else
+                                       client_p->host,
+#endif
+                                       comm_errstr(status));
+                       ilog(L_SERVER, "Error connecting to %s[%s]: %s",
+                               client_p->name, client_p->sockhost,
+                               comm_errstr(status));
+               }
+               else
+               {
+                       errstr = strerror(comm_get_sockerr(fd));
+                       sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) ? L_NETWIDE : L_ALL,
+                                       "Error connecting to %s[%s]: %s (%s)",
+                                       client_p->name,
+#ifdef HIDE_SERVERS_IPS
+                                       "255.255.255.255",
+#else
+                                       client_p->host,
+#endif
+                                       comm_errstr(status), errstr);
+                       ilog(L_SERVER, "Error connecting to %s[%s]: %s (%s)",
+                               client_p->name, client_p->sockhost,
+                               comm_errstr(status), errstr);
+               }
+
+               exit_client(client_p, client_p, &me, comm_errstr(status));
+               return;
+       }
+
+       /* COMM_OK, so continue the connection procedure */
+       /* Get the C/N lines */
+       if((server_p = client_p->localClient->att_sconf) == NULL)
+       {
+               sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) ? L_NETWIDE : L_ALL, "Lost connect{} block for %s",
+                               get_server_name(client_p, HIDE_IP));
+               exit_client(client_p, client_p, &me, "Lost connect{} block");
+               return;
+       }
+
+       /* Next, send the initial handshake */
+       SetHandshake(client_p);
+
+       /* kludge, if we're not using TS6, dont ever send
+        * ourselves as being TS6 capable.
+        */
+       if(!EmptyString(server_p->spasswd))
+       {
+               if(ServerInfo.use_ts6)
+                       sendto_one(client_p, "PASS %s TS %d :%s", 
+                                  server_p->spasswd, TS_CURRENT, me.id);
+               else
+                       sendto_one(client_p, "PASS %s :TS",
+                                  server_p->spasswd);
+       }
+
+       /* pass my info to the new server */
+       send_capabilities(client_p, default_server_capabs
+                         | (ServerConfCompressed(server_p) ? CAP_ZIP_SUPPORTED : 0)
+                         | (ServerConfTb(server_p) ? CAP_TB : 0));
+
+       sendto_one(client_p, "SERVER %s 1 :%s%s",
+                  me.name,
+                  ConfigServerHide.hidden ? "(H) " : "", me.info);
+
+       /* 
+        * If we've been marked dead because a send failed, just exit
+        * here now and save everyone the trouble of us ever existing.
+        */
+       if(IsAnyDead(client_p))
+       {
+               sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) ? L_NETWIDE : L_ALL,
+                                    "%s went dead during handshake", client_p->name);
+               exit_client(client_p, client_p, &me, "Went dead during handshake");
+               return;
+       }
+
+       /* don't move to serv_list yet -- we haven't sent a burst! */
+
+       /* If we get here, we're ok, so lets start reading some data */
+       read_packet(fd, client_p);
+}
+
+#ifndef HAVE_SOCKETPAIR
+static int
+inet_socketpair(int d, int type, int protocol, int sv[2])
+{
+       struct sockaddr_in addr1, addr2, addr3;
+       int addr3_len = sizeof(addr3);
+       int fd, rc;
+       int port_no = 20000;
+       
+       if(d != AF_INET || type != SOCK_STREAM || protocol)
+       {
+               errno = EAFNOSUPPORT;
+               return -1;
+       }
+       if(((sv[0] = socket(AF_INET, SOCK_STREAM, 0)) < 0) || ((sv[1] = socket(AF_INET, SOCK_STREAM, 0)) < 0))
+               return -1;
+       
+       addr1.sin_port = htons(port_no);
+       addr1.sin_family = AF_INET;
+       addr1.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+       while ((rc = bind (sv[0], (struct sockaddr *) &addr1, sizeof (addr1))) < 0 && errno == EADDRINUSE)
+               addr1.sin_port = htons(++port_no);
+       
+       if(rc < 0)
+               return -1;
+       
+       if(listen(sv[0], 1) < 0)
+       {
+               close(sv[0]);
+               close(sv[1]);
+               return -1;
+       }
+       
+       addr2.sin_port = htons(port_no);
+       addr2.sin_family = AF_INET;
+       addr2.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+       if(connect (sv[1], (struct sockaddr *) &addr2, sizeof (addr2)) < 0) 
+       {
+               close(sv[0]);
+               close(sv[1]);
+               return -1;
+       }
+       
+       if((fd = accept(sv[1], (struct sockaddr *) &addr3, &addr3_len)) < 0)
+       {
+               close(sv[0]);
+               close(sv[1]);
+               return -1;
+       }
+       close(sv[0]);
+       sv[0] = fd;
+       
+       return(0);
+
+}
+#endif
diff --git a/src/s_stats.c b/src/s_stats.c
new file mode 100644 (file)
index 0000000..66ccce9
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  s_stats.c: Statistics related functions
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: s_stats.c 1409 2006-05-21 14:46:17Z jilles $
+ */
+
+#include "stdinc.h"
+#include "s_stats.h"
+#include "client.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "commio.h"
+#include "send.h"
+#include "memory.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "whowas.h"
+#include "hash.h"
+#include "scache.h"
+#include "reject.h"
+
+/*
+ * stats stuff
+ */
+static struct ServerStatistics ircst;
+struct ServerStatistics *ServerStats = &ircst;
+
+void
+init_stats()
+{
+       memset(&ircst, 0, sizeof(ircst));
+}
+
+/*
+ * tstats
+ *
+ * inputs      - client to report to
+ * output      - NONE 
+ * side effects        -
+ */
+void
+tstats(struct Client *source_p)
+{
+       struct Client *target_p;
+       struct ServerStatistics *sp;
+       struct ServerStatistics tmp;
+       dlink_node *ptr;
+
+       sp = &tmp;
+       memcpy(sp, ServerStats, sizeof(struct ServerStatistics));
+
+       DLINK_FOREACH(ptr, serv_list.head)
+       {
+               target_p = ptr->data;
+
+               sp->is_sbs += target_p->localClient->sendB;
+               sp->is_sbr += target_p->localClient->receiveB;
+               sp->is_sks += target_p->localClient->sendK;
+               sp->is_skr += target_p->localClient->receiveK;
+               sp->is_sti += CurrentTime - target_p->localClient->firsttime;
+               sp->is_sv++;
+               if(sp->is_sbs > 1023)
+               {
+                       sp->is_sks += (sp->is_sbs >> 10);
+                       sp->is_sbs &= 0x3ff;
+               }
+               if(sp->is_sbr > 1023)
+               {
+                       sp->is_skr += (sp->is_sbr >> 10);
+                       sp->is_sbr &= 0x3ff;
+               }
+       }
+
+       DLINK_FOREACH(ptr, lclient_list.head)
+       {
+               target_p = ptr->data;
+
+               sp->is_cbs += target_p->localClient->sendB;
+               sp->is_cbr += target_p->localClient->receiveB;
+               sp->is_cks += target_p->localClient->sendK;
+               sp->is_ckr += target_p->localClient->receiveK;
+               sp->is_cti += CurrentTime - target_p->localClient->firsttime;
+               sp->is_cl++;
+               if(sp->is_cbs > 1023)
+               {
+                       sp->is_cks += (sp->is_cbs >> 10);
+                       sp->is_cbs &= 0x3ff;
+               }
+               if(sp->is_cbr > 1023)
+               {
+                       sp->is_ckr += (sp->is_cbr >> 10);
+                       sp->is_cbr &= 0x3ff;
+               }
+
+       }
+
+       DLINK_FOREACH(ptr, unknown_list.head)
+       {
+               sp->is_ni++;
+       }
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "T :accepts %u refused %u", sp->is_ac, sp->is_ref);
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                       "T :rejected %u delaying %lu", 
+                       sp->is_rej, dlink_list_length(&delay_exit));
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                       "T :nicks being delayed %lu",
+                       get_nd_count());
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "T :unknown commands %u prefixes %u",
+                          sp->is_unco, sp->is_unpf);
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "T :nick collisions %u saves %u unknown closes %u",
+                          sp->is_kill, sp->is_save, sp->is_ni);
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "T :wrong direction %u empty %u", 
+                          sp->is_wrdi, sp->is_empt);
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "T :numerics seen %u", sp->is_num);
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "T :auth successes %u fails %u",
+                          sp->is_asuc, sp->is_abad);
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "T :sasl successes %u fails %u",
+                          sp->is_ssuc, sp->is_sbad);
+       sendto_one_numeric(source_p, RPL_STATSDEBUG, "T :Client Server");
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "T :connected %u %u", sp->is_cl, sp->is_sv);
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "T :bytes sent %d.%uK %d.%uK",
+                          (int) sp->is_cks, sp->is_cbs, 
+                          (int) sp->is_sks, sp->is_sbs);
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "T :bytes recv %d.%uK %d.%uK",
+                          (int) sp->is_ckr, sp->is_cbr, 
+                          (int) sp->is_skr, sp->is_sbr);
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "T :time connected %d %d",
+                          (int) sp->is_cti, (int) sp->is_sti);
+}
+
+void
+count_memory(struct Client *source_p)
+{
+       struct Client *target_p;
+       struct Channel *chptr;
+       struct Ban *actualBan;
+       dlink_node *dlink;
+       dlink_node *ptr;
+       int channel_count = 0;
+       int local_client_conf_count = 0;        /* local client conf links */
+       int users_counted = 0;  /* user structs */
+
+       int channel_users = 0;
+       int channel_invites = 0;
+       int channel_bans = 0;
+       int channel_except = 0;
+       int channel_invex = 0;
+       int channel_quiets = 0;
+
+       size_t wwu = 0;         /* whowas users */
+       int class_count = 0;    /* classes */
+       int conf_count = 0;     /* conf lines */
+       int users_invited_count = 0;    /* users invited */
+       int user_channels = 0;  /* users in channels */
+       int aways_counted = 0;
+       size_t number_servers_cached;   /* number of servers cached by scache */
+
+       size_t channel_memory = 0;
+       size_t channel_ban_memory = 0;
+       size_t channel_except_memory = 0;
+       size_t channel_invex_memory = 0;
+       size_t channel_quiet_memory = 0;
+
+       size_t away_memory = 0; /* memory used by aways */
+       size_t wwm = 0;         /* whowas array memory used */
+       size_t conf_memory = 0; /* memory used by conf lines */
+       size_t mem_servers_cached;      /* memory used by scache */
+
+       size_t linebuf_count = 0;
+       size_t linebuf_memory_used = 0;
+
+       size_t total_channel_memory = 0;
+       size_t totww = 0;
+
+       size_t local_client_count = 0;
+       size_t local_client_memory_used = 0;
+
+       size_t remote_client_count = 0;
+       size_t remote_client_memory_used = 0;
+
+       size_t total_memory = 0;
+
+       count_whowas_memory(&wwu, &wwm);
+
+       DLINK_FOREACH(ptr, global_client_list.head)
+       {
+               target_p = ptr->data;
+               if(MyConnect(target_p))
+               {
+                       local_client_conf_count++;
+               }
+
+               if(target_p->user)
+               {
+                       users_counted++;
+                       users_invited_count += dlink_list_length(&target_p->user->invited);
+                       user_channels += dlink_list_length(&target_p->user->channel);
+                       if(target_p->user->away)
+                       {
+                               aways_counted++;
+                               away_memory += (strlen(target_p->user->away) + 1);
+                       }
+               }
+       }
+
+       /* Count up all channels, ban lists, except lists, Invex lists */
+       DLINK_FOREACH(ptr, global_channel_list.head)
+       {
+               chptr = ptr->data;
+               channel_count++;
+               channel_memory += (strlen(chptr->chname) + sizeof(struct Channel));
+
+               channel_users += dlink_list_length(&chptr->members);
+               channel_invites += dlink_list_length(&chptr->invites);
+
+               DLINK_FOREACH(dlink, chptr->banlist.head)
+               {
+                       actualBan = dlink->data;
+                       channel_bans++;
+
+                       channel_ban_memory += sizeof(dlink_node) + sizeof(struct Ban);
+               }
+
+               DLINK_FOREACH(dlink, chptr->exceptlist.head)
+               {
+                       actualBan = dlink->data;
+                       channel_except++;
+
+                       channel_except_memory += (sizeof(dlink_node) + sizeof(struct Ban));
+               }
+
+               DLINK_FOREACH(dlink, chptr->invexlist.head)
+               {
+                       actualBan = dlink->data;
+                       channel_invex++;
+
+                       channel_invex_memory += (sizeof(dlink_node) + sizeof(struct Ban));
+               }
+
+               DLINK_FOREACH(dlink, chptr->quietlist.head)
+               {
+                       actualBan = dlink->data;
+                       channel_quiets++;
+
+                       channel_quiet_memory += (sizeof(dlink_node) + sizeof(struct Ban));
+               }
+       }
+
+       /* count up all classes */
+
+       class_count = dlink_list_length(&class_list) + 1;
+
+       count_linebuf_memory(&linebuf_count, &linebuf_memory_used);
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "z :Users %u(%lu) Invites %u(%lu)",
+                          users_counted,
+                          (unsigned long) users_counted * sizeof(struct User),
+                          users_invited_count, 
+                          (unsigned long) users_invited_count * sizeof(dlink_node));
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "z :User channels %u(%lu) Aways %u(%d)",
+                          user_channels,
+                          (unsigned long) user_channels * sizeof(dlink_node),
+                          aways_counted, (int) away_memory);
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "z :Attached confs %u(%lu)",
+                          local_client_conf_count,
+                          (unsigned long) local_client_conf_count * sizeof(dlink_node));
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "z :Conflines %u(%d)", conf_count, (int) conf_memory);
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "z :Classes %u(%lu)",
+                          class_count, 
+                          (unsigned long) class_count * sizeof(struct Class));
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "z :Channels %u(%d)",
+                          channel_count, (int) channel_memory);
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "z :Bans %u(%d) Exceptions %u(%d) Invex %u(%d) Quiets %u(%d)",
+                          channel_bans, (int) channel_ban_memory,
+                          channel_except, (int) channel_except_memory,
+                          channel_invex, (int) channel_invex_memory,
+                          channel_quiets, (int) channel_quiet_memory);
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "z :Channel members %u(%lu) invite %u(%lu)",
+                          channel_users,
+                          (unsigned long) channel_users * sizeof(dlink_node),
+                          channel_invites, 
+                          (unsigned long) channel_invites * sizeof(dlink_node));
+
+       total_channel_memory = channel_memory +
+               channel_ban_memory +
+               channel_users * sizeof(dlink_node) + channel_invites * sizeof(dlink_node);
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "z :Whowas users %ld(%ld)",
+                          (long)wwu, (long) (wwu * sizeof(struct User)));
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "z :Whowas array %u(%d)",
+                          NICKNAMEHISTORYLENGTH, (int) wwm);
+
+       totww = wwu * sizeof(struct User) + wwm;
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "z :Hash: client %u(%ld) chan %u(%ld)",
+                          U_MAX, (long)(U_MAX * sizeof(dlink_list)), 
+                          CH_MAX, (long)(CH_MAX * sizeof(dlink_list)));
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "z :linebuf %ld(%ld)",
+                          (long)linebuf_count, (long)linebuf_memory_used);
+
+       count_scache(&number_servers_cached, &mem_servers_cached);
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "z :scache %ld(%ld)",
+                          (long)number_servers_cached, (long)mem_servers_cached);
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "z :hostname hash %d(%ld)",
+                          HOST_MAX, (long)HOST_MAX * sizeof(dlink_list));
+
+       total_memory = totww + total_channel_memory + conf_memory +
+               class_count * sizeof(struct Class);
+
+       total_memory += mem_servers_cached;
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "z :Total: whowas %d channel %d conf %d", 
+                          (int) totww, (int) total_channel_memory, 
+                          (int) conf_memory);
+
+       count_local_client_memory(&local_client_count, &local_client_memory_used);
+       total_memory += local_client_memory_used;
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "z :Local client Memory in use: %ld(%ld)",
+                          (long)local_client_count, (long)local_client_memory_used);
+
+
+       count_remote_client_memory(&remote_client_count, &remote_client_memory_used);
+       total_memory += remote_client_memory_used;
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "z :Remote client Memory in use: %ld(%ld)",
+                          (long)remote_client_count,
+                          (long)remote_client_memory_used);
+
+       sendto_one_numeric(source_p, RPL_STATSDEBUG,
+                          "z :TOTAL: %d Available:  Current max RSS: %lu",
+                          (int) total_memory, get_maxrss());
+}
diff --git a/src/s_user.c b/src/s_user.c
new file mode 100644 (file)
index 0000000..531278e
--- /dev/null
@@ -0,0 +1,1447 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  s_user.c: User related functions.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: s_user.c 3131 2007-01-21 15:36:31Z jilles $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "s_user.h"
+#include "channel.h"
+#include "class.h"
+#include "client.h"
+#include "common.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "listener.h"
+#include "msg.h"
+#include "numeric.h"
+#include "commio.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "s_log.h"
+#include "s_serv.h"
+#include "s_stats.h"
+#include "scache.h"
+#include "send.h"
+#include "supported.h"
+#include "whowas.h"
+#include "memory.h"
+#include "packet.h"
+#include "reject.h"
+#include "cache.h"
+#include "hook.h"
+#include "monitor.h"
+#include "snomask.h"
+#include "blacklist.h"
+
+static void report_and_set_user_flags(struct Client *, struct ConfItem *);
+void user_welcome(struct Client *source_p);
+
+extern char *crypt();
+
+char umodebuf[128];
+
+int user_modes[256] = {
+       /* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0F */
+       /* 0x10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x1F */
+       /* 0x20 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x2F */
+       /* 0x30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x3F */
+       0,                      /* @ */
+       0,                      /* A */
+       0,                      /* B */
+       0,                      /* C */
+       UMODE_DEAF,             /* D */
+       0,                      /* E */
+       0,                      /* F */
+       0,                      /* G */
+       0,                      /* H */
+       0,                      /* I */
+       0,                      /* J */
+       0,                      /* K */
+       0,                      /* L */
+       0,                      /* M */
+       0,                      /* N */
+       0,                      /* O */
+       0,                      /* P */
+       UMODE_NOFORWARD,        /* Q */
+       UMODE_REGONLYMSG,       /* R */
+       UMODE_SERVICE,          /* S */
+       0,                      /* T */
+       0,                      /* U */
+       0,                      /* V */
+       0,                      /* W */
+       0,                      /* X */
+       0,                      /* Y */
+       0,                      /* Z */
+       /* 0x5B */ 0, 0, 0, 0, 0, 0, /* 0x60 */
+       UMODE_ADMIN,            /* a */
+       0,                      /* b */
+       0,                      /* c */
+       0,                      /* d */
+       0,                      /* e */
+       0,                      /* f */
+       UMODE_CALLERID,         /* g */
+       0,                      /* h */
+       UMODE_INVISIBLE,        /* i */
+       0,                      /* j */
+       0,                      /* k */
+       UMODE_LOCOPS,           /* l */
+       0,                      /* m */
+       0,                      /* n */
+       UMODE_OPER,             /* o */
+       0,                      /* p */
+       0,                      /* q */
+       0,                      /* r */
+       UMODE_SERVNOTICE,       /* s */
+       0,                      /* t */
+       0,                      /* u */
+       0,                      /* v */
+       UMODE_WALLOP,           /* w */
+       0,                      /* x */
+       0,                      /* y */
+       UMODE_OPERWALL,         /* z */
+       /* 0x7B */ 0, 0, 0, 0, 0, /* 0x7F */
+       /* 0x80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x9F */
+       /* 0x90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x9F */
+       /* 0xA0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xAF */
+       /* 0xB0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xBF */
+       /* 0xC0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xCF */
+       /* 0xD0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xDF */
+       /* 0xE0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xEF */
+       /* 0xF0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  /* 0xFF */
+};
+/* *INDENT-ON* */
+
+/*
+ * show_lusers -
+ *
+ * inputs      - pointer to client
+ * output      -
+ * side effects        - display to client user counts etc.
+ */
+int
+show_lusers(struct Client *source_p)
+{
+       sendto_one_numeric(source_p, RPL_LUSERCLIENT, form_str(RPL_LUSERCLIENT),
+                          (Count.total - Count.invisi),
+                          Count.invisi, dlink_list_length(&global_serv_list));
+
+       if(dlink_list_length(&oper_list) > 0)
+               sendto_one_numeric(source_p, RPL_LUSEROP, 
+                                  form_str(RPL_LUSEROP), dlink_list_length(&oper_list));
+
+       if(dlink_list_length(&unknown_list) > 0)
+               sendto_one_numeric(source_p, RPL_LUSERUNKNOWN, 
+                                  form_str(RPL_LUSERUNKNOWN),
+                                  dlink_list_length(&unknown_list));
+
+       if(dlink_list_length(&global_channel_list) > 0)
+               sendto_one_numeric(source_p, RPL_LUSERCHANNELS, 
+                                  form_str(RPL_LUSERCHANNELS),
+                                  dlink_list_length(&global_channel_list));
+
+       sendto_one_numeric(source_p, RPL_LUSERME, form_str(RPL_LUSERME),
+                          dlink_list_length(&lclient_list),
+                          dlink_list_length(&serv_list));
+
+       sendto_one_numeric(source_p, RPL_LOCALUSERS, 
+                          form_str(RPL_LOCALUSERS),
+                          dlink_list_length(&lclient_list),
+                          Count.max_loc,
+                          dlink_list_length(&lclient_list),
+                          Count.max_loc);
+
+       sendto_one_numeric(source_p, RPL_GLOBALUSERS, form_str(RPL_GLOBALUSERS),
+                          Count.total, Count.max_tot,
+                          Count.total, Count.max_tot);
+
+       sendto_one_numeric(source_p, RPL_STATSCONN,
+                          form_str(RPL_STATSCONN),
+                          MaxConnectionCount, MaxClientCount, 
+                          Count.totalrestartcount);
+
+       if(dlink_list_length(&lclient_list) > (unsigned long)MaxClientCount)
+               MaxClientCount = dlink_list_length(&lclient_list);
+
+       if((dlink_list_length(&lclient_list) + dlink_list_length(&serv_list)) >
+          (unsigned long)MaxConnectionCount)
+               MaxConnectionCount = dlink_list_length(&lclient_list) + 
+                                       dlink_list_length(&serv_list);
+
+       return 0;
+}
+
+/*
+** register_local_user
+**      This function is called when both NICK and USER messages
+**      have been accepted for the client, in whatever order. Only
+**      after this, is the USER message 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:
+**
+**      (actually it has been implemented already for a while) -orabidoo
+**
+**      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 alread 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...
+*/
+
+int
+register_local_user(struct Client *client_p, struct Client *source_p, const char *username)
+{
+       struct ConfItem *aconf;
+       struct User *user = source_p->user;
+       char tmpstr2[IRCD_BUFSIZE];
+       char ipaddr[HOSTIPLEN];
+       char myusername[USERLEN+1];
+       int status;
+
+       s_assert(NULL != source_p);
+       s_assert(MyConnect(source_p));
+       s_assert(source_p->username != username);
+
+       if(source_p == NULL)
+               return -1;
+
+       if(IsAnyDead(source_p))
+               return -1;
+
+       if(ConfigFileEntry.ping_cookie)
+       {
+               if(!(source_p->flags & FLAGS_PINGSENT) && source_p->localClient->random_ping == 0)
+               {
+                       source_p->localClient->random_ping = (unsigned long) (rand() * rand()) << 1;
+                       sendto_one(source_p, "PING :%08lX",
+                                  (unsigned long) source_p->localClient->random_ping);
+                       source_p->flags |= FLAGS_PINGSENT;
+                       return -1;
+               }
+               if(!(source_p->flags2 & FLAGS2_PING_COOKIE))
+               {
+                       return -1;
+               }
+       }
+
+       /* hasnt finished client cap negotiation */
+       if(source_p->flags2 & FLAGS2_CLICAP)
+               return -1;
+
+       /* still has DNSbls to validate against */
+       if(dlink_list_length(&source_p->preClient->dnsbl_queries) > 0)
+               return -1;
+
+       client_p->localClient->last = CurrentTime;
+       /* Straight up the maximum rate of flooding... */
+       source_p->localClient->allow_read = MAX_FLOOD_BURST;
+
+       /* XXX - fixme. we shouldnt have to build a users buffer twice.. */
+       if(!IsGotId(source_p) && (strchr(username, '[') != NULL))
+       {
+               const char *p;
+               int i = 0;
+
+               p = username;
+
+               while(*p && i < USERLEN)
+               {
+                       if(*p != '[')
+                               myusername[i++] = *p;
+                       p++;
+               }
+
+               myusername[i] = '\0';
+               username = myusername;
+       }
+
+       if((status = check_client(client_p, source_p, username)) < 0)
+               return (CLIENT_EXITED);
+
+       /* Apply nick override */
+       if(*source_p->preClient->spoofnick)
+       {
+               del_from_client_hash(source_p->name, source_p);
+               strlcpy(source_p->name, source_p->preClient->spoofnick, NICKLEN + 1);
+               add_to_client_hash(source_p->name, source_p);
+               comm_note(source_p->localClient->fd, "Nick: %s", source_p->name);
+       }
+
+       if(!valid_hostname(source_p->host))
+       {
+               sendto_one(source_p,
+                          ":%s NOTICE %s :*** Notice -- You have an illegal character in your hostname",
+                          me.name, source_p->name);
+
+               strlcpy(source_p->host, source_p->sockhost, sizeof(source_p->host));
+
+#ifdef IPV6
+               if(ConfigFileEntry.dot_in_ip6_addr == 1)
+                       strlcat(source_p->host, ".", sizeof(source_p->host));
+#endif
+       }
+
+       aconf = source_p->localClient->att_conf;
+
+       if(aconf == NULL)
+       {
+               exit_client(client_p, source_p, &me, "*** Not Authorised");
+               return (CLIENT_EXITED);
+       }
+
+       if(!IsGotId(source_p))
+       {
+               const char *p;
+               int i = 0;
+
+               if(IsNeedIdentd(aconf))
+               {
+                       ServerStats->is_ref++;
+                       sendto_one(source_p,
+                                  ":%s NOTICE %s :*** Notice -- You need to install identd to use this server",
+                                  me.name, client_p->name);
+                       exit_client(client_p, source_p, &me, "Install identd");
+                       return (CLIENT_EXITED);
+               }
+
+               /* dont replace username if its supposed to be spoofed --fl */
+               if(!IsConfDoSpoofIp(aconf) || !strchr(aconf->name, '@'))
+               {
+                       p = username;
+
+                       if(!IsNoTilde(aconf))
+                               source_p->username[i++] = '~';
+
+                       while (*p && i < USERLEN)
+                       {
+                               if(*p != '[')
+                                       source_p->username[i++] = *p;
+                               p++;
+                       }
+
+                       source_p->username[i] = '\0';
+               }
+       }
+
+       if(IsNeedSasl(aconf) && !*user->suser)
+       {
+               ServerStats->is_ref++;
+               sendto_one(source_p,
+                               ":%s NOTICE %s :*** Notice -- You need to identify via SASL to use this server",
+                               me.name, client_p->name);
+               exit_client(client_p, source_p, &me, "SASL access only");
+               return (CLIENT_EXITED);
+       }
+
+       /* password check */
+       if(!EmptyString(aconf->passwd))
+       {
+               const char *encr;
+
+               if(EmptyString(source_p->localClient->passwd))
+                       encr = "";
+               else if(IsConfEncrypted(aconf))
+                       encr = crypt(source_p->localClient->passwd, aconf->passwd);
+               else
+                       encr = source_p->localClient->passwd;
+
+               if(strcmp(encr, aconf->passwd))
+               {
+                       ServerStats->is_ref++;
+                       sendto_one(source_p, form_str(ERR_PASSWDMISMATCH), me.name, source_p->name);
+                       exit_client(client_p, source_p, &me, "Bad Password");
+                       return (CLIENT_EXITED);
+               }
+
+               /* clear password only if used now, otherwise send it
+                * to services -- jilles */
+               if(source_p->localClient->passwd)
+               {
+                       memset(source_p->localClient->passwd, 0, strlen(source_p->localClient->passwd));
+                       MyFree(source_p->localClient->passwd);
+                       source_p->localClient->passwd = NULL;
+               }
+       }
+
+       /* report if user has &^>= etc. and set flags as needed in source_p */
+       report_and_set_user_flags(source_p, aconf);
+
+       /* Limit clients */
+       /*
+        * We want to be able to have servers and F-line clients
+        * connect, so save room for "buffer" connections.
+        * Smaller servers may want to decrease this, and it should
+        * probably be just a percentage of the MAXCLIENTS...
+        *   -Taner
+        */
+       /* Except "F:" clients */
+       if(((dlink_list_length(&lclient_list) + 1) >= 
+          ((unsigned long)GlobalSetOptions.maxclients + MAX_BUFFER) ||
+           (dlink_list_length(&lclient_list) + 1) >= 
+           ((unsigned long)GlobalSetOptions.maxclients - 5)) && !(IsExemptLimits(source_p)))
+       {
+               sendto_realops_snomask(SNO_FULL, L_ALL,
+                                    "Too many clients, rejecting %s[%s].", source_p->name, source_p->host);
+
+               ServerStats->is_ref++;
+               exit_client(client_p, source_p, &me, "Sorry, server is full - try later");
+               return (CLIENT_EXITED);
+       }
+
+       /* valid user name check */
+
+       if(!valid_username(source_p->username))
+       {
+               sendto_realops_snomask(SNO_REJ, L_ALL,
+                                    "Invalid username: %s (%s@%s)",
+                                    source_p->name, source_p->username, source_p->host);
+               ServerStats->is_ref++;
+               ircsprintf(tmpstr2, "Invalid username [%s]", source_p->username);
+               exit_client(client_p, source_p, &me, tmpstr2);
+               return (CLIENT_EXITED);
+       }
+
+       /* end of valid user name check */
+
+       /* kline exemption extends to xline too */
+       if(!IsExemptKline(source_p) &&
+          find_xline(source_p->info, 1) != NULL)
+       {
+               ServerStats->is_ref++;
+               add_reject(source_p);
+               exit_client(client_p, source_p, &me, "Bad user info");
+               return CLIENT_EXITED;
+       }
+
+       /* dnsbl check */
+       if (source_p->preClient->dnsbl_listed != NULL)
+       {
+               if (IsExemptKline(source_p) || IsConfExemptDNSBL(aconf))
+                       sendto_one_notice(source_p, ":*** Your IP address %s is listed in %s, but you are exempt",
+                                       source_p->sockhost, source_p->preClient->dnsbl_listed->host);
+               else
+               {
+                       ServerStats->is_ref++;
+                       sendto_one(source_p, form_str(ERR_YOUREBANNEDCREEP),
+                                       me.name, source_p->name,
+                                       source_p->preClient->dnsbl_listed->reject_reason);
+                       sendto_one_notice(source_p, ":*** Your IP address %s is listed in %s",
+                                       source_p->sockhost, source_p->preClient->dnsbl_listed->host);
+                       source_p->preClient->dnsbl_listed->hits++;
+                       add_reject(source_p);
+                       exit_client(client_p, source_p, &me, "*** Banned (DNS blacklist)");
+                       return CLIENT_EXITED;
+               }
+       }
+
+       /* Store original hostname -- jilles */
+       strlcpy(source_p->orighost, source_p->host, HOSTLEN + 1);
+
+       /* Spoof user@host */
+       if(*source_p->preClient->spoofuser)
+               strlcpy(source_p->username, source_p->preClient->spoofuser, USERLEN + 1);
+       if(*source_p->preClient->spoofhost)
+       {
+               strlcpy(source_p->host, source_p->preClient->spoofhost, HOSTLEN + 1);
+               if (irccmp(source_p->host, source_p->orighost))
+                       SetDynSpoof(source_p);
+       }
+
+       if(IsAnyDead(client_p))
+               return CLIENT_EXITED;
+
+       inetntop_sock((struct sockaddr *)&source_p->localClient->ip, ipaddr, sizeof(ipaddr));
+
+       sendto_realops_snomask(SNO_CCONN, L_ALL,
+                            "Client connecting: %s (%s@%s) [%s] {%s} [%s]",
+                            source_p->name, source_p->username, source_p->orighost,
+                            show_ip(NULL, source_p) ? ipaddr : "255.255.255.255",
+                            get_client_class(source_p), source_p->info);
+
+       sendto_realops_snomask(SNO_CCONNEXT, L_ALL,
+                       "CLICONN %s %s %s %s %s %s 0 %s",
+                       source_p->name, source_p->username, source_p->orighost,
+                       show_ip(NULL, source_p) ? ipaddr : "255.255.255.255",
+                       get_client_class(source_p),
+                       /* mirc can sometimes send ips here */
+                       show_ip(NULL, source_p) ? source_p->localClient->fullcaps : "<hidden> <hidden>",
+                       source_p->info);
+
+       /* If they have died in send_* don't do anything. */
+       if(IsAnyDead(source_p))
+               return CLIENT_EXITED;
+
+       add_to_hostname_hash(source_p->orighost, source_p);
+
+       /* Allocate a UID if it was not previously allocated.
+        * If this already occured, it was probably during SASL auth...
+        */
+       if(!*source_p->id)
+       {
+               strcpy(source_p->id, generate_uid());
+               add_to_id_hash(source_p->id, source_p);
+       }
+
+       source_p->umodes |= ConfigFileEntry.default_umodes & ~ConfigFileEntry.oper_only_umodes;
+
+       if (source_p->umodes & UMODE_INVISIBLE)
+               Count.invisi++;
+
+       s_assert(!IsClient(source_p));
+       dlinkMoveNode(&source_p->localClient->tnode, &unknown_list, &lclient_list);
+       SetClient(source_p);
+
+       /* XXX source_p->servptr is &me, since local client */
+       source_p->servptr = find_server(NULL, user->server);
+       dlinkAdd(source_p, &source_p->lnode, &source_p->servptr->serv->users);
+       /* Increment our total user count here */
+       if(++Count.total > Count.max_tot)
+               Count.max_tot = Count.total;
+       source_p->localClient->allow_read = MAX_FLOOD_BURST;
+
+       Count.totalrestartcount++;
+
+       s_assert(source_p->localClient != NULL);
+
+       if(dlink_list_length(&lclient_list) > (unsigned long)Count.max_loc)
+       {
+               Count.max_loc = dlink_list_length(&lclient_list);
+               if(!(Count.max_loc % 10))
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "New Max Local Clients: %d", Count.max_loc);
+       }
+
+       /* they get a reduced limit */
+       if(find_tgchange(source_p->sockhost))
+               USED_TARGETS(source_p) = 6;
+
+       call_hook(h_new_local_user, source_p);
+
+       monitor_signon(source_p);
+       user_welcome(source_p);
+
+       free_pre_client(source_p);
+
+       return (introduce_client(client_p, source_p, user, source_p->name, 1));
+}
+
+/*
+ * introduce_clients
+ *
+ * inputs      -
+ * output      -
+ * side effects - This common function introduces a client to the rest
+ *               of the net, either from a local client connect or
+ *               from a remote connect.
+ */
+int
+introduce_client(struct Client *client_p, struct Client *source_p, struct User *user, const char *nick, int use_euid)
+{
+       static char ubuf[12];
+       struct Client *identifyservice_p;
+       char *p;
+       hook_data_umode_changed hdata;
+       hook_data_client hdata2;
+
+       if(MyClient(source_p))
+               send_umode(source_p, source_p, 0, 0, ubuf);
+       else
+               send_umode(NULL, source_p, 0, 0, ubuf);
+
+       if(!*ubuf)
+       {
+               ubuf[0] = '+';
+               ubuf[1] = '\0';
+       }
+
+       /* if it has an ID, introduce it with its id to TS6 servers,
+        * otherwise introduce it normally to all.
+        */
+       if(has_id(source_p))
+       {
+               char sockhost[HOSTLEN];
+               if(source_p->sockhost[0] == ':')
+               {
+                       sockhost[0] = '0';
+                       sockhost[1] = '\0';
+                       strlcat(sockhost, source_p->sockhost, sizeof(sockhost));
+               } else
+                       strcpy(sockhost, source_p->sockhost);
+               
+               if (use_euid)
+                       sendto_server(client_p, NULL, CAP_EUID | CAP_TS6, NOCAPS,
+                                       ":%s EUID %s %d %ld %s %s %s %s %s %s %s :%s",
+                                       source_p->servptr->id, nick,
+                                       source_p->hopcount + 1,
+                                       (long) source_p->tsinfo, ubuf,
+                                       source_p->username, source_p->host,
+                                       IsIPSpoof(source_p) ? "0" : sockhost,
+                                       source_p->id,
+                                       IsDynSpoof(source_p) ? source_p->orighost : "*",
+                                       EmptyString(source_p->user->suser) ? "*" : source_p->user->suser,
+                                       source_p->info);
+
+               sendto_server(client_p, NULL, CAP_TS6, use_euid ? CAP_EUID : NOCAPS,
+                             ":%s UID %s %d %ld %s %s %s %s %s :%s",
+                             source_p->servptr->id, nick,
+                             source_p->hopcount + 1,
+                             (long) source_p->tsinfo, ubuf,
+                             source_p->username, source_p->host,
+                             IsIPSpoof(source_p) ? "0" : sockhost,
+                             source_p->id, source_p->info);
+
+               sendto_server(client_p, NULL, NOCAPS, CAP_TS6,
+                             "NICK %s %d %ld %s %s %s %s :%s",
+                             nick, source_p->hopcount + 1,
+                             (long) source_p->tsinfo,
+                             ubuf, source_p->username, source_p->host,
+                             user->server, source_p->info);
+       }
+       else
+               sendto_server(client_p, NULL, NOCAPS, NOCAPS,
+                             "NICK %s %d %ld %s %s %s %s :%s",
+                             nick, source_p->hopcount + 1,
+                             (long) source_p->tsinfo,
+                             ubuf, source_p->username, source_p->host,
+                             user->server, source_p->info);
+
+       if (IsDynSpoof(source_p))
+       {
+               sendto_server(client_p, NULL, CAP_TS6, use_euid ? CAP_EUID : NOCAPS, ":%s ENCAP * REALHOST %s",
+                               use_id(source_p), source_p->orighost);
+               sendto_server(client_p, NULL, NOCAPS, CAP_TS6, ":%s ENCAP * REALHOST %s",
+                               source_p->name, source_p->orighost);
+       }
+       if (!EmptyString(source_p->user->suser))
+       {
+               sendto_server(client_p, NULL, CAP_TS6, use_euid ? CAP_EUID : NOCAPS, ":%s ENCAP * LOGIN %s",
+                               use_id(source_p), source_p->user->suser);
+               sendto_server(client_p, NULL, NOCAPS, CAP_TS6, ":%s ENCAP * LOGIN %s",
+                               source_p->name, source_p->user->suser);
+       }
+
+       if(MyConnect(source_p) && source_p->localClient->passwd)
+       {
+               if (ConfigFileEntry.identifyservice[0] != '\0' &&
+                               ConfigFileEntry.identifycommand[0] != '\0')
+               {
+                       /* use user@server */
+                       p = strchr(ConfigFileEntry.identifyservice, '@');
+                       if (p != NULL)
+                               identifyservice_p = find_named_client(p + 1);
+                       else
+                               identifyservice_p = NULL;
+                       if (identifyservice_p != NULL)
+                               sendto_one(identifyservice_p, ":%s PRIVMSG %s :%s %s",
+                                               get_id(source_p, identifyservice_p),
+                                               ConfigFileEntry.identifyservice,
+                                               ConfigFileEntry.identifycommand,
+                                               source_p->localClient->passwd);
+               }
+               memset(source_p->localClient->passwd, 0, strlen(source_p->localClient->passwd));
+               MyFree(source_p->localClient->passwd);
+               source_p->localClient->passwd = NULL;
+       }
+
+       /* let modules providing usermodes know that we've got a new user,
+        * why is this here? -- well, some modules need to be able to send out new
+        * information about a client, so this was the best place to do it
+        *    --nenolod
+        */
+       hdata.client = source_p;
+       hdata.oldumodes = 0;
+       hdata.oldsnomask = 0;
+       call_hook(h_umode_changed, &hdata);
+
+       /* On the other hand, some modules need to know when a client is
+        * being introduced, period.
+        * --gxti
+        */
+       hdata2.client = client_p;
+       hdata2.target = source_p;
+       call_hook(h_introduce_client, &hdata2);
+
+       return 0;
+}
+
+/* 
+ * valid_hostname - check hostname for validity
+ *
+ * Inputs       - pointer to user
+ * Output       - YES if valid, NO if not
+ * Side effects - NONE
+ *
+ * NOTE: this doesn't allow a hostname to begin with a dot and
+ * will not allow more dots than chars.
+ */
+int
+valid_hostname(const char *hostname)
+{
+       const char *p = hostname;
+       int found_sep = 0;
+
+       s_assert(NULL != p);
+
+       if(hostname == NULL)
+               return NO;
+
+       if('.' == *p || ':' == *p)
+               return NO;
+
+       while (*p)
+       {
+               if(!IsHostChar(*p))
+                       return NO;
+                if(*p == '.' || *p == ':')
+                       found_sep++;
+               p++;
+       }
+
+       if(found_sep == 0)
+               return(NO);
+
+       return (YES);
+}
+
+/* 
+ * valid_username - check username for validity
+ *
+ * Inputs       - pointer to user
+ * Output       - YES if valid, NO if not
+ * Side effects - NONE
+ * 
+ * Absolutely always reject any '*' '!' '?' '@' in an user name
+ * reject any odd control characters names.
+ * Allow '.' in username to allow for "first.last"
+ * style of username
+ */
+int
+valid_username(const char *username)
+{
+       int dots = 0;
+       const char *p = username;
+
+       s_assert(NULL != p);
+
+       if(username == NULL)
+               return NO;
+
+       if('~' == *p)
+               ++p;
+
+       /* reject usernames that don't start with an alphanum
+        * i.e. reject jokers who have '-@somehost' or '.@somehost'
+        * or "-hi-@somehost", "h-----@somehost" would still be accepted.
+        */
+       if(!IsAlNum(*p))
+               return NO;
+
+       while (*++p)
+       {
+               if((*p == '.') && ConfigFileEntry.dots_in_ident)
+               {
+                       dots++;
+                       if(dots > ConfigFileEntry.dots_in_ident)
+                               return NO;
+                       if(!IsUserChar(p[1]))
+                               return NO;
+               }
+               else if(!IsUserChar(*p))
+                       return NO;
+       }
+       return YES;
+}
+
+/* report_and_set_user_flags
+ *
+ * Inputs       - pointer to source_p
+ *              - pointer to aconf for this user
+ * Output       - NONE
+ * Side effects -
+ * Report to user any special flags they are getting, and set them.
+ */
+
+static void
+report_and_set_user_flags(struct Client *source_p, struct ConfItem *aconf)
+{
+       /* If this user is being spoofed, tell them so */
+       if(IsConfDoSpoofIp(aconf))
+       {
+               sendto_one(source_p,
+                          ":%s NOTICE %s :*** Spoofing your IP. congrats.",
+                          me.name, source_p->name);
+       }
+
+       /* If this user is in the exception class, Set it "E lined" */
+       if(IsConfExemptKline(aconf))
+       {
+               SetExemptKline(source_p);
+               sendto_one(source_p,
+                          ":%s NOTICE %s :*** You are exempt from K/D/G/X lines. congrats.",
+                          me.name, source_p->name);
+       }
+
+       if(IsConfExemptGline(aconf))
+       {
+               SetExemptGline(source_p);
+
+               /* dont send both a kline and gline exempt notice */
+               if(!IsConfExemptKline(aconf))
+                       sendto_one(source_p,
+                                  ":%s NOTICE %s :*** You are exempt from G lines.",
+                                  me.name, source_p->name);
+       }
+
+       if(IsConfExemptDNSBL(aconf))
+               /* kline exempt implies this, don't send both */
+               if(!IsConfExemptKline(aconf))
+                       sendto_one(source_p,
+                                  ":%s NOTICE %s :*** You are exempt from DNS blacklists.",
+                                  me.name, source_p->name);
+
+       /* If this user is exempt from user limits set it F lined" */
+       if(IsConfExemptLimits(aconf))
+       {
+               SetExemptLimits(source_p);
+               sendto_one(source_p,
+                          ":%s NOTICE %s :*** You are exempt from user limits. congrats.",
+                          me.name, source_p->name);
+       }
+
+       /* If this user is exempt from idle time outs */
+       if(IsConfIdlelined(aconf))
+       {
+               SetIdlelined(source_p);
+               sendto_one(source_p,
+                          ":%s NOTICE %s :*** You are exempt from idle limits. congrats.",
+                          me.name, source_p->name);
+       }
+
+       if(IsConfExemptFlood(aconf))
+       {
+               SetExemptFlood(source_p);
+               sendto_one(source_p,
+                          ":%s NOTICE %s :*** You are exempt from flood limits.",
+                          me.name, source_p->name);
+       }
+
+       if(IsConfExemptSpambot(aconf))
+       {
+               SetExemptSpambot(source_p);
+               sendto_one(source_p,
+                          ":%s NOTICE %s :*** You are exempt from spambot checks.",
+                          me.name, source_p->name);
+       }
+
+       if(IsConfExemptJupe(aconf))
+       {
+               SetExemptJupe(source_p);
+               sendto_one(source_p,
+                               ":%s NOTICE %s :*** You are exempt from juped channel warnings.",
+                               me.name, source_p->name);
+       }
+
+       if(IsConfExemptResv(aconf))
+       {
+               SetExemptResv(source_p);
+               sendto_one(source_p,
+                               ":%s NOTICE %s :*** You are exempt from resvs.",
+                               me.name, source_p->name);
+       }
+
+       if(IsConfExemptShide(aconf))
+       {
+               SetExemptShide(source_p);
+               sendto_one(source_p,
+                          ":%s NOTICE %s :*** You are exempt from serverhiding.",
+                          me.name, source_p->name);
+       }
+}
+
+/*
+ * user_mode - set get current users mode
+ *
+ * m_umode() added 15/10/91 By Darren Reed.
+ * parv[0] - sender
+ * parv[1] - username to change mode for
+ * parv[2] - modes to change
+ */
+int
+user_mode(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       int flag;
+       int i;
+       char *m;
+       const char *pm;
+       struct Client *target_p;
+       int what, setflags;
+       int badflag = NO;       /* Only send one bad flag notice */
+       int showsnomask = NO;
+       unsigned int setsnomask;
+       char buf[BUFSIZE];
+       hook_data_umode_changed hdata;
+
+       what = MODE_ADD;
+
+       if(parc < 2)
+       {
+               sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "MODE");
+               return 0;
+       }
+
+       if((target_p = MyClient(source_p) ? find_named_person(parv[1]) : find_person(parv[1])) == NULL)
+       {
+               if(MyConnect(source_p))
+                       sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
+                                          form_str(ERR_NOSUCHCHANNEL), parv[1]);
+               return 0;
+       }
+
+       /* Dont know why these were commented out..
+        * put them back using new sendto() funcs
+        */
+
+       if(IsServer(source_p))
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ADMIN,
+                                    "*** Mode for User %s from %s", parv[1], source_p->name);
+               return 0;
+       }
+
+       if(source_p != target_p || target_p->from != source_p->from)
+       {
+               sendto_one(source_p, form_str(ERR_USERSDONTMATCH), me.name, source_p->name);
+               return 0;
+       }
+
+       if(parc < 3)
+       {
+               m = buf;
+               *m++ = '+';
+
+               for (i = 0; i < 128; i++) /* >= 127 is extended ascii */
+                       if (source_p->umodes & user_modes[i])
+                               *m++ = (char) i;
+
+               *m = '\0';
+               sendto_one(source_p, form_str(RPL_UMODEIS), me.name, source_p->name, buf);
+               if (source_p->snomask != 0)
+                       sendto_one(source_p, form_str(RPL_SNOMASK), me.name, source_p->name,
+                               construct_snobuf(source_p->snomask));
+               return 0;
+       }
+
+       /* find flags already set for user */
+       setflags = source_p->umodes;
+       setsnomask = source_p->snomask;
+
+       /*
+        * parse mode change string(s)
+        */
+       for (pm = parv[2]; *pm; pm++)
+               switch (*pm)
+               {
+               case '+':
+                       what = MODE_ADD;
+                       break;
+               case '-':
+                       what = MODE_DEL;
+                       break;
+
+               case 'o':
+                       if(what == MODE_ADD)
+                       {
+                               if(IsServer(client_p) && !IsOper(source_p))
+                               {
+                                       ++Count.oper;
+                                       SetOper(source_p);
+                                       dlinkAddAlloc(source_p, &oper_list);
+                               }
+                       }
+                       else
+                       {
+                               /* Only decrement the oper counts if an oper to begin with
+                                * found by Pat Szuta, Perly , perly@xnet.com 
+                                */
+
+                               if(!IsOper(source_p))
+                                       break;
+
+                               ClearOper(source_p);
+
+                               Count.oper--;
+
+                               if(MyConnect(source_p))
+                               {
+                                       source_p->umodes &= ~ConfigFileEntry.oper_only_umodes;
+                                       if (!(source_p->umodes & UMODE_SERVNOTICE) && source_p->snomask != 0)
+                                       {
+                                               source_p->snomask = 0;
+                                               showsnomask = YES;
+                                       }
+                                       source_p->flags2 &= ~OPER_FLAGS;
+
+                                       MyFree(source_p->localClient->opername);
+                                       source_p->localClient->opername = NULL;
+
+                                       dlinkFindDestroy(source_p, &local_oper_list);
+                               }
+
+                               dlinkFindDestroy(source_p, &oper_list);
+                       }
+                       break;
+
+                       /* we may not get these,
+                        * but they shouldnt be in default
+                        */
+
+               /* can only be set on burst */
+               case 'S':
+               case ' ':
+               case '\n':
+               case '\r':
+               case '\t':
+                       break;
+
+               case 's':
+                       if (MyConnect(source_p))
+                       {
+                               if(!IsOper(source_p)
+                                               && (ConfigFileEntry.oper_only_umodes & UMODE_SERVNOTICE))
+                               {
+                                       if (what == MODE_ADD || source_p->umodes & UMODE_SERVNOTICE)
+                                               badflag = YES;
+                                       continue;
+                               }
+                               showsnomask = YES;
+                               if(what == MODE_ADD)
+                               {
+                                       if (parc > 3)
+                                               source_p->snomask = parse_snobuf_to_mask(source_p->snomask, parv[3]);
+                                       else
+                                               source_p->snomask |= SNO_GENERAL;
+                               }
+                               else
+                                       source_p->snomask = 0;
+                               if (source_p->snomask != 0)
+                                       source_p->umodes |= UMODE_SERVNOTICE;
+                               else
+                                       source_p->umodes &= ~UMODE_SERVNOTICE;
+                               break;
+                       }
+                       /* FALLTHROUGH */
+               default:
+                       if (MyConnect(source_p) && *pm == 'Q' && !ConfigChannel.use_forward) {
+                               badflag = YES;
+                               break;
+                       }
+
+                       if((flag = user_modes[(unsigned char) *pm]))
+                       {
+                               if(MyConnect(source_p)
+                                  && !IsOper(source_p)
+                                  && (ConfigFileEntry.oper_only_umodes & flag))
+                               {
+                                       if (what == MODE_ADD || source_p->umodes & flag)
+                                               badflag = YES;
+                               }
+                               else
+                               {
+                                       if(what == MODE_ADD)
+                                               source_p->umodes |= flag;
+                                       else
+                                               source_p->umodes &= ~flag;
+                               }
+                       }
+                       else
+                       {
+                               if(MyConnect(source_p))
+                                       badflag = YES;
+                       }
+                       break;
+               }
+
+       if(badflag)
+               sendto_one(source_p, form_str(ERR_UMODEUNKNOWNFLAG), me.name, source_p->name);
+
+       if(MyClient(source_p) && (source_p->snomask & SNO_NCHANGE) && !IsOperN(source_p))
+       {
+               sendto_one(source_p,
+                          ":%s NOTICE %s :*** You need oper and N flag for +s +n", me.name, parv[0]);
+               source_p->snomask &= ~SNO_NCHANGE;      /* only tcm's really need this */
+       }
+
+       if(MyClient(source_p) && (source_p->umodes & UMODE_OPERWALL) && !IsOperOperwall(source_p))
+       {
+               sendto_one(source_p,
+                          ":%s NOTICE %s :*** You need oper and operwall flag for +z", me.name, parv[0]);
+               source_p->umodes &= ~UMODE_OPERWALL;
+       }
+
+       if(MyConnect(source_p) && (source_p->umodes & UMODE_ADMIN) &&
+          (!IsOperAdmin(source_p) || IsOperHiddenAdmin(source_p)))
+       {
+               sendto_one(source_p,
+                          ":%s NOTICE %s :*** You need oper and A flag for +a", me.name, parv[0]);
+               source_p->umodes &= ~UMODE_ADMIN;
+       }
+
+       /* let modules providing usermodes know that we've changed our usermode --nenolod */
+       hdata.client = source_p;
+       hdata.oldumodes = setflags;
+       hdata.oldsnomask = setsnomask;
+       call_hook(h_umode_changed, &hdata);
+
+       if(!(setflags & UMODE_INVISIBLE) && IsInvisible(source_p))
+               ++Count.invisi;
+       if((setflags & UMODE_INVISIBLE) && !IsInvisible(source_p))
+               --Count.invisi;
+       /*
+        * compare new flags with old flags and send string which
+        * will cause servers to update correctly.
+        */
+       send_umode_out(client_p, source_p, setflags);
+       if (showsnomask && MyConnect(source_p))
+               sendto_one(source_p, form_str(RPL_SNOMASK), me.name, source_p->name,
+                       construct_snobuf(source_p->snomask));
+
+       return (0);
+}
+
+/*
+ * send the MODE string for user (user) to connection client_p
+ * -avalon
+ */
+void
+send_umode(struct Client *client_p, struct Client *source_p, int old, int sendmask, char *umode_buf)
+{
+       int i;
+       int flag;
+       char *m;
+       int what = 0;
+
+       /*
+        * build a string in umode_buf to represent the change in the user's
+        * mode between the new (source_p->flag) and 'old'.
+        */
+       m = umode_buf;
+       *m = '\0';
+
+       for (i = 0; i < 128; i++)
+       {
+               flag = user_modes[i];
+
+               if((flag & old) && !(source_p->umodes & flag))
+               {
+                       if(what == MODE_DEL)
+                               *m++ = (char) i;
+                       else
+                       {
+                               what = MODE_DEL;
+                               *m++ = '-';
+                               *m++ = (char) i;
+                       }
+               }
+               else if(!(flag & old) && (source_p->umodes & flag))
+               {
+                       if(what == MODE_ADD)
+                               *m++ = (char) i;
+                       else
+                       {
+                               what = MODE_ADD;
+                               *m++ = '+';
+                               *m++ = (char) i;
+                       }
+               }
+       }
+       *m = '\0';
+
+       if(*umode_buf && client_p)
+               sendto_one(client_p, ":%s MODE %s :%s", source_p->name, source_p->name, umode_buf);
+}
+
+/*
+ * send_umode_out
+ *
+ * inputs      -
+ * output      - NONE
+ * side effects - 
+ */
+void
+send_umode_out(struct Client *client_p, struct Client *source_p, int old)
+{
+       struct Client *target_p;
+       char buf[BUFSIZE];
+       dlink_node *ptr;
+
+       send_umode(NULL, source_p, old, 0, buf);
+
+       DLINK_FOREACH(ptr, serv_list.head)
+       {
+               target_p = ptr->data;
+
+               if((target_p != client_p) && (target_p != source_p) && (*buf))
+               {
+                       sendto_one(target_p, ":%s MODE %s :%s",
+                                  get_id(source_p, target_p), 
+                                  get_id(source_p, target_p), buf);
+               }
+       }
+
+       if(client_p && MyClient(client_p))
+               send_umode(client_p, source_p, old, 0, buf);
+}
+
+/* 
+ * user_welcome
+ *
+ * inputs      - client pointer to client to welcome
+ * output      - NONE
+ * side effects        -
+ */
+void
+user_welcome(struct Client *source_p)
+{
+       sendto_one(source_p, form_str(RPL_WELCOME), me.name, source_p->name,
+                  ServerInfo.network_name, source_p->name);
+       sendto_one(source_p, form_str(RPL_YOURHOST), me.name,
+                  source_p->name,
+                  get_listener_name(source_p->localClient->listener), ircd_version);
+
+       sendto_one(source_p, form_str(RPL_CREATED), me.name, source_p->name, creation);
+       sendto_one(source_p, form_str(RPL_MYINFO), me.name, source_p->name, me.name, ircd_version, umodebuf);
+
+       show_isupport(source_p);
+
+       show_lusers(source_p);
+
+       if(ConfigFileEntry.short_motd)
+       {
+               sendto_one(source_p,
+                          "NOTICE %s :*** Notice -- motd was last changed at %s",
+                          source_p->name, user_motd_changed);
+
+               sendto_one(source_p,
+                          "NOTICE %s :*** Notice -- Please read the motd if you haven't read it",
+                          source_p->name);
+
+               sendto_one(source_p, form_str(RPL_MOTDSTART), 
+                          me.name, source_p->name, me.name);
+
+               sendto_one(source_p, form_str(RPL_MOTD),
+                          me.name, source_p->name, "*** This is the short motd ***");
+
+               sendto_one(source_p, form_str(RPL_ENDOFMOTD), me.name, source_p->name);
+       }
+       else
+               send_user_motd(source_p);
+}
+
+/* oper_up()
+ *
+ * inputs      - pointer to given client to oper
+ *             - pointer to ConfItem to use
+ * output      - none
+ * side effects        - opers up source_p using aconf for reference
+ */
+int
+oper_up(struct Client *source_p, struct oper_conf *oper_p)
+{
+       unsigned int old = source_p->umodes, oldsnomask = source_p->snomask;
+       hook_data_umode_changed hdata;
+
+       SetOper(source_p);
+
+       if(oper_p->umodes)
+               source_p->umodes |= oper_p->umodes;
+       else if(ConfigFileEntry.oper_umodes)
+               source_p->umodes |= ConfigFileEntry.oper_umodes;
+       else
+               source_p->umodes |= DEFAULT_OPER_UMODES;
+
+       if (oper_p->snomask)
+       {
+               source_p->snomask |= oper_p->snomask;
+               source_p->umodes |= UMODE_SERVNOTICE;
+       }
+       else if (source_p->umodes & UMODE_SERVNOTICE)
+       {
+               /* Only apply these if +s is already set -- jilles */
+               if (ConfigFileEntry.oper_snomask)
+                       source_p->snomask |= ConfigFileEntry.oper_snomask;
+               else
+                       source_p->snomask |= DEFAULT_OPER_SNOMASK;
+       }
+
+       Count.oper++;
+
+       SetExemptKline(source_p);
+
+       source_p->flags2 |= oper_p->flags;
+       DupString(source_p->localClient->opername, oper_p->name);
+
+       dlinkAddAlloc(source_p, &local_oper_list);
+       dlinkAddAlloc(source_p, &oper_list);
+
+       if(IsOperAdmin(source_p) && !IsOperHiddenAdmin(source_p))
+               source_p->umodes |= UMODE_ADMIN;
+       if(!IsOperN(source_p))
+               source_p->snomask &= ~SNO_NCHANGE;
+       if(!IsOperOperwall(source_p))
+               source_p->umodes &= ~UMODE_OPERWALL;
+       hdata.client = source_p;
+       hdata.oldumodes = old;
+       hdata.oldsnomask = oldsnomask;
+       call_hook(h_umode_changed, &hdata);
+
+       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                            "%s (%s@%s) is now an operator", source_p->name,
+                            source_p->username, source_p->host);
+       send_umode_out(source_p, source_p, old);
+       sendto_one(source_p, form_str(RPL_SNOMASK), me.name, source_p->name,
+                  construct_snobuf(source_p->snomask));
+       sendto_one(source_p, form_str(RPL_YOUREOPER), me.name, source_p->name);
+       sendto_one(source_p, ":%s NOTICE %s :*** Oper privs are %s", me.name,
+                  source_p->name, get_oper_privs(oper_p->flags));
+       send_oper_motd(source_p);
+
+       return (1);
+}
+
+void
+construct_umodebuf(void)
+{
+       int i;
+       char *ptr = umodebuf;
+
+       *ptr = '\0';
+
+       for (i = 0; i < 128; i++)
+               if (user_modes[i])
+                       *ptr++ = (char) i;
+
+       *ptr++ = '\0';
+}
+
+void
+change_nick_user_host(struct Client *target_p, const char *nick, const char *user,
+                     const char *host, int newts, char *format, ...)
+{
+       dlink_node *ptr;
+       struct Channel *chptr;
+       struct membership *mscptr;
+       int changed = irccmp(target_p->name, nick);
+       int changed_case = strcmp(target_p->name, nick);
+       int do_qjm = irccmp(target_p->username, user) || irccmp(target_p->host, host);
+       char mode[10], modeval[NICKLEN * 2 + 2], reason[256], *mptr;
+       va_list ap;
+
+       modeval[0] = '\0';
+       
+       if(changed)
+       {
+               target_p->tsinfo = newts;
+               monitor_signoff(target_p);
+       }
+       invalidate_bancache_user(target_p);
+
+       if(do_qjm)
+       {
+               va_start(ap, format);
+               vsnprintf(reason, 255, format, ap);
+               va_end(ap);
+
+               sendto_common_channels_local_butone(target_p, ":%s!%s@%s QUIT :%s",
+                               target_p->name, target_p->username, target_p->host,
+                               reason);
+
+               DLINK_FOREACH(ptr, target_p->user->channel.head)
+               {
+                       mscptr = ptr->data;
+                       chptr = mscptr->chptr;
+                       mptr = mode;
+
+                       if(is_chanop(mscptr))
+                       {
+                               *mptr++ = 'o';
+                               strcat(modeval, nick);
+                               strcat(modeval, " ");
+                       }
+
+                       if(is_voiced(mscptr))
+                       {
+                               *mptr++ = 'v';
+                               strcat(modeval, nick);
+                       }
+
+                       *mptr = '\0';
+
+                       sendto_channel_local_butone(target_p, ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s",
+                                       nick, user, host, chptr->chname);
+                       if(*mode)
+                               sendto_channel_local_butone(target_p, ALL_MEMBERS, chptr,
+                                               ":%s MODE %s +%s %s",
+                                               target_p->servptr->name,
+                                               chptr->chname, mode, modeval);
+
+                       *modeval = '\0';
+               }
+
+               if(MyClient(target_p) && changed_case)
+                       sendto_one(target_p, ":%s!%s@%s NICK %s",
+                                       target_p->name, target_p->username, target_p->host, nick);
+       }
+       else if(changed_case)
+       {
+               sendto_common_channels_local(target_p, ":%s!%s@%s NICK :%s",
+                               target_p->name, target_p->username,
+                               target_p->host, nick);
+       }
+
+       strlcpy(target_p->username, user, USERLEN);
+       strlcpy(target_p->host, host, HOSTLEN);
+
+       if (changed)
+               add_history(target_p, 1);
+
+       del_from_client_hash(target_p->name, target_p);
+       strlcpy(target_p->name, nick, NICKLEN);
+       add_to_client_hash(target_p->name, target_p);
+
+       if(changed)
+       {
+               monitor_signon(target_p);
+               del_all_accepts(target_p);
+       }
+}
diff --git a/src/scache.c b/src/scache.c
new file mode 100644 (file)
index 0000000..0819bbd
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  scache.c: Server names cache.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: scache.c 6 2005-09-10 01:02:21Z nenolod $
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "common.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "scache.h"
+#include "memory.h"
+
+
+/*
+ * ircd used to store full servernames in anUser as well as in the 
+ * whowas info.  there can be some 40k such structures alive at any
+ * given time, while the number of unique server names a server sees
+ * in its lifetime is at most a few hundred.  by tokenizing server
+ * names internally, the server can easily save 2 or 3 megs of RAM.  
+ * -orabidoo
+ */
+
+
+#define SCACHE_HASH_SIZE 257
+
+typedef struct scache_entry
+{
+       char name[HOSTLEN + 1];
+       struct scache_entry *next;
+}
+SCACHE;
+
+static SCACHE *scache_hash[SCACHE_HASH_SIZE];
+
+void
+clear_scache_hash_table(void)
+{
+       memset(scache_hash, 0, sizeof(scache_hash));
+}
+
+static int
+sc_hash(const char *string)
+{
+       int hash_value;
+
+       hash_value = 0;
+       while (*string)
+       {
+               hash_value += ToLower(*string++);
+       }
+
+       return hash_value % SCACHE_HASH_SIZE;
+}
+
+/*
+ * this takes a server name, and returns a pointer to the same string
+ * (up to case) in the server name token list, adding it to the list if
+ * it's not there.  care must be taken not to call this with
+ * user-supplied arguments that haven't been verified to be a valid,
+ * existing, servername.  use the hash in list.c for those.  -orabidoo
+ */
+
+const char *
+find_or_add(const char *name)
+{
+       int hash_index;
+       SCACHE *ptr;
+
+       ptr = scache_hash[hash_index = sc_hash(name)];
+       for (; ptr; ptr = ptr->next)
+       {
+               if(!irccmp(ptr->name, name))
+                       return (ptr->name);
+       }
+
+       ptr = (SCACHE *) MyMalloc(sizeof(SCACHE));
+       s_assert(0 != ptr);
+
+       strlcpy(ptr->name, name, sizeof(ptr->name));
+
+       ptr->next = scache_hash[hash_index];
+       scache_hash[hash_index] = ptr;
+       return ptr->name;
+}
+
+/*
+ * count_scache
+ * inputs      - pointer to where to leave number of servers cached
+ *             - pointer to where to leave total memory usage
+ * output      - NONE
+ * side effects        -
+ */
+void
+count_scache(size_t * number_servers_cached, size_t * mem_servers_cached)
+{
+       SCACHE *scache_ptr;
+       int i;
+
+       *number_servers_cached = 0;
+       *mem_servers_cached = 0;
+
+       for (i = 0; i < SCACHE_HASH_SIZE; i++)
+       {
+               scache_ptr = scache_hash[i];
+               while (scache_ptr)
+               {
+                       *number_servers_cached = *number_servers_cached + 1;
+                       *mem_servers_cached = *mem_servers_cached +
+                               (strlen(scache_ptr->name) + sizeof(SCACHE *));
+
+                       scache_ptr = scache_ptr->next;
+               }
+       }
+}
diff --git a/src/send.c b/src/send.c
new file mode 100644 (file)
index 0000000..bafeb0a
--- /dev/null
@@ -0,0 +1,1239 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  send.c: Functions for sending messages.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: send.c 1379 2006-05-20 14:11:07Z jilles $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "send.h"
+#include "channel.h"
+#include "class.h"
+#include "client.h"
+#include "common.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "commio.h"
+#include "s_serv.h"
+#include "sprintf_irc.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "linebuf.h"
+#include "s_log.h"
+#include "memory.h"
+#include "hook.h"
+
+#define LOG_BUFSIZE 2048
+
+/* send the message to the link the target is attached to */
+#define send_linebuf(a,b) _send_linebuf((a->from ? a->from : a) ,b)
+
+unsigned long current_serial = 0L;
+
+/* send_linebuf()
+ *
+ * inputs      - client to send to, linebuf to attach
+ * outputs     -
+ * side effects - linebuf is attached to client
+ */
+static int
+_send_linebuf(struct Client *to, buf_head_t *linebuf)
+{
+       if(IsMe(to))
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "Trying to send message to myself!");
+               return 0;
+       }
+
+       if(!MyConnect(to) || IsIOError(to))
+               return 0;
+
+       if(linebuf_len(&to->localClient->buf_sendq) > get_sendq(to))
+       {
+               if(IsServer(to))
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "Max SendQ limit exceeded for %s: %u > %lu",
+                                            get_server_name(to, HIDE_IP),
+                                            linebuf_len(&to->localClient->buf_sendq), 
+                                            get_sendq(to));
+
+                       ilog(L_SERVER, "Max SendQ limit exceeded for %s: %u > %lu",
+                            log_client_name(to, SHOW_IP),
+                            linebuf_len(&to->localClient->buf_sendq), 
+                            get_sendq(to));
+               }
+
+               if(IsClient(to))
+                       to->flags |= FLAGS_SENDQEX;
+
+               dead_link(to);
+               return -1;
+       }
+       else
+       {
+               /* just attach the linebuf to the sendq instead of
+                * generating a new one
+                */
+               linebuf_attach(&to->localClient->buf_sendq, linebuf);
+       }
+
+       /*
+        ** 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.
+        */
+       to->localClient->sendM += 1;
+       me.localClient->sendM += 1;
+       if(linebuf_len(&to->localClient->buf_sendq) > 0)
+               send_queued_write(to->localClient->fd, to);
+       return 0;
+}
+
+/* send_linebuf_remote()
+ *
+ * inputs      - client to attach to, sender, linebuf
+ * outputs     -
+ * side effects - client has linebuf attached
+ */
+static void
+send_linebuf_remote(struct Client *to, struct Client *from, buf_head_t *linebuf)
+{
+       if(to->from)
+               to = to->from;
+
+       /* test for fake direction */
+       if(!MyClient(from) && IsPerson(to) && (to == from->from))
+       {
+               if(IsServer(from))
+               {
+                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                            "Send message to %s[%s] dropped from %s(Fake Dir)",
+                                            to->name, to->from->name, from->name);
+                       return;
+               }
+
+               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                                    "Ghosted: %s[%s@%s] from %s[%s@%s] (%s)",
+                                    to->name, to->username, to->host,
+                                    from->name, from->username, from->host, to->from->name);
+               kill_client_serv_butone(NULL, to, "%s (%s[%s@%s] Ghosted %s)",
+                                       me.name, to->name, to->username,
+                                       to->host, to->from->name);
+
+               to->flags |= FLAGS_KILLED;
+
+               exit_client(NULL, to, &me, "Ghosted client");
+               return;
+       }
+
+       _send_linebuf(to, linebuf);
+       return;
+}
+
+/* send_queued_write()
+ *
+ * inputs      - fd to have queue sent, client we're sending to
+ * outputs     - contents of queue
+ * side effects - write is rescheduled if queue isnt emptied
+ */
+void
+send_queued_write(int fd, void *data)
+{
+       struct Client *to = data;
+       int retlen;
+       int flags;
+#ifdef USE_IODEBUG_HOOKS
+       hook_data_int hd;
+#endif
+       /* cant write anything to a dead socket. */
+       if(IsIOError(to))
+               return;
+
+#ifdef USE_IODEBUG_HOOKS
+       hd.client = to;
+       if(to->localClient->buf_sendq.list.head)
+               hd.arg1 = ((buf_line_t *) to->localClient->buf_sendq.list.head->data)->buf +
+                            to->localClient->buf_sendq.writeofs;
+#endif
+
+       if(linebuf_len(&to->localClient->buf_sendq))
+       {
+               while ((retlen =
+                       linebuf_flush(to->localClient->fd, &to->localClient->buf_sendq)) > 0)
+               {
+                       /* We have some data written .. update counters */
+#ifdef USE_IODEBUG_HOOKS
+                        hd.arg2 = retlen;
+                        call_hook(h_iosend_id, &hd);
+
+                        if(to->localClient->buf_sendq.list.head)
+                                hd.arg1 =
+                                        ((buf_line_t *) to->localClient->buf_sendq.list.head->
+                                         data)->buf + to->localClient->buf_sendq.writeofs;
+#endif
+     
+
+                       to->localClient->sendB += retlen;
+                       me.localClient->sendB += retlen;
+                       if(to->localClient->sendB > 1023)
+                       {
+                               to->localClient->sendK += (to->localClient->sendB >> 10);
+                               to->localClient->sendB &= 0x03ff;       /* 2^10 = 1024, 3ff = 1023 */
+                       }
+                       else if(me.localClient->sendB > 1023)
+                       {
+                               me.localClient->sendK += (me.localClient->sendB >> 10);
+                               me.localClient->sendB &= 0x03ff;
+                       }
+               }
+
+               if(retlen == 0 || (retlen < 0 && !ignoreErrno(errno)))
+               {
+                       dead_link(to);
+                       return;
+               }
+       }
+       if(ignoreErrno(errno))
+               flags = COMM_SELECT_WRITE|COMM_SELECT_RETRY;
+       else
+               flags = COMM_SELECT_WRITE;
+       if(linebuf_len(&to->localClient->buf_sendq))
+       comm_setselect(fd, FDLIST_IDLECLIENT, flags,
+                              send_queued_write, to, 0);
+}
+
+/* send_queued_slink_write()
+ *
+ * inputs      - fd to have queue sent, client we're sending to
+ * outputs     - contents of queue
+ * side effects - write is rescheduled if queue isnt emptied
+ */
+void
+send_queued_slink_write(int fd, void *data)
+{
+       struct Client *to = data;
+       int retlen;
+
+       /*
+        ** Once socket is marked dead, we cannot start writing to it,
+        ** even if the error is removed...
+        */
+       if(IsIOError(to))
+               return;
+
+       /* Next, lets try to write some data */
+       if(to->localClient->slinkq)
+       {
+               retlen = write(to->localClient->ctrlfd,
+                             to->localClient->slinkq + to->localClient->slinkq_ofs,
+                             to->localClient->slinkq_len);
+
+               if(retlen < 0)
+               {
+                       /* If we have a fatal error */
+                       if(!ignoreErrno(errno))
+                       {
+                               dead_link(to);
+                               return;
+                       }
+               }
+               /* 0 bytes is an EOF .. */
+               else if(retlen == 0)
+               {
+                       dead_link(to);
+                       return;
+               }
+               else
+               {
+                       to->localClient->slinkq_len -= retlen;
+
+                       s_assert(to->localClient->slinkq_len >= 0);
+                       if(to->localClient->slinkq_len)
+                               to->localClient->slinkq_ofs += retlen;
+                       else
+                       {
+                               to->localClient->slinkq_ofs = 0;
+                               MyFree(to->localClient->slinkq);
+                               to->localClient->slinkq = NULL;
+                       }
+               }
+       }
+
+       /* if we have any more data, reschedule a write */
+       if(to->localClient->slinkq_len)
+               comm_setselect(to->localClient->ctrlfd, FDLIST_IDLECLIENT,
+                              COMM_SELECT_WRITE|COMM_SELECT_RETRY, send_queued_slink_write, to, 0);
+}
+
+/* sendto_one()
+ *
+ * inputs      - client to send to, va_args
+ * outputs     - client has message put into its queue
+ * side effects - 
+ */
+void
+sendto_one(struct Client *target_p, const char *pattern, ...)
+{
+       va_list args;
+       buf_head_t linebuf;
+
+       /* send remote if to->from non NULL */
+       if(target_p->from != NULL)
+               target_p = target_p->from;
+
+       if(IsIOError(target_p))
+               return;
+
+       linebuf_newbuf(&linebuf);
+
+       va_start(args, pattern);
+       linebuf_putmsg(&linebuf, pattern, &args, NULL);
+       va_end(args);
+
+       _send_linebuf(target_p, &linebuf);
+
+       linebuf_donebuf(&linebuf);
+
+}
+
+/* sendto_one_prefix()
+ *
+ * inputs      - client to send to, va_args
+ * outputs     - client has message put into its queue
+ * side effects - source(us)/target is chosen based on TS6 capability
+ */
+void
+sendto_one_prefix(struct Client *target_p, struct Client *source_p,
+                 const char *command, const char *pattern, ...)
+{
+       struct Client *dest_p;
+       va_list args;
+       buf_head_t linebuf;
+
+       /* send remote if to->from non NULL */
+       if(target_p->from != NULL)
+               dest_p = target_p->from;
+       else
+               dest_p = target_p;
+
+       if(IsIOError(dest_p))
+               return;
+
+       if(IsMe(dest_p))
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "Trying to send to myself!");
+               return;
+       }
+
+       linebuf_newbuf(&linebuf);
+       va_start(args, pattern);
+       linebuf_putmsg(&linebuf, pattern, &args,
+                      ":%s %s %s ",
+                      get_id(source_p, target_p),
+                      command, get_id(target_p, target_p));
+       va_end(args);
+
+       _send_linebuf(dest_p, &linebuf);
+       linebuf_donebuf(&linebuf);
+}
+
+/* sendto_one_notice()
+ *
+ * inputs      - client to send to, va_args
+ * outputs     - client has a NOTICE put into its queue
+ * side effects - source(us)/target is chosen based on TS6 capability
+ */
+void
+sendto_one_notice(struct Client *target_p, const char *pattern, ...)
+{
+       struct Client *dest_p;
+       va_list args;
+       buf_head_t linebuf;
+
+       /* send remote if to->from non NULL */
+       if(target_p->from != NULL)
+               dest_p = target_p->from;
+       else
+               dest_p = target_p;
+
+       if(IsIOError(dest_p))
+               return;
+
+       if(IsMe(dest_p))
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "Trying to send to myself!");
+               return;
+       }
+
+       linebuf_newbuf(&linebuf);
+       va_start(args, pattern);
+       linebuf_putmsg(&linebuf, pattern, &args,
+                      ":%s NOTICE %s ",
+                      get_id(&me, target_p), get_id(target_p, target_p));
+       va_end(args);
+
+       _send_linebuf(dest_p, &linebuf);
+       linebuf_donebuf(&linebuf);
+}
+
+
+/* sendto_one_numeric()
+ *
+ * inputs      - client to send to, va_args
+ * outputs     - client has message put into its queue
+ * side effects - source/target is chosen based on TS6 capability
+ */
+void
+sendto_one_numeric(struct Client *target_p, int numeric, const char *pattern, ...)
+{
+       struct Client *dest_p;
+       va_list args;
+       buf_head_t linebuf;
+
+       /* send remote if to->from non NULL */
+       if(target_p->from != NULL)
+               dest_p = target_p->from;
+       else
+               dest_p = target_p;
+
+       if(IsIOError(dest_p))
+               return;
+
+       if(IsMe(dest_p))
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_ALL, "Trying to send to myself!");
+               return;
+       }
+
+       linebuf_newbuf(&linebuf);
+       va_start(args, pattern);
+       linebuf_putmsg(&linebuf, pattern, &args,
+                      ":%s %03d %s ",
+                      get_id(&me, target_p),
+                      numeric, get_id(target_p, target_p));
+       va_end(args);
+
+       _send_linebuf(dest_p, &linebuf);
+       linebuf_donebuf(&linebuf);
+}
+
+/*
+ * sendto_server
+ * 
+ * inputs       - pointer to client to NOT send to
+ *              - caps or'd together which must ALL be present
+ *              - caps or'd together which must ALL NOT be present
+ *              - printf style format string
+ *              - args to format string
+ * output       - NONE
+ * side effects - Send a message to all connected servers, except the
+ *                client 'one' (if non-NULL), as long as the servers
+ *                support ALL capabs in 'caps', and NO capabs in 'nocaps'.
+ *            
+ * This function was written in an attempt to merge together the other
+ * billion sendto_*serv*() functions, which sprung up with capabs, uids etc
+ * -davidt
+ */
+void
+sendto_server(struct Client *one, struct Channel *chptr, unsigned long caps,
+             unsigned long nocaps, const char *format, ...)
+{
+       va_list args;
+       struct Client *target_p;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+       buf_head_t linebuf;
+
+       /* noone to send to.. */
+       if(dlink_list_length(&serv_list) == 0)
+               return;
+
+       if(chptr != NULL && *chptr->chname != '#')
+                       return;
+
+       linebuf_newbuf(&linebuf);
+       va_start(args, format);
+       linebuf_putmsg(&linebuf, format, &args, NULL);
+       va_end(args);
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, serv_list.head)
+       {
+               target_p = ptr->data;
+
+               /* check against 'one' */
+               if(one != NULL && (target_p == one->from))
+                       continue;
+
+               /* check we have required capabs */
+               if(!IsCapable(target_p, caps))
+                       continue;
+
+               /* check we don't have any forbidden capabs */
+               if(!NotCapable(target_p, nocaps))
+                       continue;
+
+               _send_linebuf(target_p, &linebuf);
+       }
+
+       linebuf_donebuf(&linebuf);
+
+}
+
+/* sendto_channel_flags()
+ *
+ * inputs      - server not to send to, flags needed, source, channel, va_args
+ * outputs     - message is sent to channel members
+ * side effects -
+ */
+void
+sendto_channel_flags(struct Client *one, int type, struct Client *source_p,
+                    struct Channel *chptr, const char *pattern, ...)
+{
+       static char buf[BUFSIZE];
+       va_list args;
+       buf_head_t linebuf_local;
+       buf_head_t linebuf_name;
+       buf_head_t linebuf_id;
+       struct Client *target_p;
+       struct membership *msptr;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+
+       linebuf_newbuf(&linebuf_local);
+       linebuf_newbuf(&linebuf_name);
+       linebuf_newbuf(&linebuf_id);
+
+       current_serial++;
+
+       va_start(args, pattern);
+       ircvsnprintf(buf, sizeof(buf), pattern, args);
+       va_end(args);
+
+       if(IsServer(source_p))
+               linebuf_putmsg(&linebuf_local, NULL, NULL,
+                              ":%s %s", source_p->name, buf);
+       else
+               linebuf_putmsg(&linebuf_local, NULL, NULL,
+                              ":%s!%s@%s %s",
+                              source_p->name, source_p->username, 
+                              source_p->host, buf);
+
+       linebuf_putmsg(&linebuf_name, NULL, NULL, ":%s %s", source_p->name, buf);
+       linebuf_putmsg(&linebuf_id, NULL, NULL, ":%s %s", use_id(source_p), buf);
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->members.head)
+       {
+               msptr = ptr->data;
+               target_p = msptr->client_p;
+
+               if(IsIOError(target_p->from) || target_p->from == one)
+                       continue;
+
+               if(type && ((msptr->flags & type) == 0))
+                       continue;
+
+               if(IsDeaf(target_p))
+                       continue;
+
+               if(!MyClient(target_p))
+               {
+                       /* if we've got a specific type, target must support
+                        * CHW.. --fl
+                        */
+                       if(type && NotCapable(target_p->from, CAP_CHW))
+                               continue;
+
+                       if(target_p->from->serial != current_serial)
+                       {
+                               if(has_id(target_p->from))
+                                       send_linebuf_remote(target_p, source_p, &linebuf_id);
+                               else
+                                       send_linebuf_remote(target_p, source_p, &linebuf_name);
+
+                               target_p->from->serial = current_serial;
+                       }
+               }
+               else
+                       _send_linebuf(target_p, &linebuf_local);
+       }
+
+       linebuf_donebuf(&linebuf_local);
+       linebuf_donebuf(&linebuf_name);
+       linebuf_donebuf(&linebuf_id);
+}
+
+
+/* sendto_channel_local()
+ *
+ * inputs      - flags to send to, channel to send to, va_args
+ * outputs     - message to local channel members
+ * side effects -
+ */
+void
+sendto_channel_local(int type, struct Channel *chptr, const char *pattern, ...)
+{
+       va_list args;
+       buf_head_t linebuf;
+       struct membership *msptr;
+       struct Client *target_p;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+       
+       linebuf_newbuf(&linebuf); 
+       
+       va_start(args, pattern);
+       linebuf_putmsg(&linebuf, pattern, &args, NULL);
+       va_end(args);
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->locmembers.head)
+       {
+               msptr = ptr->data;
+               target_p = msptr->client_p;
+
+               if(IsIOError(target_p))
+                       continue;
+
+               if(type && ((msptr->flags & type) == 0))
+                       continue;
+
+               _send_linebuf(target_p, &linebuf);
+       }
+
+       linebuf_donebuf(&linebuf);
+}
+
+/* sendto_channel_local_butone()
+ *
+ * inputs      - flags to send to, channel to send to, va_args
+ *             - user to ignore when sending
+ * outputs     - message to local channel members
+ * side effects -
+ */
+void
+sendto_channel_local_butone(struct Client *one, int type, struct Channel *chptr, const char *pattern, ...)
+{
+       va_list args;
+       buf_head_t linebuf;
+       struct membership *msptr;
+       struct Client *target_p;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+       
+       linebuf_newbuf(&linebuf); 
+       
+       va_start(args, pattern);
+       linebuf_putmsg(&linebuf, pattern, &args, NULL);
+       va_end(args);
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->locmembers.head)
+       {
+               msptr = ptr->data;
+               target_p = msptr->client_p;
+
+               if(target_p == one)
+                       continue;
+
+               if(IsIOError(target_p))
+                       continue;
+
+               if(type && ((msptr->flags & type) == 0))
+                       continue;
+
+               _send_linebuf(target_p, &linebuf);
+       }
+
+       linebuf_donebuf(&linebuf);
+}
+
+/*
+ * sendto_common_channels_local()
+ *
+ * inputs      - pointer to client
+ *             - pattern to send
+ * output      - NONE
+ * side effects        - Sends a message to all people on local server who are
+ *               in same channel with user. 
+ *               used by m_nick.c and exit_one_client.
+ */
+void
+sendto_common_channels_local(struct Client *user, const char *pattern, ...)
+{
+       va_list args;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+       dlink_node *uptr;
+       dlink_node *next_uptr;
+       struct Channel *chptr;
+       struct Client *target_p;
+       struct membership *msptr;
+       struct membership *mscptr;
+       buf_head_t linebuf;
+
+       linebuf_newbuf(&linebuf);
+       va_start(args, pattern);
+       linebuf_putmsg(&linebuf, pattern, &args, NULL);
+       va_end(args);
+
+       ++current_serial;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, user->user->channel.head)
+       {
+               mscptr = ptr->data;
+               chptr = mscptr->chptr;
+
+               DLINK_FOREACH_SAFE(uptr, next_uptr, chptr->locmembers.head)
+               {
+                       msptr = uptr->data;
+                       target_p = msptr->client_p;
+
+                       if(IsIOError(target_p) ||
+                          target_p->serial == current_serial)
+                               continue;
+
+                       target_p->serial = current_serial;
+                       send_linebuf(target_p, &linebuf);
+               }
+       }
+
+       /* this can happen when the user isnt in any channels, but we still
+        * need to send them the data, ie a nick change
+        */
+       if(MyConnect(user) && (user->serial != current_serial))
+               send_linebuf(user, &linebuf);
+
+       linebuf_donebuf(&linebuf);
+}
+
+/*
+ * sendto_common_channels_local_butone()
+ *
+ * inputs      - pointer to client
+ *             - pattern to send
+ * output      - NONE
+ * side effects        - Sends a message to all people on local server who are
+ *               in same channel with user, except for user itself.
+ */
+void
+sendto_common_channels_local_butone(struct Client *user, const char *pattern, ...)
+{
+       va_list args;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+       dlink_node *uptr;
+       dlink_node *next_uptr;
+       struct Channel *chptr;
+       struct Client *target_p;
+       struct membership *msptr;
+       struct membership *mscptr;
+       buf_head_t linebuf;
+
+       linebuf_newbuf(&linebuf);
+       va_start(args, pattern);
+       linebuf_putmsg(&linebuf, pattern, &args, NULL);
+       va_end(args);
+
+       ++current_serial;
+       /* Skip them -- jilles */
+       user->serial = current_serial;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, user->user->channel.head)
+       {
+               mscptr = ptr->data;
+               chptr = mscptr->chptr;
+
+               DLINK_FOREACH_SAFE(uptr, next_uptr, chptr->locmembers.head)
+               {
+                       msptr = uptr->data;
+                       target_p = msptr->client_p;
+
+                       if(IsIOError(target_p) ||
+                          target_p->serial == current_serial)
+                               continue;
+
+                       target_p->serial = current_serial;
+                       send_linebuf(target_p, &linebuf);
+               }
+       }
+
+       linebuf_donebuf(&linebuf);
+}
+
+/* sendto_match_butone()
+ *
+ * inputs      - server not to send to, source, mask, type of mask, va_args
+ * output      -
+ * side effects - message is sent to matching clients
+ */
+void
+sendto_match_butone(struct Client *one, struct Client *source_p,
+                   const char *mask, int what, const char *pattern, ...)
+{
+       static char buf[BUFSIZE];
+       va_list args;
+       struct Client *target_p;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+       buf_head_t linebuf_local;
+       buf_head_t linebuf_name;
+       buf_head_t linebuf_id;
+
+       linebuf_newbuf(&linebuf_local);
+       linebuf_newbuf(&linebuf_name);
+       linebuf_newbuf(&linebuf_id);
+
+       va_start(args, pattern);
+       ircvsnprintf(buf, sizeof(buf), pattern, args);
+       va_end(args);
+
+       if(IsServer(source_p))
+               linebuf_putmsg(&linebuf_local, NULL, NULL,
+                              ":%s %s", source_p->name, buf);
+       else
+               linebuf_putmsg(&linebuf_local, NULL, NULL,
+                              ":%s!%s@%s %s",
+                              source_p->name, source_p->username, 
+                              source_p->host, buf);
+
+       linebuf_putmsg(&linebuf_name, NULL, NULL, ":%s %s", source_p->name, buf);
+       linebuf_putmsg(&linebuf_id, NULL, NULL, ":%s %s", use_id(source_p), buf);
+
+       if(what == MATCH_HOST)
+       {
+               DLINK_FOREACH_SAFE(ptr, next_ptr, lclient_list.head)
+               {
+                       target_p = ptr->data;
+
+                       if(match(mask, target_p->host))
+                               _send_linebuf(target_p, &linebuf_local);
+               }
+       }
+       /* what = MATCH_SERVER, if it doesnt match us, just send remote */
+       else if(match(mask, me.name))
+       {
+               DLINK_FOREACH_SAFE(ptr, next_ptr, lclient_list.head)
+               {
+                       target_p = ptr->data;
+                       _send_linebuf(target_p, &linebuf_local);
+               }
+       }
+
+       DLINK_FOREACH(ptr, serv_list.head)
+       {
+               target_p = ptr->data;
+
+               if(target_p == one)
+                       continue;
+
+               if(has_id(target_p))
+                       send_linebuf_remote(target_p, source_p, &linebuf_id);
+               else
+                       send_linebuf_remote(target_p, source_p, &linebuf_name);
+       }
+
+       linebuf_donebuf(&linebuf_local);
+       linebuf_donebuf(&linebuf_id);
+       linebuf_donebuf(&linebuf_name);
+}
+
+/* sendto_match_servs()
+ *
+ * inputs       - source, mask to send to, caps needed, va_args
+ * outputs      - 
+ * side effects - message is sent to matching servers with caps.
+ */
+void
+sendto_match_servs(struct Client *source_p, const char *mask, int cap, 
+                       int nocap, const char *pattern, ...)
+{
+       static char buf[BUFSIZE];
+       va_list args;
+       dlink_node *ptr;
+       struct Client *target_p;
+       buf_head_t linebuf_id;
+       buf_head_t linebuf_name;
+
+       if(EmptyString(mask))
+               return;
+
+       linebuf_newbuf(&linebuf_id);
+       linebuf_newbuf(&linebuf_name);
+
+       va_start(args, pattern);
+       ircvsnprintf(buf, sizeof(buf), pattern, args);
+       va_end(args);
+
+       linebuf_putmsg(&linebuf_id, NULL, NULL, 
+                       ":%s %s", use_id(source_p), buf);
+       linebuf_putmsg(&linebuf_name, NULL, NULL, 
+                       ":%s %s", source_p->name, buf);
+
+       current_serial++;
+
+       DLINK_FOREACH(ptr, global_serv_list.head)
+       {
+               target_p = ptr->data;
+
+               /* dont send to ourselves, or back to where it came from.. */
+               if(IsMe(target_p) || target_p->from == source_p->from)
+                       continue;
+
+               if(target_p->from->serial == current_serial)
+                       continue;
+
+               if(match(mask, target_p->name))
+               {
+                       /* if we set the serial here, then we'll never do
+                        * a match() again if !IsCapable()
+                        */
+                       target_p->from->serial = current_serial;
+
+                       if(cap && !IsCapable(target_p->from, cap))
+                               continue;
+
+                       if(nocap && !NotCapable(target_p->from, nocap))
+                               continue;
+
+                       if(has_id(target_p->from))
+                               _send_linebuf(target_p->from, &linebuf_id);
+                       else
+                               _send_linebuf(target_p->from, &linebuf_name);
+               }
+       }
+
+       linebuf_donebuf(&linebuf_id);
+       linebuf_donebuf(&linebuf_name);
+}
+
+/* sendto_anywhere()
+ *
+ * inputs      - target, source, va_args
+ * outputs     -
+ * side effects - client is sent message with correct prefix.
+ */
+void
+sendto_anywhere(struct Client *target_p, struct Client *source_p, 
+               const char *command, const char *pattern, ...)
+{
+       va_list args;
+       buf_head_t linebuf;
+
+       linebuf_newbuf(&linebuf);
+
+       va_start(args, pattern);
+
+       if(MyClient(target_p))
+       {
+               if(IsServer(source_p))
+                       linebuf_putmsg(&linebuf, pattern, &args, ":%s %s %s ",
+                                      source_p->name, command, 
+                                      target_p->name);
+               else
+                       linebuf_putmsg(&linebuf, pattern, &args, 
+                                      ":%s!%s@%s %s %s ", 
+                                      source_p->name, source_p->username,
+                                      source_p->host, command,
+                                      target_p->name);
+       }
+       else
+               linebuf_putmsg(&linebuf, pattern, &args, ":%s %s %s ",
+                              get_id(source_p, target_p), command,
+                              get_id(target_p, target_p));
+       va_end(args);
+
+       if(MyClient(target_p))
+               _send_linebuf(target_p, &linebuf);
+       else
+               send_linebuf_remote(target_p, source_p, &linebuf);
+
+       linebuf_donebuf(&linebuf);
+}
+
+/* sendto_realops_flags()
+ *
+ * inputs      - umode needed, level (opers/admin), va_args
+ * output      -
+ * side effects - message is sent to opers with matching umodes
+ */
+void
+sendto_realops_flags(int flags, int level, const char *pattern, ...)
+{
+       struct Client *client_p;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+       va_list args;
+       buf_head_t linebuf;
+
+       linebuf_newbuf(&linebuf);
+
+       va_start(args, pattern);
+       linebuf_putmsg(&linebuf, pattern, &args, 
+                      ":%s NOTICE * :*** Notice -- ", me.name);
+       va_end(args);
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, local_oper_list.head)
+       {
+               client_p = ptr->data;
+
+               /* If we're sending it to opers and theyre an admin, skip.
+                * If we're sending it to admins, and theyre not, skip.
+                */
+               if(((level == L_ADMIN) && !IsOperAdmin(client_p)) ||
+                  ((level == L_OPER) && IsOperAdmin(client_p)))
+                       continue;
+
+               if(client_p->umodes & flags)
+                       _send_linebuf(client_p, &linebuf);
+       }
+
+       linebuf_donebuf(&linebuf);
+}
+
+/* sendto_realops_snomask()
+ *
+ * inputs      - snomask needed, level (opers/admin), va_args
+ * output      -
+ * side effects - message is sent to opers with matching snomasks
+ */
+void
+sendto_realops_snomask(int flags, int level, const char *pattern, ...)
+{
+       static char buf[BUFSIZE];
+       char *snobuf;
+       struct Client *client_p;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+       va_list args;
+       buf_head_t linebuf;
+
+       linebuf_newbuf(&linebuf);
+
+       /* Be very sure not to do things like "Trying to send to myself"
+        * L_NETWIDE, otherwise infinite recursion may result! -- jilles */
+       if (level & L_NETWIDE && ConfigFileEntry.global_snotices)
+       {
+               /* rather a lot of copying around, oh well -- jilles */
+               va_start(args, pattern);
+               ircvsnprintf(buf, sizeof(buf), pattern, args);
+               va_end(args);
+               linebuf_putmsg(&linebuf, pattern, NULL, 
+                               ":%s NOTICE * :*** Notice -- %s", me.name, buf);
+               snobuf = construct_snobuf(flags);
+               if (snobuf[1] != '\0')
+               {
+                       sendto_server(NULL, NULL, CAP_ENCAP|CAP_TS6, NOCAPS,
+                                       ":%s ENCAP * SNOTE %c :%s",
+                                       me.id, snobuf[1], buf);
+                       sendto_server(NULL, NULL, CAP_ENCAP, CAP_TS6,
+                                       ":%s ENCAP * SNOTE %c :%s",
+                                       me.name, snobuf[1], buf);
+               }
+       }
+       else
+       {
+               va_start(args, pattern);
+               linebuf_putmsg(&linebuf, pattern, &args, 
+                               ":%s NOTICE * :*** Notice -- ", me.name);
+               va_end(args);
+       }
+       level &= ~L_NETWIDE;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, local_oper_list.head)
+       {
+               client_p = ptr->data;
+
+               /* If we're sending it to opers and theyre an admin, skip.
+                * If we're sending it to admins, and theyre not, skip.
+                */
+               if(((level == L_ADMIN) && !IsOperAdmin(client_p)) ||
+                  ((level == L_OPER) && IsOperAdmin(client_p)))
+                       continue;
+
+               if(client_p->snomask & flags)
+                       _send_linebuf(client_p, &linebuf);
+       }
+
+       linebuf_donebuf(&linebuf);
+}
+/* sendto_realops_snomask_from()
+ *
+ * inputs      - snomask needed, level (opers/admin), source server, va_args
+ * output      -
+ * side effects - message is sent to opers with matching snomask
+ */
+void
+sendto_realops_snomask_from(int flags, int level, struct Client *source_p,
+               const char *pattern, ...)
+{
+       struct Client *client_p;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+       va_list args;
+       buf_head_t linebuf;
+
+       linebuf_newbuf(&linebuf);
+
+       va_start(args, pattern);
+       linebuf_putmsg(&linebuf, pattern, &args, 
+                      ":%s NOTICE * :*** Notice -- ", source_p->name);
+       va_end(args);
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, local_oper_list.head)
+       {
+               client_p = ptr->data;
+
+               /* If we're sending it to opers and theyre an admin, skip.
+                * If we're sending it to admins, and theyre not, skip.
+                */
+               if(((level == L_ADMIN) && !IsOperAdmin(client_p)) ||
+                  ((level == L_OPER) && IsOperAdmin(client_p)))
+                       continue;
+
+               if(client_p->snomask & flags)
+                       _send_linebuf(client_p, &linebuf);
+       }
+
+       linebuf_donebuf(&linebuf);
+}
+
+/*
+ * sendto_wallops_flags
+ *
+ * inputs       - flag types of messages to show to real opers
+ *              - client sending request
+ *              - var args input message
+ * output       - NONE
+ * side effects - Send a wallops to local opers
+ */
+void
+sendto_wallops_flags(int flags, struct Client *source_p, const char *pattern, ...)
+{
+       struct Client *client_p;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+       va_list args;
+       buf_head_t linebuf;
+
+       linebuf_newbuf(&linebuf);
+
+       va_start(args, pattern);
+
+       if(IsPerson(source_p))
+               linebuf_putmsg(&linebuf, pattern, &args,
+                              ":%s!%s@%s WALLOPS :", source_p->name,
+                              source_p->username, source_p->host);
+       else
+               linebuf_putmsg(&linebuf, pattern, &args, ":%s WALLOPS :", source_p->name);
+
+       va_end(args);
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, IsPerson(source_p) && flags == UMODE_WALLOP ? lclient_list.head : local_oper_list.head)
+       {
+               client_p = ptr->data;
+
+               if(client_p->umodes & flags)
+                       _send_linebuf(client_p, &linebuf);
+       }
+
+       linebuf_donebuf(&linebuf);
+}
+
+/* kill_client()
+ *
+ * input       - client to send kill to, client to kill, va_args
+ * output      -
+ * side effects - we issue a kill for the client
+ */
+void
+kill_client(struct Client *target_p, struct Client *diedie, const char *pattern, ...)
+{
+       va_list args;
+       buf_head_t linebuf;
+
+       linebuf_newbuf(&linebuf);
+
+       va_start(args, pattern);
+       linebuf_putmsg(&linebuf, pattern, &args, ":%s KILL %s :",
+                     get_id(&me, target_p), get_id(diedie, target_p));
+       va_end(args);
+
+       send_linebuf(target_p, &linebuf);
+       linebuf_donebuf(&linebuf);
+}
+
+
+/*
+ * kill_client_serv_butone
+ *
+ * inputs      - pointer to client to not send to
+ *             - pointer to client to kill
+ * output      - NONE
+ * side effects        - Send a KILL for the given client
+ *               message to all connected servers
+ *                except the client 'one'. Also deal with
+ *               client being unknown to leaf, as in lazylink...
+ */
+void
+kill_client_serv_butone(struct Client *one, struct Client *target_p, const char *pattern, ...)
+{
+       static char buf[BUFSIZE];
+       va_list args;
+       struct Client *client_p;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+       buf_head_t linebuf_id;
+       buf_head_t linebuf_name;
+
+       linebuf_newbuf(&linebuf_name);
+       linebuf_newbuf(&linebuf_id);
+       
+       va_start(args, pattern);
+       ircvsnprintf(buf, sizeof(buf), pattern, args);
+       va_end(args);
+
+       linebuf_putmsg(&linebuf_name, NULL, NULL, ":%s KILL %s :%s",
+                      me.name, target_p->name, buf);
+       linebuf_putmsg(&linebuf_id, NULL, NULL, ":%s KILL %s :%s",
+                      use_id(&me), use_id(target_p), buf);
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, serv_list.head)
+       {
+               client_p = ptr->data;
+
+               /* ok, if the client we're supposed to not send to has an
+                * ID, then we still want to issue the kill there..
+                */
+               if(one != NULL && (client_p == one->from) &&
+                       (!has_id(client_p) || !has_id(target_p)))
+                       continue;
+
+               if(has_id(client_p))
+                       _send_linebuf(client_p, &linebuf_id);
+               else
+                       _send_linebuf(client_p, &linebuf_name);
+       }
+
+       linebuf_donebuf(&linebuf_id);
+       linebuf_donebuf(&linebuf_name);
+}
diff --git a/src/snomask.c b/src/snomask.c
new file mode 100644 (file)
index 0000000..a96f48c
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * charybdis: An advanced ircd.
+ * snomask.c: Management for user server-notice masks.
+ *
+ * Copyright (c) 2006 William Pitcock <nenolod@nenolod.net>
+ *
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id$
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "snomask.h"
+
+/* *INDENT-OFF* */
+int snomask_modes[256] = {
+        /* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0F */
+        /* 0x10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x1F */
+        /* 0x20 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x2F */
+        /* 0x30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x3F */
+        0,                      /* @ */
+        0,                      /* A */
+        0,                      /* B */
+        SNO_CCONNEXT,           /* C */
+        0,                     /* D */
+        0,                      /* E */
+        0,                      /* F */
+        0,                      /* G */
+        0,                      /* H */
+        0,                      /* I */
+        0,                      /* J */
+        0,                      /* K */
+        0,                      /* L */
+        0,                      /* M */
+        0,                      /* N */
+        0,                      /* O */
+        0,                      /* P */
+        0,                     /* Q */
+        0,                      /* R */
+        0,                     /* S */
+        0,                      /* T */
+        0,                      /* U */
+        0,                      /* V */
+        0,                      /* W */
+        0,                      /* X */
+        0,                      /* Y */
+        SNO_OPERSPY,           /* Z */
+        /* 0x5B */ 0, 0, 0, 0, 0, 0, /* 0x60 */
+        0,                     /* a */
+        SNO_BOTS,              /* b */
+        SNO_CCONN,              /* c */
+        SNO_DEBUG,              /* d */
+        0,                      /* e */
+        SNO_FULL,               /* f */
+        0,                      /* g */
+        0,                      /* h */
+        0,                      /* i */
+        0,                      /* j */
+        SNO_SKILL,              /* k */
+        0,                      /* l */
+        0,                      /* m */
+        SNO_NCHANGE,            /* n */
+        0,                      /* o */
+        0,                      /* p */
+        0,                      /* q */
+        SNO_REJ,                /* r */
+        SNO_GENERAL,            /* s */
+        0,                      /* t */
+        SNO_UNAUTH,             /* u */
+        0,                      /* v */
+        0,                      /* w */
+        SNO_EXTERNAL,           /* x */
+        SNO_SPY,                /* y */
+        0,                      /* z */
+        /* 0x7B */ 0, 0, 0, 0, 0, /* 0x7F */
+        /* 0x80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x9F */
+        /* 0x90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x9F */
+        /* 0xA0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xAF */
+        /* 0xB0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xBF */
+        /* 0xC0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xCF */
+        /* 0xD0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xDF */
+        /* 0xE0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xEF */
+        /* 0xF0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  /* 0xFF */
+};
+/* *INDENT-ON* */
+
+static char snobuf[BUFSIZE];
+
+/*
+ * construct_snobuf
+ *
+ * inputs       - client to generate snomask string for
+ * outputs      - snomask string of client
+ * side effects - NONE
+ */
+char *
+construct_snobuf(unsigned int val)
+{
+        int i;
+        char *ptr = snobuf;
+
+        *ptr = '\0';
+       *ptr++ = '+';
+
+        for (i = 0; i < 128; i++)
+                if (snomask_modes[i] && (val & snomask_modes[i]))
+                        *ptr++ = (char) i;
+
+        *ptr++ = '\0';
+
+       return snobuf;
+}
+
+/*
+ * parse_snobuf_to_mask
+ *
+ * inputs       - value to alter bitmask for, snomask itself
+ * outputs      - replacement bitmask to set
+ * side effects - NONE
+ */
+unsigned int
+parse_snobuf_to_mask(unsigned int val, const char *sno)
+{
+       const char *p;
+       int what = SNO_ADD;
+
+       if (sno == NULL)
+               return val;
+
+       for (p = sno; *p != '\0'; p++)
+       {
+               switch(*p)
+               {
+                       case '+':
+                               what = SNO_ADD;
+                               break;
+                       case '-':
+                               what = SNO_DEL;
+                               break;
+                       default:
+                               if (what == SNO_ADD)
+                                       val |= snomask_modes[(unsigned char) *p];
+                               else if (what == SNO_DEL)
+                                       val &= ~snomask_modes[(unsigned char) *p];
+
+                               break;
+               }
+       }
+
+       return val;
+}
+
+/*
+ * find_snomask_slot
+ *
+ * inputs       - NONE
+ * outputs      - an available umode bitmask or
+ *                0 if no umodes are available
+ * side effects - NONE
+ */
+unsigned int
+find_snomask_slot(void)
+{
+       unsigned int all_umodes = 0, my_umode = 0, i;
+
+       for (i = 0; i < 128; i++)
+               all_umodes |= snomask_modes[i];
+
+       for (my_umode = 1; my_umode && (all_umodes & my_umode);
+               my_umode <<= 1);
+
+       return my_umode;
+}
+
diff --git a/src/supported.c b/src/supported.c
new file mode 100644 (file)
index 0000000..64cdbfa
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ *  charybdis: A slightly useful ircd.
+ *  supported.c: isupport (005) numeric
+ *
+ * Copyright (C) 2006 Jilles Tjoelker
+ *
+ * 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.The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ *  $Id: supported.c 3131 2007-01-21 15:36:31Z jilles $
+ */
+
+/* From the old supported.h which is
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2004 ircd-ratbox development team
+ */
+/*
+ * - from mirc's versions.txt
+ *
+ *  mIRC now supports the numeric 005 tokens: CHANTYPES=# and
+ *  PREFIX=(ohv)@%+ and can handle a dynamic set of channel and
+ *  nick prefixes.
+ *
+ *  mIRC assumes that @ is supported on all networks, any mode
+ *  left of @ is assumed to have at least equal power to @, and
+ *  any mode right of @ has less power.
+ *
+ *  mIRC has internal support for @%+ modes.
+ *
+ *  $nick() can now handle all mode letters listed in PREFIX.
+ *
+ *  Also added support for CHANMODES=A,B,C,D token (not currently
+ *  supported by any servers), which lists all modes supported
+ *  by a channel, where:
+ *
+ *    A = modes that take a parameter, and add or remove nicks
+ *        or addresses to a list, such as +bIe for the ban,
+ *        invite, and exception lists.
+ *
+ *    B = modes that change channel settings, but which take
+ *        a parameter when they are set and unset, such as
+ *        +k key, and -k key.
+ *
+ *    C = modes that change channel settings, but which take
+ *        a parameter only when they are set, such as +l N,
+ *        and -l.
+ *
+ *    D = modes that change channel settings, such as +imnpst
+ *        and take no parameters.
+ *
+ *  All unknown/unlisted modes are treated as type D.
+ */
+/* ELIST=[tokens]:
+ *
+ * M = mask search
+ * N = !mask search
+ * U = user count search (< >)
+ * C = creation time search (C> C<)
+ * T = topic search (T> T<)
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "client.h"
+#include "common.h"
+#include "numeric.h"
+#include "ircd.h"
+#include "s_conf.h"
+
+dlink_list isupportlist;
+
+struct isupportitem
+{
+       const char *name;
+       const char *(*func)(void *);
+       void *param;
+       dlink_node node;
+};
+
+void
+add_isupport(const char *name, const char *(*func)(void *), void *param)
+{
+       struct isupportitem *item;
+
+       item = MyMalloc(sizeof(struct isupportitem));
+       item->name = name;
+       item->func = func;
+       item->param = param;
+       dlinkAddTail(item, &item->node, &isupportlist);
+}
+
+void
+delete_isupport(const char *name)
+{
+       dlink_node *ptr, *next_ptr;
+       struct isupportitem *item;
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, isupportlist.head)
+       {
+               item = ptr->data;
+
+               if (!strcmp(item->name, name))
+               {
+                       dlinkDelete(ptr, &isupportlist);
+                       MyFree(item);
+               }
+       }
+}
+
+/* XXX caching? */
+void
+show_isupport(struct Client *client_p)
+{
+       dlink_node *ptr;
+       struct isupportitem *item;
+       const char *value;
+       char buf[512];
+       int extra_space;
+       int nchars, nparams;
+       int l;
+
+       extra_space = strlen(client_p->name);
+       /* UID */
+       if (!MyClient(client_p) && extra_space < 9)
+               extra_space = 9;
+       /* :<me.name> 005 <nick> <params> :are supported by this server */
+       /* form_str(RPL_ISUPPORT) is %s :are supported by this server */
+       extra_space += strlen(me.name) + 1 + strlen(form_str(RPL_ISUPPORT));
+
+       nchars = extra_space, nparams = 0, buf[0] = '\0';
+       DLINK_FOREACH(ptr, isupportlist.head)
+       {
+               item = ptr->data;
+               value = (*item->func)(item->param);
+               if (value == NULL)
+                       continue;
+               l = strlen(item->name) + (EmptyString(value) ? 0 : 1 + strlen(value));
+               if (nchars + l + (nparams > 0) >= sizeof buf || nparams + 1 > 12)
+               {
+                       sendto_one_numeric(client_p, RPL_ISUPPORT, form_str(RPL_ISUPPORT), buf);
+                       nchars = extra_space, nparams = 0, buf[0] = '\0';
+               }
+               if (nparams > 0)
+                       strlcat(buf, " ", sizeof buf), nchars++;
+               strlcat(buf, item->name, sizeof buf);
+               if (!EmptyString(value))
+               {
+                       strlcat(buf, "=", sizeof buf);
+                       strlcat(buf, value, sizeof buf);
+               }
+               nchars += l;
+               nparams++;
+       }
+       if (nparams > 0)
+               sendto_one_numeric(client_p, RPL_ISUPPORT, form_str(RPL_ISUPPORT), buf);
+}
+
+const char *
+isupport_intptr(void *ptr)
+{
+       static char buf[15];
+
+       ircsnprintf(buf, sizeof buf, "%d", *(int *)ptr);
+       return buf;
+}
+
+const char *
+isupport_boolean(void *ptr)
+{
+
+       return *(int *)ptr ? "" : NULL;
+}
+
+const char *
+isupport_string(void *ptr)
+{
+
+       return (const char *)ptr;
+}
+
+const char *
+isupport_stringptr(void *ptr)
+{
+
+       return *(const char **)ptr;
+}
+
+const char *
+isupport_chanmodes(void *ptr)
+{
+       static char result[80];
+
+       ircsnprintf(result, sizeof result, "%s%sbq,k,%slj,imnpstrcgzLP%s",
+                       ConfigChannel.use_except ? "e" : "",
+                       ConfigChannel.use_invex ? "I" : "",
+                       ConfigChannel.use_forward ? "f" : "",
+                       ConfigChannel.use_forward ? "QF" : "");
+       return result;
+}
+
+const char *
+isupport_chanlimit(void *ptr)
+{
+       static char result[30];
+
+       ircsnprintf(result, sizeof result, "&#:%i", ConfigChannel.max_chans_per_user);
+       return result;
+}
+
+const char *
+isupport_maxlist(void *ptr)
+{
+       static char result[30];
+
+       ircsnprintf(result, sizeof result, "bq%s%s:%i",
+                       ConfigChannel.use_except ? "e" : "",
+                       ConfigChannel.use_invex ? "I" : "",
+                       ConfigChannel.max_bans);
+       return result;
+}
+
+const char *
+isupport_targmax(void *ptr)
+{
+       static char result[200];
+
+       ircsnprintf(result, sizeof result, "NAMES:1,LIST:1,KICK:1,WHOIS:1,PRIVMSG:%d,NOTICE:%d,ACCEPT:,MONITOR:",
+                       ConfigFileEntry.max_targets,
+                       ConfigFileEntry.max_targets);
+       return result;
+}
+
+const char *
+isupport_extban(void *ptr)
+{
+       const char *p;
+       static char result[200];
+
+       p = get_extban_string();
+       if (EmptyString(p))
+               return NULL;
+       ircsnprintf(result, sizeof result, "$:%s", p);
+       return result;
+}
+
+void
+init_isupport(void)
+{
+       static int maxmodes = MAXMODEPARAMS;
+       static int nicklen = NICKLEN-1;
+       static int channellen = LOC_CHANNELLEN;
+       static int topiclen = TOPICLEN;
+
+       add_isupport("CHANTYPES", isupport_string, "&#");
+       add_isupport("EXCEPTS", isupport_boolean, &ConfigChannel.use_except);
+       add_isupport("INVEX", isupport_boolean, &ConfigChannel.use_invex);
+       add_isupport("CHANMODES", isupport_chanmodes, NULL);
+       add_isupport("CHANLIMIT", isupport_chanlimit, NULL);
+       add_isupport("PREFIX", isupport_string, "(ov)@+");
+       add_isupport("MAXLIST", isupport_maxlist, NULL);
+       add_isupport("MODES", isupport_intptr, &maxmodes);
+       add_isupport("NETWORK", isupport_stringptr, &ServerInfo.network_name);
+       add_isupport("KNOCK", isupport_boolean, &ConfigChannel.use_knock);
+       add_isupport("STATUSMSG", isupport_string, "@+");
+       add_isupport("CALLERID", isupport_string, "g");
+       add_isupport("SAFELIST", isupport_string, "");
+       add_isupport("ELIST", isupport_string, "U");
+       add_isupport("CASEMAPPING", isupport_string, "rfc1459");
+       add_isupport("CHARSET", isupport_string, "ascii");
+       add_isupport("NICKLEN", isupport_intptr, &nicklen);
+       add_isupport("CHANNELLEN", isupport_intptr, &channellen);
+       add_isupport("TOPICLEN", isupport_intptr, &topiclen);
+       add_isupport("ETRACE", isupport_string, "");
+       add_isupport("CPRIVMSG", isupport_string, "");
+       add_isupport("CNOTICE", isupport_string, "");
+       add_isupport("DEAF", isupport_string, "D");
+       add_isupport("MONITOR", isupport_intptr, &ConfigFileEntry.max_monitor);
+       add_isupport("FNC", isupport_string, "");
+       add_isupport("TARGMAX", isupport_targmax, NULL);
+       add_isupport("EXTBAN", isupport_extban, NULL);
+}
diff --git a/src/version.c.SH b/src/version.c.SH
new file mode 100644 (file)
index 0000000..17163e1
--- /dev/null
@@ -0,0 +1,86 @@
+#!/bin/sh
+
+# $Id: version.c.SH 1028 2006-03-10 15:28:58Z jilles $ 
+
+spitshell=cat
+package=IRC
+
+echo "Extracting $package/src/version.c..."
+
+if test -r version.c.last
+then
+   generation=`sed -n 's/^char \*generation = \"\(.*\)\";/\1/p' < version.c.last`
+   if test ! "$generation" ; then generation=0; fi
+else
+   generation=0
+fi
+
+generation=`expr $generation + 1`
+
+uname=`uname -a`
+
+creation=`date | \
+awk '{if (NF == 6) \
+         { print $1 " "  $2 " " $3 " "  $6 " at " $4 " " $5 } \
+else \
+         { print $1 " "  $2 " " $3 " " $7 " at " $4 " " $5 " " $6 }}'`
+
+$spitshell >version.c <<!SUB!THIS!
+/*
+ *   IRC - Internet Relay Chat, src/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 "patchlevel.h"
+#include "serno.h"
+
+const char *generation = "$generation";
+const char *creation = "$creation";
+const char *platform = "$uname";
+const char *ircd_version = PATCHLEVEL;
+const char *serno = SERNO;
+
+const char *infotext[] =
+{
+  "$package --",
+  "Based on the original code written by Jarkko Oikarinen",
+  "Copyright 1988, 1989, 1990, 1991 University of Oulu, Computing Center",
+  "Copyright (c) 1996-2001 Hybrid Development Team", 
+  "Copyright (c) 2002-2005 ircd-ratbox Development Team",
+  "Copyright (c) 2005-2006 charybdis development 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 1, or",
+  "(at your option) any later version.",
+  "",
+!SUB!THIS!
+
+IFS='
+'
+for i in `grep -v '^$Id' ../CREDITS |tr -d '"'` ; do
+echo "  \"$i\"," >> version.c
+done
+$spitshell >>version.c <<!SUB!THISTOO!
+  "",
+  0,
+};
+!SUB!THISTOO!
diff --git a/src/whowas.c b/src/whowas.c
new file mode 100644 (file)
index 0000000..01279f7
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ *  ircd-ratbox: A slightly useful ircd.
+ *  whowas.c: WHOWAS user cache.
+ *
+ *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
+ *  Copyright (C) 1996-2002 Hybrid Development Team
+ *  Copyright (C) 2002-2005 ircd-ratbox development 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: whowas.c 1717 2006-07-04 14:41:11Z jilles $
+ */
+
+#include "stdinc.h"
+
+#include "whowas.h"
+#include "client.h"
+#include "common.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "ircd_defs.h"
+#include "numeric.h"
+#include "s_serv.h"
+#include "s_user.h"
+#include "send.h"
+#include "s_conf.h"
+#include "memory.h"
+
+/* internally defined function */
+static void add_whowas_to_clist(struct Whowas **, struct Whowas *);
+static void del_whowas_from_clist(struct Whowas **, struct Whowas *);
+static void add_whowas_to_list(struct Whowas **, struct Whowas *);
+static void del_whowas_from_list(struct Whowas **, struct Whowas *);
+
+struct Whowas WHOWAS[NICKNAMEHISTORYLENGTH];
+struct Whowas *WHOWASHASH[WW_MAX];
+
+static int whowas_next = 0;
+
+unsigned int hash_whowas_name(const char *name)
+{
+       return fnv_hash_upper((const unsigned char *) name, WW_MAX_BITS);
+}
+
+void add_history(struct Client *client_p, int online)
+{
+       struct Whowas *who = &WHOWAS[whowas_next];
+
+       s_assert(NULL != client_p);
+
+       if(client_p == NULL)
+               return;
+
+       if(who->hashv != -1)
+       {
+               if(who->online)
+                       del_whowas_from_clist(&(who->online->whowas), who);
+               del_whowas_from_list(&WHOWASHASH[who->hashv], who);
+       }
+       who->hashv = hash_whowas_name(client_p->name);
+       who->logoff = CurrentTime;
+       /*
+        * NOTE: strcpy ok here, the sizes in the client struct MUST
+        * match the sizes in the whowas struct
+        */
+       strlcpy(who->name, client_p->name, sizeof(who->name));
+       strcpy(who->username, client_p->username);
+       strcpy(who->hostname, client_p->host);
+       strcpy(who->realname, client_p->info);
+       if (!EmptyString(client_p->sockhost) && strcmp(client_p->sockhost, "0") && show_ip(NULL, client_p))
+               strcpy(who->sockhost, client_p->sockhost);
+       else
+               who->sockhost[0] = '\0';
+
+       who->servername = client_p->user->server;
+
+       if(online)
+       {
+               who->online = client_p;
+               add_whowas_to_clist(&(client_p->whowas), who);
+       }
+       else
+               who->online = NULL;
+       add_whowas_to_list(&WHOWASHASH[who->hashv], who);
+       whowas_next++;
+       if(whowas_next == NICKNAMEHISTORYLENGTH)
+               whowas_next = 0;
+}
+
+void off_history(struct Client *client_p)
+{
+       struct Whowas *temp, *next;
+
+       for (temp = client_p->whowas; temp; temp = next)
+       {
+               next = temp->cnext;
+               temp->online = NULL;
+               del_whowas_from_clist(&(client_p->whowas), temp);
+       }
+}
+
+struct Client *get_history(const char *nick, time_t timelimit)
+{
+       struct Whowas *temp;
+       int blah;
+
+       timelimit = CurrentTime - timelimit;
+       blah = hash_whowas_name(nick);
+       temp = WHOWASHASH[blah];
+       for (; temp; temp = temp->next)
+       {
+               if(irccmp(nick, temp->name))
+                       continue;
+               if(temp->logoff < timelimit)
+                       continue;
+               return temp->online;
+       }
+       return NULL;
+}
+
+void count_whowas_memory(size_t * wwu, size_t * wwum)
+{
+       struct Whowas *tmp;
+       int i;
+       size_t u = 0;
+       size_t um = 0;
+
+       /* count the number of used whowas structs in 'u' */
+       /* count up the memory used of whowas structs in um */
+
+       for (i = 0, tmp = &WHOWAS[0]; i < NICKNAMEHISTORYLENGTH; i++, tmp++)
+               if(tmp->hashv != -1)
+               {
+                       u++;
+                       um += sizeof(struct Whowas);
+               }
+       *wwu = u;
+       *wwum = um;
+       return;
+}
+
+void
+initwhowas()
+{
+       int i;
+
+       for (i = 0; i < NICKNAMEHISTORYLENGTH; i++)
+       {
+               memset((void *) &WHOWAS[i], 0, sizeof(struct Whowas));
+               WHOWAS[i].hashv = -1;
+       }
+       for (i = 0; i < WW_MAX; i++)
+               WHOWASHASH[i] = NULL;
+}
+
+
+static void
+add_whowas_to_clist(struct Whowas **bucket, struct Whowas *whowas)
+{
+       whowas->cprev = NULL;
+       if((whowas->cnext = *bucket) != NULL)
+               whowas->cnext->cprev = whowas;
+       *bucket = whowas;
+}
+
+static void
+del_whowas_from_clist(struct Whowas **bucket, struct Whowas *whowas)
+{
+       if(whowas->cprev)
+               whowas->cprev->cnext = whowas->cnext;
+       else
+               *bucket = whowas->cnext;
+       if(whowas->cnext)
+               whowas->cnext->cprev = whowas->cprev;
+}
+
+static void
+add_whowas_to_list(struct Whowas **bucket, struct Whowas *whowas)
+{
+       whowas->prev = NULL;
+       if((whowas->next = *bucket) != NULL)
+               whowas->next->prev = whowas;
+       *bucket = whowas;
+}
+
+static void
+del_whowas_from_list(struct Whowas **bucket, struct Whowas *whowas)
+{
+       if(whowas->prev)
+               whowas->prev->next = whowas->next;
+       else
+               *bucket = whowas->next;
+       if(whowas->next)
+               whowas->next->prev = whowas->prev;
+}
diff --git a/tools/.cvsignore b/tools/.cvsignore
new file mode 100644 (file)
index 0000000..a31e851
--- /dev/null
@@ -0,0 +1,8 @@
+Makefile
+mkpasswd
+viconf
+convertconf
+fixklines
+convertklines
+encspeed
+convertilines
\ No newline at end of file
diff --git a/tools/Makefile.in b/tools/Makefile.in
new file mode 100644 (file)
index 0000000..f942c77
--- /dev/null
@@ -0,0 +1,103 @@
+# $Id: Makefile.in 6 2005-09-10 01:02:21Z nenolod $
+
+CC             = @CC@
+INSTALL                = @INSTALL@
+INSTALL_BIN    = @INSTALL_PROGRAM@
+INSTALL_DATA   = @INSTALL_DATA@
+INSTALL_SUID   = @INSTALL_PROGRAM@ -o root -m 4755
+RM             = @RM@
+LEX            = @LEX@
+LEXLIB         = @LEXLIB@
+CFLAGS         = @IRC_CFLAGS@ -DIRCD_PREFIX=\"@prefix@\"
+LDFLAGS        = @LDFLAGS@
+MKDEP          = @MKDEP@ -DIRCD_PREFIX=\"@prefix@\"
+MV             = @MV@
+RM             = @RM@
+LN              = @LN@
+
+IRCDLIBS       = @LIBS@ 
+INCLUDES       = -I../include 
+CPPFLAGS       = ${INCLUDES} @CPPFLAGS@
+
+prefix         = @prefix@
+exec_prefix    = @exec_prefix@
+bindir         = @bindir@
+libexecdir     = @libexecdir@
+confdir                = @confdir@
+localstatedir  = @localstatedir@
+
+PROGS          = viconf mkpasswd convertilines convertklines 
+
+all: $(PROGS)
+
+build: all
+
+mkpasswd: mkpasswd.c
+       $(CC) $(CFLAGS) $(LDFLAGS) $(INCLUDES) mkpasswd.c -o mkpasswd $(IRCDLIBS)
+
+viconf: viconf.c
+       $(CC) $(CFLAGS) $(LDFLAGS) $(INCLUDES) viconf.c -o viconf $(IRCDLIBS)
+
+convertilines: convertilines.c
+       $(CC) $(CFLAGS) $(LDFLAGS) $(INCLUDES) convertilines.c -o convertilines $(IRCDLIBS)
+
+convertklines: convertklines.c
+       $(CC) $(CFLAGS) $(LDFLAGS) $(INCLUDES) convertklines.c -o convertklines $(IRCDLIBS)
+
+clean:
+       $(RM) -f encspeed viconf chkconf mkpasswd *~ core *.exe convertklines convertilines
+
+distclean: clean
+       $(RM) -f Makefile
+
+lint:
+       lint -aacgprxhH $(CPPFLAGS) -DIRCD_PREFIX=\"@prefix@\" $(convertklines_SOURCES) $(mkpasswd_SOURCES) $(viconf_SOURCES) $(encspeed_SOURCES) >>../lint.out
+
+depend:
+
+.c.o:
+       $(CC) $(CFLAGS) $(INCLUDES) $(CPPFLAGS) -c $<
+
+# DO NOT DELETE
+
+viconf.o: ../include/config.h ../include/setup.h
+viconf.o:
+
+
+prefix         = @prefix@
+exec_prefix    = @exec_prefix@
+exec_suffix    = @exec_suffix@
+bindir         = @bindir@
+libexecdir     = @libexecdir@
+confdir                = @confdir@
+localstatedir  = @localstatedir@
+# Change this later! -- adrian
+moduledir      = @moduledir@
+automoduledir  = @moduledir@/autoload
+
+
+install-mkdirs:
+       -@if test ! -d $(DESTDIR)$(prefix); then \
+               echo "ircd: setting up tools directory structure"; \
+               mkdir $(DESTDIR)$(prefix); \
+       fi
+       -@if test ! -d $(DESTDIR)$(exec_prefix); then \
+               mkdir $(DESTDIR)$(exec_prefix); \
+       fi
+       -@if test ! -d $(DESTDIR)$(bindir); then \
+               mkdir $(DESTDIR)$(bindir); \
+       fi
+
+install: install-mkdirs build
+       @echo "ircd: installing tools ($(PROGS))"
+       @for i in $(PROGS); do \
+               if test -f $(DESTDIR)$(bindir)/$$i; then \
+                       $(MV) $(DESTDIR)$(bindir)/$$i $(DESTDIR)$(bindir)/$$i.old; \
+               fi; \
+               $(INSTALL_BIN) $$i $(DESTDIR)$(bindir); \
+       done; \
+       $(RM) -f $(DESTDIR)$(bindir)/vimotd $(DESTDIR)$(bindir)/viklines
+       $(LN) $(DESTDIR)$(bindir)/viconf $(DESTDIR)$(bindir)/vimotd
+       $(LN) $(DESTDIR)$(bindir)/viconf $(DESTDIR)$(bindir)/viklines
+
diff --git a/tools/README b/tools/README
new file mode 100644 (file)
index 0000000..9ea64db
--- /dev/null
@@ -0,0 +1,22 @@
+$Id: README 6 2005-09-10 01:02:21Z nenolod $
+
+A directory of support programs for ircd.
+
+convertconf.c   - converts a Hybrid 5 or 6 conf file to the new
+                  style.  will not convert I:
+convertilines.c - convert hybrid 5/6 I: to auth {};
+convertklines.c - convert Hybrid 5/6 and early 7beta kline.conf files
+                  to the new spreadsheet like format.
+encspeed.c      - test the speed of various encryption algorithms used in
+                  cryptlinks
+mkkeypair       - a small program used for generating a public and private
+                  key pair
+mkpasswd.c      - makes password for O lines
+rsa_respond/    - a tool to generate an RSA response to the challenge asked
+                  by the server, and a tool to generate a keypair for the
+                  C/R system
+untabify        - converts tab characters to a specific number of spaces
+viconf.c        - edit your conf file without having to chdir su etc. etc.
+                  also locks the file if file locking is used.
+                  viconf is also installed with hard links as vimotd and
+                  viklines, to edit those files in a locked mode.
diff --git a/tools/README.mkpasswd b/tools/README.mkpasswd
new file mode 100644 (file)
index 0000000..2d87a78
--- /dev/null
@@ -0,0 +1,59 @@
+mkpasswd.c documentation
+$Id: README.mkpasswd 6 2005-09-10 01:02:21Z nenolod $
+
+This is documentation for the updated mkpasswd.c included with a number
+of ircd, irc services, and non-IRC related programs
+
+This version of mkpasswd can create DES, Extended DES, BlowFish, and MD5
+passwords, with either randomly generated or user provided salts.  
+
+Options:
+-m Generate an MD5 password
+-d Generate a DES password
+-b Generate a BlowFish password
+-e Generate an Extended (BSDi) DES password
+-l Specify a length for a random MD5 or BlowFish salt
+-r Specify a number of rounds for a BlowFish or Extended DES password
+   BlowFish: no more than 6 recommended, no less than 4 accepted
+   Extended DES: default of 25
+-s Specify a salt, 2 alphanumeric characters for DES, up to 16 for MD5,
+   up to 22 for BlowFish, 2 for Extended DES
+-p Specify a plaintext password to use
+-? Get brief help
+-h Get extended help
+
+Without the presence of any parameters, it'll behave like the old mkpasswd,
+creating a DES password with a randomly generated salt and prompting for
+the password (without echo).
+
+A DES salt is a pair of alphanumeric characters ('.' and '/' are permitted
+as well), such as 'a4' or 'Td'.
+
+An MD5 salt consists of up to 16 (though most implementations limit you to
+8) alphanumeric characters (plus '.' and '/'),
+such as 'tGd' or 'J6d4dfG'.
+
+A BlowFish salt consists of up to 22 alphanumeric characters (plus '.' and
+'/').  BlowFish also specifies a number of rounds*, by default 4.
+
+Known bugs:
+The encryption algorithms supported depend on your system's crypt()
+  implementation.
+The maximum length of an MD5 salt is limited to your systems crypt()
+  implementation, typically 8.
+
+Supported Platforms (Known and tested):
+Linux glibc (DES and MD5)
+FreeBSD 3.x (DES (MD5 maybe))
+FreeBSD 4.x (DES, MD5, BlowFish, Extended DES)
+Solaris 2.5-2.6 (DES only)
+Cygwin 1.1.4 (DES only)
+Prior Cygwin with the MD5 libcrypt (MD5 only)
+OpenBSD 2.7 (don't link with -lcrypt) (DES, MD5, Blowfish)
+Mac OS-X (Darwin) (don't link with -lcrypt) (DES only)
+
+An MMK build script is included, as well as an MD5 crypt() implementation
+
+Other systems probably work, but they haven't been amply tested.
+
+* BlowFish's rounds parameter is a logarithm, not an integer value
diff --git a/tools/convertilines.c b/tools/convertilines.c
new file mode 100644 (file)
index 0000000..d317483
--- /dev/null
@@ -0,0 +1,627 @@
+/* tools/convertilines.c
+ * Copyright (c) 2002 Hybrid Development Team
+ * 
+ *  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.The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: convertilines.c 6 2005-09-10 01:02:21Z nenolod $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#define BUFSIZE 512
+
+#define FLAGS_RESTRICTED       0x001
+#define FLAGS_EXCEEDLIMIT      0x002
+#define FLAGS_KLINEEXEMPT      0x004
+#define FLAGS_GLINEEXEMPT      0x008
+#define FLAGS_NEEDIDENT                0x010
+#define FLAGS_NOTILDE          0x020
+
+struct flag_table_struct
+{
+       const char *name;
+       int flag;
+};
+static struct flag_table_struct flag_table[] =
+{
+       { "restricted",         FLAGS_RESTRICTED        },
+       { "exceed_limit",       FLAGS_EXCEEDLIMIT       },
+       { "kline_exempt",       FLAGS_KLINEEXEMPT       },
+       { "gline_exempt",       FLAGS_GLINEEXEMPT       },
+       { "need_ident",         FLAGS_NEEDIDENT         },
+       { "no_tilde",           FLAGS_NOTILDE           },
+       { NULL, 0 }
+};
+
+struct AuthBlock
+{
+    struct AuthBlock *next;
+
+    char **hostname;
+    int hostnum;
+    
+    char *spoof;
+    char *passwd;
+    int class;
+    int flags;
+
+    /* indicates one of above */
+    int special;
+    int specialk;
+};
+
+static struct AuthBlock *auth_spoof = NULL;
+static struct AuthBlock *auth_special = NULL;
+static struct AuthBlock *auth_passwd = NULL;
+static struct AuthBlock *auth_general = NULL;
+static struct AuthBlock *auth_restricted = NULL;
+
+static void ConvertConf(FILE* file,FILE *out);
+static void set_flags(struct AuthBlock *, const char *, const char *);
+static void usage(void);
+static char *getfield(char *);
+static struct AuthBlock *find_matching_conf(struct AuthBlock *);
+static void ReplaceQuotes(char *out, char *in);
+static void oldParseOneLine(FILE *out, char *in);
+static void write_auth_entries(FILE *out);
+static void write_specific(FILE *out, struct AuthBlock *);
+static int match(struct AuthBlock *, struct AuthBlock *);
+
+int main(int argc,char *argv[])
+{
+  FILE *in;
+  FILE *out;
+
+  if(argc < 3)
+    usage();
+
+  if((in = fopen(argv[1],"r")) == NULL)
+  {
+      fprintf(stderr, "Can't open %s for reading\n", argv[1]);
+      usage();
+  }
+
+  if((out = fopen(argv[2],"w")) == NULL)
+  {
+      fprintf(stderr, "Can't open %s for writing\n", argv[2]);
+      usage();
+  }
+  
+  ConvertConf(in, out);
+
+  return 0;
+}
+
+void usage()
+{
+    fprintf(stderr, "convertilines conf.old conf.new\n");
+    exit(-1);
+}
+
+/*
+ * ConvertConf() 
+ *    Read configuration file.
+ *
+ *
+ * Inputs        - FILE* to config file to convert
+ *              - FILE* to output for new style conf
+ *
+ */
+
+#define MAXCONFLINKS 150
+
+static void ConvertConf(FILE* file, FILE *out)
+{
+  char             line[BUFSIZE];
+  char             quotedLine[BUFSIZE];
+  char*            p;
+
+  while (fgets(line, sizeof(line), file))
+  {
+      if ((p = strchr(line, '\n')))
+          *p = '\0';
+
+      ReplaceQuotes(quotedLine,line);
+
+      if(!*quotedLine || quotedLine[0] == '#' || quotedLine[0] == '\n' ||
+        quotedLine[0] == ' ' || quotedLine[0] == '\t')
+          continue;
+
+      if(quotedLine[0] == '.')
+      {
+          char *filename;
+          char *back;
+
+          if(!strncmp(quotedLine+1,"include ",8))
+          {
+              if( (filename = strchr(quotedLine+8,'"')) )
+                  filename++;
+              else
+              {
+                  fprintf(stderr, "Bad config line: %s", quotedLine);
+                  continue;
+              }
+
+              if((back = strchr(filename,'"')))
+                  *back = '\0';
+              else
+              {
+                  fprintf(stderr, "Bad config line: %s", quotedLine);
+                  continue;
+              }
+
+         }
+      }
+
+      /* Could we test if it's conf line at all?        -Vesa */
+      if (quotedLine[1] == ':')
+          oldParseOneLine(out,quotedLine);
+
+  }
+
+  fclose(file);
+
+  write_auth_entries(out);
+  fclose(out);
+}
+
+/*
+ * ReplaceQuotes
+ * Inputs       - input line to quote
+ * Output       - quoted line
+ * Side Effects - All quoted chars in input are replaced
+ *                with quoted values in output, # chars replaced with '\0'
+ *                otherwise input is copied to output.
+ */
+static void ReplaceQuotes(char* quotedLine,char *inputLine)
+{
+  char *in;
+  char *out;
+  static char  quotes[] = {
+    0,    /*  */
+    0,    /* a */
+    '\b', /* b */
+    0,    /* c */
+    0,    /* d */
+    0,    /* e */
+    '\f', /* f */
+    0,    /* g */
+    0,    /* h */
+    0,    /* i */
+    0,    /* j */
+    0,    /* k */
+    0,    /* l */
+    0,    /* m */
+    '\n', /* n */
+    0,    /* o */
+    0,    /* p */
+    0,    /* q */
+    '\r', /* r */
+    0,    /* s */
+    '\t', /* t */
+    0,    /* u */
+    '\v', /* v */
+    0,    /* w */
+    0,    /* x */
+    0,    /* y */
+    0,    /* z */
+    0,0,0,0,0,0 
+    };
+
+  /*
+   * Do quoting of characters and # detection.
+   */
+  for (out = quotedLine,in = inputLine; *in; out++, in++)
+    {
+      if (*in == '\\')
+       {
+          in++;
+          if(*in == '\\')
+            *out = '\\';
+          else if(*in == '#')
+            *out = '#';
+         else
+           *out = quotes[ (unsigned int) (*in & 0x1F) ];
+       }
+      else if (*in == '#')
+        {
+         *out = '\0';
+          return;
+       }
+      else
+        *out = *in;
+    }
+  *out = '\0';
+}
+
+/*
+ * oldParseOneLine
+ * Inputs       - pointer to line to parse
+ *             - pointer to output to write
+ * Output       - 
+ * Side Effects - Parse one old style conf line.
+ */
+
+static void oldParseOneLine(FILE *out,char* line)
+{
+  char conf_letter;
+  char* tmp;
+  const char* host_field=NULL;
+  const char* passwd_field=NULL;
+  const char* user_field=NULL;
+  const char* port_field = NULL;
+  const char* classconf_field = NULL;
+  int class_field = 0;
+
+  tmp = getfield(line);
+
+  conf_letter = *tmp;
+
+  for (;;) /* Fake loop, that I can use break here --msa */
+  {
+      /* host field */
+      if ((host_field = getfield(NULL)) == NULL)
+       return;
+      
+      /* pass field */
+      if ((passwd_field = getfield(NULL)) == NULL)
+       break;
+
+      /* user field */
+      if ((user_field = getfield(NULL)) == NULL)
+       break;
+
+      /* port field */
+      if ((port_field = getfield(NULL)) == NULL)
+       break;
+
+      /* class field */
+      if ((classconf_field = getfield(NULL)) == NULL)
+       break;
+
+      break;
+  }
+
+  if (!passwd_field)
+    passwd_field = "";
+  if (!user_field)
+    user_field = "";
+  if (!port_field)    
+    port_field = "";
+  if (classconf_field)
+    class_field = atoi(classconf_field);
+
+  switch( conf_letter )
+  {
+    case 'i': 
+    case 'I': 
+    {
+        struct AuthBlock *ptr;
+       struct AuthBlock *tempptr;
+
+       tempptr = malloc(sizeof(struct AuthBlock));
+       memset(tempptr, 0, sizeof(*tempptr));
+
+       if(conf_letter == 'i')
+       {
+           tempptr->flags |= FLAGS_RESTRICTED;
+           tempptr->specialk = 1;
+       }
+
+        if(passwd_field && *passwd_field)
+           tempptr->passwd = strdup(passwd_field);
+
+       tempptr->class = class_field;
+
+       set_flags(tempptr, user_field, host_field);
+
+       /* dont add specials/passworded ones to existing auth blocks */
+        if((ptr = find_matching_conf(tempptr)))
+       {
+            int authindex;
+
+           authindex = ptr->hostnum;
+           ptr->hostnum++;
+
+           ptr->hostname = realloc((void *)ptr->hostname, ptr->hostnum * sizeof(void *));
+
+           ptr->hostname[authindex] = strdup(tempptr->hostname[0]);
+
+           free(tempptr->hostname[0]);
+           free(tempptr->hostname);
+           free(tempptr);
+       }
+       else
+       {
+           ptr = tempptr;
+
+            if(ptr->spoof)
+           {
+               ptr->next = auth_spoof;
+               auth_spoof = ptr;
+           }
+           else if(ptr->special)
+           {
+               ptr->next = auth_special;
+               auth_special = ptr;
+           }
+           else if(ptr->passwd)
+           {
+               ptr->next = auth_passwd;
+               auth_passwd = ptr;
+           }
+           else if(ptr->specialk)
+           {
+               ptr->next = auth_restricted;
+               auth_restricted = ptr;
+           }
+           else
+           {
+               ptr->next = auth_general;
+               auth_general = ptr;
+           }
+       }
+    }
+    break;
+      
+    default:
+      break;
+  }
+}
+
+static void write_auth_entries(FILE *out)
+{
+    struct AuthBlock *ptr;
+
+    for(ptr = auth_spoof; ptr; ptr = ptr->next)
+       write_specific(out, ptr);
+
+    for(ptr = auth_special; ptr; ptr = ptr->next)
+       write_specific(out, ptr);
+
+    for(ptr = auth_passwd; ptr; ptr = ptr->next)
+       write_specific(out, ptr);
+
+    for(ptr = auth_general; ptr; ptr = ptr->next)
+       write_specific(out, ptr);
+
+    for(ptr = auth_restricted; ptr; ptr = ptr->next)
+       write_specific(out, ptr);
+}
+
+    
+static void write_specific(FILE *out, struct AuthBlock *ptr)
+{
+    int i;
+    int prev = 0;
+
+    fprintf(out, "auth {\n");
+
+    for(i = 0; i < ptr->hostnum; i++)
+        fprintf(out, "\tuser = \"%s\";\n", ptr->hostname[i]);
+
+    if(ptr->spoof)
+       fprintf(out, "\tspoof = \"%s\";\n", ptr->spoof);
+
+    if(ptr->passwd)
+       fprintf(out, "\tpassword = \"%s\";\n", ptr->passwd);
+
+    if(ptr->flags)
+    {
+           fprintf(out, "\tflags = ");
+
+           for(i = 0; flag_table[i].flag; i++)
+           {
+                   if(ptr->flags & flag_table[i].flag)
+                   {
+                           fprintf(out, "%s%s", 
+                                       prev ? ", " : "", 
+                                       flag_table[i].name);
+                           prev = 1;
+                   }
+           }
+
+           fprintf(out, ";\n");
+    }
+
+    fprintf(out, "\tclass = \"%d\";\n", ptr->class);
+    fprintf(out, "};\n");
+}
+
+/*
+ * field breakup for ircd.conf file.
+ */
+static char *getfield(char *newline)
+{
+  static char *line = NULL;
+  char  *end, *field;
+        
+  if (newline)
+    line = newline;
+
+  if (line == NULL)
+    return(NULL);
+
+  field = line;
+  if ((end = strchr(line,':')) == NULL)
+    {
+      line = NULL;
+      if ((end = strchr(field,'\n')) == NULL)
+        end = field + strlen(field);
+    }
+  else
+    line = end + 1;
+  *end = '\0';
+  return(field);
+}
+
+struct AuthBlock *find_matching_conf(struct AuthBlock *acptr)
+{
+    struct AuthBlock *ptr;
+
+    for(ptr = auth_spoof; ptr; ptr = ptr->next)
+    {
+       if(match(ptr, acptr))
+           return ptr;
+    }
+
+    for(ptr = auth_special; ptr; ptr = ptr->next)
+    {
+       if(match(ptr, acptr))
+           return ptr;
+    }
+
+    for(ptr = auth_passwd; ptr; ptr = ptr->next)
+    {
+       if(match(ptr, acptr))
+           return ptr;
+    }
+
+    for(ptr = auth_restricted; ptr; ptr = ptr->next)
+    {
+       if(match(ptr, acptr))
+           return ptr;
+    }
+       
+    for(ptr = auth_general; ptr; ptr = ptr->next)
+    {
+        if(match(ptr, acptr))
+           return ptr;
+    }
+
+
+    return NULL;
+}
+
+static int match(struct AuthBlock *ptr, struct AuthBlock *acptr)
+{
+    if((ptr->class == acptr->class) &&
+       (ptr->flags == acptr->flags))
+    {
+       const char *p1, *p2;
+       
+       /* check the spoofs match.. */
+       if(ptr->spoof)
+          p1 = ptr->spoof;
+       else
+          p1 = "";
+
+       if(acptr->spoof)
+          p2 = acptr->spoof;
+       else
+          p2 = "";
+
+       if(strcmp(p1, p2))
+           return 0;
+
+       /* now check the passwords match.. */
+       if(ptr->passwd)
+           p1 = ptr->passwd;
+       else
+           p1 = "";
+
+       if(acptr->passwd)
+           p2 = acptr->passwd;
+       else
+           p2 = "";
+
+       if(strcmp(p1, p2))
+           return 0;
+
+       return 1;
+    }
+
+    return 0;
+}
+
+void set_flags(struct AuthBlock *ptr, const char *user_field, const char *host_field)
+{
+  for(; *user_field; user_field++)
+  {
+      switch(*user_field)
+      {
+          case '=':
+             if(host_field)
+                 ptr->spoof = strdup(host_field);
+
+             ptr->special = 1;
+              break;
+
+          case '-':
+             ptr->flags |= FLAGS_NOTILDE;
+             ptr->special = 1;
+              break;
+
+          case '+':
+             ptr->flags |= FLAGS_NEEDIDENT;
+             ptr->specialk = 1;
+              break;
+
+          case '^':        /* is exempt from k/g lines */
+             ptr->flags |= FLAGS_KLINEEXEMPT;
+             ptr->special = 1;
+              break;
+
+         case '>':
+             ptr->flags |= FLAGS_EXCEEDLIMIT;
+             ptr->special = 1;
+             break;
+
+         case '_':
+             ptr->flags |= FLAGS_GLINEEXEMPT;
+             ptr->special = 1;
+             break;
+
+         case '!':
+          case '$':
+          case '%':
+          case '&':
+         case '<':
+              break;
+
+          default:
+         {
+             int authindex;
+             authindex = ptr->hostnum;
+             ptr->hostnum++;
+
+              ptr->hostname = realloc((void *)ptr->hostname, ptr->hostnum * sizeof(void *));
+
+             /* if the IP field contains something useful, use that */
+             if(strcmp(host_field, "NOMATCH") && (*host_field != 'x') && 
+               strcmp(host_field, "*") && !ptr->spoof)
+                 ptr->hostname[authindex] = strdup(host_field);
+             else
+                 ptr->hostname[authindex] = strdup(user_field);
+
+             return;
+         }
+      }
+  }
+}
+
diff --git a/tools/convertklines.c b/tools/convertklines.c
new file mode 100644 (file)
index 0000000..deb8ff8
--- /dev/null
@@ -0,0 +1,305 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, tools/convertklines.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.
+ *
+ * $Id: convertklines.c 6 2005-09-10 01:02:21Z nenolod $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#define BUFSIZE 512
+
+static void ConvertConf(FILE* file,FILE *outkline, FILE *outdline);
+static void usage(void);
+static char *getfield(char *);
+static void ReplaceQuotes(char *out, char *in);
+static void parse(FILE *outkline, FILE *outdline, char *in);
+
+int main(int argc,char *argv[])
+{
+  FILE *in;
+  FILE *outkline;
+  FILE *outdline;
+
+  if(argc < 4)
+    usage();
+
+  if (( in = fopen(argv[1],"r")) == NULL )
+    {
+      fprintf(stderr,"Can't open %s for reading\n", argv[1]);
+      usage();
+    }
+
+  if (( outkline = fopen(argv[2],"w")) == NULL )
+    {
+      fprintf(stderr,"Can't open %s for writing\n", argv[2]);
+      usage();
+    }
+  
+  if(( outdline = fopen(argv[3], "w")) == NULL )
+    {
+      fprintf(stderr, "Can't open %s for writing\n", argv[3]);
+      usage();
+    }
+    
+  ConvertConf(in, outkline, outdline);
+
+  fprintf(stderr, "The kline file has been converted and should be renamed to\n");
+  fprintf(stderr, "the config.h options (normally kline.conf and dline.conf) and\n");
+  fprintf(stderr, "placed in your etc/ dir\n");
+  return 0;
+}
+
+static void usage()
+{
+  fprintf(stderr, "klines and dlines now go in separate files:\n");
+  fprintf(stderr,"convertklines kline.conf.old kline.conf.new dline.conf.new\n");
+  exit(-1);
+}
+
+
+/*
+ * ConvertConf() 
+ *    Read configuration file.
+ *
+ *
+ * inputs      - FILE* to config file to convert
+ *             - FILE* to output for new klines
+ *             - FILE* to output for new dlines
+ * outputs     - -1 if the file cannot be opened
+ *             - 0 otherwise
+ */
+
+static void ConvertConf(FILE* file, FILE *outkline, FILE *outdline)
+{
+  char             line[BUFSIZE];
+  char             quotedLine[BUFSIZE];
+  char*            p;
+
+  while (fgets(line, sizeof(line), file))
+    {
+      if ((p = strchr(line, '\n')))
+        *p = '\0';
+
+      ReplaceQuotes(quotedLine,line);
+
+      if (!*quotedLine || quotedLine[0] == '#' || quotedLine[0] == '\n' ||
+          quotedLine[0] == ' ' || quotedLine[0] == '\t')
+        continue;
+
+      /* Could we test if it's conf line at all?        -Vesa */
+      if (quotedLine[1] == ':')
+      {
+        parse(outkline, outdline, quotedLine);
+      }
+    }
+
+  fclose(file);
+}
+
+/*
+ * ReplaceQuotes
+ * Inputs       - input line to quote
+ * Output       - quoted line
+ * Side Effects - All quoted chars in input are replaced
+ *                with quoted values in output, # chars replaced with '\0'
+ *                otherwise input is copied to output.
+ */
+static void ReplaceQuotes(char* quotedLine,char *inputLine)
+{
+  char *in;
+  char *out;
+  static char  quotes[] = {
+    0,    /*  */
+    0,    /* a */
+    '\b', /* b */
+    0,    /* c */
+    0,    /* d */
+    0,    /* e */
+    '\f', /* f */
+    0,    /* g */
+    0,    /* h */
+    0,    /* i */
+    0,    /* j */
+    0,    /* k */
+    0,    /* l */
+    0,    /* m */
+    '\n', /* n */
+    0,    /* o */
+    0,    /* p */
+    0,    /* q */
+    '\r', /* r */
+    0,    /* s */
+    '\t', /* t */
+    0,    /* u */
+    '\v', /* v */
+    0,    /* w */
+    0,    /* x */
+    0,    /* y */
+    0,    /* z */
+    0,0,0,0,0,0 
+    };
+
+  /*
+   * Do quoting of characters and # detection.
+   */
+  for (out = quotedLine,in = inputLine; *in; out++, in++)
+    {
+      if (*in == '\\')
+       {
+          in++;
+          if(*in == '\\')
+            *out = '\\';
+          else if(*in == '#')
+            *out = '#';
+         else
+           *out = quotes[ (unsigned int) (*in & 0x1F) ];
+       }
+      else if (*in == '#')
+        {
+         *out = '\0';
+          return;
+       }
+      else
+        *out = *in;
+    }
+  *out = '\0';
+}
+
+/*
+ * parse()
+ * Inputs       - pointer to line to parse
+ *             - pointer to output to write
+ * Output       - 
+ * Side Effects - Parse one old style conf line.
+ */
+
+static void parse(FILE *outkline, FILE *outdline, char* line)
+{
+  char conf_letter;
+  char *tmp;
+  const char *user_field = NULL;
+  const char *passwd_field = NULL;
+  const char *host_field = NULL;
+  const char *operpasswd_field = NULL;
+
+  tmp = getfield(line);
+
+  conf_letter = *tmp;
+
+  for (;;) /* Fake loop, that I can use break here --msa */
+  {
+    /* host field */
+    if ((host_field = getfield(NULL)) == NULL)
+      return;
+      
+    /* pass field */
+    if ((passwd_field = getfield(NULL)) == NULL) 
+      break;
+    else
+    {
+      /* if theres a password, try splitting the operreason out */
+      char *p;
+
+      if((p = strchr(passwd_field, '|')))
+      {
+        *p++ = '\0';
+        operpasswd_field = p;
+      }
+      else
+        operpasswd_field = "";
+    }
+
+    /* user field */
+    if ((user_field = getfield(NULL)) == NULL)
+      break;
+
+    /* what could possibly be after a userfield? */
+    break;
+  }
+
+  if (!passwd_field)
+  {
+    passwd_field = "";
+    operpasswd_field = "";
+  }
+   
+  if (!user_field)
+    user_field = "";
+    
+  switch( conf_letter )
+  {
+    case 'd':
+      fprintf(stderr, "exempt in old file, ignoring.\n");
+      break;
+
+    case 'D': /* Deny lines (immediate refusal) */
+      if(host_field && passwd_field)
+        fprintf(outdline, "\"%s\",\"%s\",\"%s\",\"\",\"Unknown\",0\n",
+               host_field, passwd_field, operpasswd_field);
+      break;
+
+    case 'K': /* Kill user line on irc.conf           */
+    case 'k':
+      if(host_field && passwd_field && user_field)
+        fprintf(outkline, "\"%s\",\"%s\",\"%s\",\"%s\",\"\",\"Unknown\",0\n",
+               user_field, host_field, passwd_field, operpasswd_field);
+      break;
+
+    default:
+      fprintf(stderr, "Error in config file: %s", line);
+      break;
+  }
+}
+
+
+/*
+ * field breakup for ircd.conf file.
+ */
+static char *getfield(char *newline)
+{
+  static char *line = NULL;
+  char  *end, *field;
+        
+  if (newline)
+    line = newline;
+  
+  if (line == NULL)
+  {
+    fprintf(stderr, "returned null!\n");
+    return NULL;
+  }
+  
+  field = line;
+  
+  if ((end = strchr(line,':')) == NULL)
+    {
+      line = NULL;
+      if ((end = strchr(field,'\n')) == NULL)
+        end = field + strlen(field);
+    }
+  else
+    line = end + 1;
+    
+  *end = '\0';
+  
+  return field;
+}
+
+
diff --git a/tools/mkkeypair b/tools/mkkeypair
new file mode 100755 (executable)
index 0000000..598bd2f
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+dd if=/dev/urandom of=randdata count=1 bs=2048
+openssl genrsa -rand randdata -out private.key 2048
+openssl rsa -in private.key -out public.key -pubout
+rm randdata
diff --git a/tools/mkpasswd.c b/tools/mkpasswd.c
new file mode 100644 (file)
index 0000000..6c1fed3
--- /dev/null
@@ -0,0 +1,364 @@
+/* simple password generator by Nelson Minar (minar@reed.edu)
+** copyright 1991, all rights reserved.
+** You can use this code as long as my name stays with it.
+**
+** md5 patch by W. Campbell <wcampbel@botbay.net>
+** Modernization, getopt, etc for the Hybrid IRCD team
+** by W. Campbell
+** 
+** /dev/random for salt generation added by 
+** Aaron Sethman <androsyn@ratbox.org>
+**
+** $Id: mkpasswd.c 6 2005-09-10 01:02:21Z nenolod $
+*/
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#define FLAG_MD5     0x00000001
+#define FLAG_DES     0x00000002
+#define FLAG_SALT    0x00000004
+#define FLAG_PASS    0x00000008
+#define FLAG_LENGTH  0x00000010
+#define FLAG_BLOWFISH 0x00000020
+#define FLAG_ROUNDS  0x00000040
+#define FLAG_EXT     0x00000080
+
+extern char *getpass();
+extern char *crypt();
+
+static char *make_des_salt(void);
+static char *make_ext_salt(int);
+static char *make_ext_salt_para(int, char *);
+static char *make_md5_salt(int);
+static char *make_md5_salt_para(char *);
+static char *make_bf_salt(int, int);
+static char *make_bf_salt_para(int, char *);
+static char *int_to_base64(int);
+static char *generate_random_salt(char *, int);
+static char *generate_poor_salt(char *, int);
+
+static void full_usage(void);
+static void brief_usage(void);
+
+static char saltChars[] =
+       "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+       /* 0 .. 63, ascii - 64 */
+
+extern char *optarg;
+
+int main(int argc, char *argv[])
+{
+  char *plaintext = NULL;
+  int c;
+  char *saltpara = NULL;
+  char *salt;
+  int flag = 0;
+  int length = 0; /* Not Set */
+  int rounds = 0; /* Not set, since extended DES needs 25 and blowfish needs
+                  ** 4 by default, a side effect of this being the encryption
+                  ** type parameter must be specified before the rounds
+                  ** parameter.
+                  */
+
+  while( (c=getopt(argc, argv, "mdber:h?l:s:p:")) != -1)
+  {
+    switch(c)
+    {
+      case 'm':
+        flag |= FLAG_MD5;
+        break;
+      case 'd':
+        flag |= FLAG_DES;
+        break;
+      case 'b':
+        flag |= FLAG_BLOWFISH;
+        rounds = 4;
+        break;
+      case 'e':
+        flag |= FLAG_EXT;
+        rounds = 25;
+        break;
+      case 'l':
+        flag |= FLAG_LENGTH;
+        length = atoi(optarg);
+        break;
+      case 'r':
+        flag |= FLAG_ROUNDS;
+        rounds = atoi(optarg);
+        break;
+      case 's':
+        flag |= FLAG_SALT;
+        saltpara = optarg;
+        break;
+      case 'p':
+        flag |= FLAG_PASS;
+        plaintext = optarg;
+        break;
+      case 'h':
+        full_usage();
+        /* NOT REACHED */
+        break;
+      case '?':
+        brief_usage();
+        /* NOT REACHED */
+        break;
+      default:
+        printf("Invalid Option: -%c\n", c);
+        break;
+    }
+  }
+
+  if (flag & FLAG_MD5)
+  {
+    if (length == 0)
+      length = 8;
+    if (flag & FLAG_SALT)
+      salt = make_md5_salt_para(saltpara);
+    else
+      salt = make_md5_salt(length);
+  }
+  else if (flag & FLAG_BLOWFISH)
+  {
+    if (length == 0)
+      length = 22;
+    if (flag & FLAG_SALT)
+      salt = make_bf_salt_para(rounds, saltpara);
+    else
+      salt = make_bf_salt(rounds, length);
+  }
+  else if (flag & FLAG_EXT)
+  {
+    /* XXX - rounds needs to be done */
+    if (flag & FLAG_SALT)
+    {
+      if ((strlen(saltpara) == 4))
+      {
+        salt = make_ext_salt_para(rounds, saltpara);
+      }
+      else
+      {
+        printf("Invalid salt, please enter 4 alphanumeric characters\n");
+        exit(1);
+      }
+    }
+    else
+    {
+      salt = make_ext_salt(rounds);
+    }
+  }
+  else
+  {
+    if (flag & FLAG_SALT)
+    {
+      if ((strlen(saltpara) == 2))
+      {
+        salt = saltpara;
+      }
+      else
+      {
+        printf("Invalid salt, please enter 2 alphanumeric characters\n");
+        exit(1);
+      }
+    }
+    else
+    {
+      salt = make_des_salt();
+    }
+  }
+
+  if (flag & FLAG_PASS)
+  {
+    if (!plaintext)
+      printf("Please enter a valid password\n");
+  }
+  else
+  {
+    plaintext = getpass("plaintext: ");
+  }
+
+  printf("%s\n", crypt(plaintext, salt));
+  return 0;
+}
+
+static char *make_des_salt()
+{
+  static char salt[3];
+  generate_random_salt(salt, 2);
+  salt[2] = '\0';
+  return salt;
+}
+
+char *int_to_base64(int value)
+{
+  static char buf[5];
+  int i;
+
+  for (i = 0; i < 4; i++)
+  {
+    buf[i] = saltChars[value & 63];
+    value >>= 6;  /* Right shifting 6 places is the same as dividing by 64 */
+  }
+
+  buf[i] = '\0';  /* not REALLY needed as it's static, and thus initialized
+                  ** to \0.
+                  */
+  return buf;
+}
+
+char *make_ext_salt(int rounds)
+{
+  static char salt[10];
+
+  sprintf(salt, "_%s", int_to_base64(rounds));
+  generate_random_salt(&salt[5], 4);
+  salt[9] = '\0';
+  return salt;
+}
+
+char *make_ext_salt_para(int rounds, char *saltpara)
+{
+  static char salt[10];
+
+  sprintf(salt, "_%s%s", int_to_base64(rounds), saltpara);
+  return salt;
+}
+
+char *make_md5_salt_para(char *saltpara)
+{
+  static char salt[21];
+  if (saltpara && (strlen(saltpara) <= 16))
+  {
+    /* sprintf used because of portability requirements, the length
+    ** is checked above, so it should not be too much of a concern
+    */
+    sprintf(salt, "$1$%s$", saltpara);
+    return salt;
+  }
+  printf("Invalid Salt, please use up to 16 random alphanumeric characters\n");
+  exit(1);
+
+  /* NOT REACHED */
+  return NULL;
+}
+  
+char *make_md5_salt(int length)
+{
+  static char salt[21];
+  if (length > 16)
+  {
+    printf("MD5 salt length too long\n");
+    exit(0);
+  }
+  salt[0] = '$';
+  salt[1] = '1';
+  salt[2] = '$';
+  generate_random_salt(&salt[3], length);
+  salt[length+3] = '$';
+  salt[length+4] = '\0';
+  return salt;
+}
+
+char *make_bf_salt_para(int rounds, char *saltpara)
+{
+  static char salt[31];
+  char tbuf[3];
+  if (saltpara && (strlen(saltpara) <= 22))
+  {
+    /* sprintf used because of portability requirements, the length
+    ** is checked above, so it should not be too much of a concern
+    */
+    sprintf(tbuf, "%02d", rounds);
+    sprintf(salt, "$2a$%s$%s$", tbuf, saltpara);
+    return salt;
+  }
+  printf("Invalid Salt, please use up to 22 random alphanumeric characters\n");
+  exit(1);
+
+  /* NOT REACHED */
+  return NULL;
+}
+
+char *make_bf_salt(int rounds, int length)
+{
+  static char salt[31];
+  char tbuf[3];
+  if (length > 22)
+  {
+    printf("BlowFish salt length too long\n");
+    exit(0);
+  }
+  sprintf(tbuf, "%02d", rounds);
+  sprintf(salt, "$2a$%s$", tbuf);
+  generate_random_salt(&salt[7], length);
+  salt[length+7] = '$';
+  salt[length+8] = '\0';
+  return salt;
+}
+
+char *generate_poor_salt(char *salt, int length)
+{
+  int i;
+  srandom(time(NULL));
+  for(i = 0; i < length; i++)
+  {
+    salt[i] = saltChars[random() % 64];
+  }
+  return(salt);
+}
+
+char *generate_random_salt(char *salt, int length)
+{
+  char *buf;
+  int fd, i;
+  if((fd = open("/dev/random", O_RDONLY)) < 0)
+  {
+    return(generate_poor_salt(salt, length));  
+  }
+  buf = calloc(1, length);
+  if(read(fd, buf, length) != length)
+  {
+    free(buf);
+    return(generate_poor_salt(salt, length));
+  }
+       
+  for(i = 0; i < length; i++)
+  {
+    salt[i] = saltChars[abs(buf[i]) % 64];
+  }
+  free(buf);
+  return(salt);
+}
+
+void full_usage()
+{
+  printf("mkpasswd [-m|-d|-b|-e] [-l saltlength] [-r rounds] [-s salt] [-p plaintext]\n");
+  printf("-m Generate an MD5 password\n");
+  printf("-d Generate a DES password\n");
+  printf("-b Generate a BlowFish password\n");
+  printf("-e Generate an Extended DES password\n");
+  printf("-l Specify a length for a random MD5 or BlowFish salt\n");
+  printf("-r Specify a number of rounds for a BlowFish or Extended DES password\n");
+  printf("   BlowFish:  default 4, no more than 6 recommended\n");
+  printf("   Extended DES:  default 25\n");
+  printf("-s Specify a salt, 2 alphanumeric characters for DES, up to 16 for MD5,\n");
+  printf("   up to 22 for BlowFish, and 4 for Extended DES\n");
+  printf("-p Specify a plaintext password to use\n");
+  printf("Example: mkpasswd -m -s 3dr -p test\n");
+  exit(0);
+}
+
+void brief_usage()
+{
+  printf("mkpasswd - password hash generator\n");
+  printf("Standard DES:  mkpasswd [-d] [-s salt] [-p plaintext]\n");
+  printf("Extended DES:  mkpasswd -e [-r rounds] [-s salt] [-p plaintext]\n");
+  printf("         MD5:  mkpasswd -m [-l saltlength] [-s salt] [-p plaintext]\n");
+  printf("    BlowFish:  mkpasswd -b [-r rounds] [-l saltlength] [-s salt]\n");
+  printf("                           [-p plaintext]\n");
+  printf("Use -h for full usage\n");
+  exit(0);
+}
diff --git a/tools/untabify b/tools/untabify
new file mode 100755 (executable)
index 0000000..94880e0
--- /dev/null
@@ -0,0 +1,9 @@
+#!/usr/bin/perl
+#
+# untabify - convert tabs to spaces
+#
+# $Id: untabify 6 2005-09-10 01:02:21Z nenolod $
+use Text::Tabs;
+$tabstop = 8;
+while (<>) { print expand($_) }
+
diff --git a/tools/viconf.c b/tools/viconf.c
new file mode 100644 (file)
index 0000000..d716d51
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * viconf.c
+ *
+ * $Id: viconf.c 6 2005-09-10 01:02:21Z nenolod $
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+#include <signal.h>
+#include "config.h"
+
+
+/* wait.h is in /include on solaris, likely on other SYSV machines as well
+ * but wait.h is normally in /include/sys on BSD boxen,
+ * probably we should have an #ifdef SYSV?
+ * -Dianora
+ */
+
+#ifdef SOL20
+#include <wait.h>
+#else
+#include <sys/wait.h>
+#endif
+
+static int LockedFile(const char *filename);
+static char lockpath[PATH_MAX + 1];
+
+
+int main(int argc, char *argv[])
+{
+  const char *ed, *p, *filename = CPATH;
+
+  if( chdir(DPATH) < 0 )
+    {
+      fprintf(stderr,"Cannot chdir to %s\n", DPATH);
+      exit(errno);
+    }
+
+  if((p = strrchr(argv[0], '/')) == NULL)
+    p = argv[0];
+  else
+    p++;
+#ifdef KPATH
+  if(strcmp(p, "viklines") == 0)
+    filename = KPATH;
+#endif /* KPATH */
+
+  if(strcmp(p, "vimotd") == 0)
+    filename = MPATH;
+
+  if(LockedFile(filename))
+    {
+      fprintf(stderr,"Can't lock %s\n", filename);
+      exit(errno);
+    }
+
+  /* ed config file */
+  switch(fork())
+    {
+    case -1:
+      fprintf(stderr, "error forking, %d\n", errno);
+      exit(errno);
+    case 0:            /* Child */
+      if((ed = getenv("EDITOR")) == NULL)
+       ed = "vi";
+      execlp(ed, ed, filename, NULL);
+      fprintf(stderr, "error running editor, %d\n", errno);
+      exit(errno);
+    default:
+      wait(0);
+    }
+
+  unlink(lockpath);
+  return 0;
+}
+
+/*
+ * LockedFile() (copied from m_kline.c in ircd)
+ * Determine if 'filename' is currently locked. If it is locked,
+ * there should be a filename.lock file which contains the current
+ * pid of the editing process. Make sure the pid is valid before
+ * giving up.
+ *
+ * Return: 1 if locked
+ *         -1 if couldn't unlock
+ *         0 if was able to lock
+ */
+
+
+
+static int
+LockedFile(const char *filename)
+
+{
+
+  char buffer[1024];
+  FILE *fileptr;
+  int killret;
+  int fd;
+
+  if (!filename)
+    return (0);
+  
+  sprintf(lockpath, "%s.lock", filename);
+  
+  if ((fileptr = fopen(lockpath, "r")) != NULL)
+    {
+      if (fgets(buffer, sizeof(buffer) - 1, fileptr))
+       {
+         /*
+          * If it is a valid lockfile, 'buffer' should now
+          * contain the pid number of the editing process.
+          * Send the pid a SIGCHLD to see if it is a valid
+          * pid - it could be a remnant left over from a
+          * crashed editor or system reboot etc.
+          */
+      
+         killret = kill(atoi(buffer), SIGCHLD);
+         if (killret == 0)
+           {
+             fclose(fileptr);
+             return (1);
+           }
+
+         /*
+          * killret must be -1, which indicates an error (most
+          * likely ESRCH - No such process), so it is ok to
+          * proceed writing klines.
+          */
+       }
+      fclose(fileptr);
+    }
+
+  /*
+   * Delete the outdated lock file
+   */
+  unlink(lockpath);
+
+  /* create exclusive lock */
+  if((fd = open(lockpath, O_WRONLY|O_CREAT|O_EXCL, 0666)) < 0)
+    {
+      fprintf(stderr, "ircd config file locked\n");
+      return (-1);
+    }
+
+  fileptr = fdopen(fd,"w");
+  fprintf(fileptr,"%d\n",(int)getpid());
+  fclose(fileptr);
+  return (0);
+} /* LockedFile() */
diff --git a/unsupported/Makefile.in b/unsupported/Makefile.in
new file mode 100644 (file)
index 0000000..2ebf514
--- /dev/null
@@ -0,0 +1,69 @@
+#
+# Makefile.in for ircd/unsupported
+#
+# $Id: Makefile.in 1425 2006-05-23 16:41:33Z jilles $
+#
+CC             = @CC@
+RM             = @RM@
+SED             = @SED@
+LEX            = @LEX@
+LEXLIB         = @LEXLIB@
+CFLAGS         = @IRC_CFLAGS@ -DIRCD_PREFIX=\"@prefix@\"
+PICFLAGS       = @PICFLAGS@
+MKDEP          = @MKDEP@
+INSTALL                = @INSTALL@
+INSTALL_PROGRAM        = @INSTALL_PROGRAM@
+INSTALL_DATA   = @INSTALL_DATA@
+INSTALL_SUID    = @INSTALL_PROGRAM@ -o root -m 4755
+SHELL          = /bin/sh
+AUTOMODULEDIR  = @moduledir@/unsupported
+
+SSL_LIBS       = @SSL_LIBS@
+SSL_INCLUDES   = @SSL_INCLUDES@
+
+IRCDLIBS       = @LIBS@ $(SSL_LIBS)
+
+INCLUDES       = -I. -I../include -I../libcharybdis -I../adns $(SSL_INCLUDES)
+CPPFLAGS       = ${INCLUDES} @CPPFLAGS@
+
+SRCS =                          \
+  m_clearchan.c                        \
+  m_force.c
+
+OBJS = ${SRCS:.c=.so}
+
+default:       build
+build: all
+all: $(OBJS)
+
+install: all
+       -@if test ! -d $(DESTDIR)$(AUTOMODULEDIR); then \
+                mkdir $(DESTDIR)$(AUTOMODULEDIR); \
+        fi
+       @echo "Installing modules into $(DESTDIR)$(AUTOMODULEDIR) .."
+       @for file in $(OBJS); do \
+               $(INSTALL_DATA) $$file $(DESTDIR)$(AUTOMODULEDIR); \
+       done
+
+.SUFFIXES: .so
+
+.c.so:
+       ${CC} ${PICFLAGS}  ${CPPFLAGS} ${CFLAGS} $< -o $@
+
+.PHONY: depend clean distclean
+depend:
+       @${MKDEP} ${CPPFLAGS} ${SRCS} > .depend
+       @sed s/\\\.o/\\\.so/ < .depend > .depend.tmp
+       @sed -e '/^# DO NOT DELETE THIS LINE/,$$d' <Makefile >Makefile.depend
+       @echo '# DO NOT DELETE THIS LINE!!!' >>Makefile.depend
+       @echo '# make depend needs it.' >>Makefile.depend
+       @cat .depend.tmp >>Makefile.depend
+       @mv Makefile.depend Makefile
+       @rm -f .depend.tmp .depend
+
+clean:
+       ${RM} -f *.so *~ 
+
+distclean: clean
+       ${RM} -f Makefile
+
diff --git a/unsupported/m_clearchan.c b/unsupported/m_clearchan.c
new file mode 100644 (file)
index 0000000..505cce8
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ *   IRC - Internet Relay Chat, contrib/m_clearchan.c
+ *   Copyright (C) 2002 Hybrid Development Team
+ *   Copyright (C) 2004 ircd-ratbox Development 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 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_clearchan.c 1425 2006-05-23 16:41:33Z jilles $
+ */
+#include "stdinc.h"
+#include "tools.h"
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_user.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "packet.h"
+
+static int mo_clearchan(struct Client *client_p, struct Client *source_p,
+                       int parc, const char *parv[]);
+
+struct Message clearchan_msgtab = {
+       "CLEARCHAN", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_clearchan, 2}}
+};
+
+mapi_clist_av1 clearchan_clist[] = { &clearchan_msgtab, NULL };
+
+DECLARE_MODULE_AV1(clearchan, NULL, NULL, clearchan_clist, NULL, NULL, "$Revision: 1425 $");
+
+/*
+** mo_clearchan
+**      parv[0] = sender prefix
+**      parv[1] = channel
+*/
+static int
+mo_clearchan(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Channel *chptr;
+       struct membership *msptr;
+       struct Client *target_p;
+       dlink_node *ptr;
+       dlink_node *next_ptr;
+
+       /* admins only */
+       if(!IsOperAdmin(source_p))
+       {
+               sendto_one(source_p, ":%s NOTICE %s :You have no A flag", me.name, parv[0]);
+               return 0;
+       }
+
+
+       if((chptr = find_channel(parv[1])) == NULL)
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
+                                  form_str(ERR_NOSUCHCHANNEL), parv[1]);
+               return 0;
+       }
+
+       if(IsMember(source_p, chptr))
+       {
+               sendto_one(source_p, ":%s NOTICE %s :*** Please part %s before using CLEARCHAN",
+                          me.name, source_p->name, parv[1]);
+               return 0;
+       }
+
+       /* quickly make everyone a peon.. */
+       DLINK_FOREACH(ptr, chptr->members.head)
+       {
+               msptr = ptr->data;
+               msptr->flags &= ~CHFL_CHANOP | CHFL_VOICE;
+       }
+
+       sendto_wallops_flags(UMODE_WALLOP, &me,
+                            "CLEARCHAN called for [%s] by %s!%s@%s",
+                            parv[1], source_p->name, source_p->username, source_p->host);
+       ilog(L_MAIN, "CLEARCHAN called for [%s] by %s!%s@%s",
+            parv[1], source_p->name, source_p->username, source_p->host);
+
+       if(*chptr->chname != '&')
+       {
+               sendto_server(NULL, NULL, NOCAPS, NOCAPS,
+                             ":%s WALLOPS :CLEARCHAN called for [%s] by %s!%s@%s",
+                             me.name, parv[1], source_p->name, source_p->username, source_p->host);
+
+               /* SJOIN the user to give them ops, and lock the channel */
+               sendto_server(client_p, chptr, NOCAPS, NOCAPS,
+                             ":%s SJOIN %ld %s +ntsi :@%s",
+                             me.name, (long) (chptr->channelts - 1),
+                             chptr->chname, source_p->name);
+       }
+
+       sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s",
+                            source_p->name, source_p->username, source_p->host, chptr->chname);
+       sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +o %s",
+                            me.name, chptr->chname, source_p->name);
+
+       add_user_to_channel(chptr, source_p, CHFL_CHANOP);
+
+       /* Take the TS down by 1, so we don't see the channel taken over
+        * again. */
+       if(chptr->channelts)
+               chptr->channelts--;
+
+       chptr->mode.mode = MODE_SECRET | MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS;
+       chptr->mode.key[0] = '\0';
+
+       DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->members.head)
+       {
+               msptr = ptr->data;
+               target_p = msptr->client_p;
+
+               /* skip the person we just added.. */
+               if(is_chanop(msptr))
+                       continue;
+
+               sendto_channel_local(ALL_MEMBERS, chptr,
+                                    ":%s KICK %s %s :CLEARCHAN",
+                                    source_p->name, chptr->chname, target_p->name);
+
+               if(*chptr->chname != '&')
+                       sendto_server(NULL, chptr, NOCAPS, NOCAPS,
+                                     ":%s KICK %s %s :CLEARCHAN",
+                                     source_p->name, chptr->chname, target_p->name);
+
+               remove_user_from_channel(msptr);
+       }
+
+       /* Join the user themselves to the channel down here, so they dont see a nicklist 
+        * or people being kicked */
+       sendto_one(source_p, ":%s!%s@%s JOIN %s",
+                  source_p->name, source_p->username, source_p->host, chptr->chname);
+
+       channel_member_names(chptr, source_p, 1);
+
+       return 0;
+}
diff --git a/unsupported/m_force.c b/unsupported/m_force.c
new file mode 100644 (file)
index 0000000..d531977
--- /dev/null
@@ -0,0 +1,299 @@
+/* contrib/m_force.c
+ * Copyright (C) 1996-2002 Hybrid Development Team
+ * Copyright (C) 2004 ircd-ratbox Development Team
+ *
+ *  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.The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: m_force.c 1425 2006-05-23 16:41:33Z jilles $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "channel.h"
+#include "class.h"
+#include "client.h"
+#include "common.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "hostmask.h"
+#include "numeric.h"
+#include "commio.h"
+#include "s_conf.h"
+#include "s_newconf.h"
+#include "s_log.h"
+#include "send.h"
+#include "hash.h"
+#include "s_serv.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include "event.h"
+
+
+static int mo_forcejoin(struct Client *client_p, struct Client *source_p,
+                       int parc, const char *parv[]);
+static int mo_forcepart(struct Client *client_p, struct Client *source_p,
+                       int parc, const char *parv[]);
+
+struct Message forcejoin_msgtab = {
+       "FORCEJOIN", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_forcejoin, 3}}
+};
+
+struct Message forcepart_msgtab = {
+       "FORCEPART", 0, 0, 0, MFLG_SLOW,
+       {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_forcepart, 3}}
+};
+
+mapi_clist_av1 force_clist[] = { &forcejoin_msgtab, &forcepart_msgtab, NULL };
+
+DECLARE_MODULE_AV1(force, NULL, NULL, force_clist, NULL, NULL, "$Revision: 1425 $");
+
+/*
+ * m_forcejoin
+ *      parv[0] = sender prefix
+ *      parv[1] = user to force
+ *      parv[2] = channel to force them into
+ */
+static int
+mo_forcejoin(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+       struct Channel *chptr;
+       int type;
+       char mode;
+       char sjmode;
+       char *newch;
+
+       if(!IsOperAdmin(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "forcejoin");
+               return 0;
+       }
+
+       if((hunt_server(client_p, source_p, ":%s FORCEJOIN %s %s", 1, parc, parv)) != HUNTED_ISME)
+               return 0;
+
+       /* if target_p is not existant, print message
+        * to source_p and bail - scuzzy
+        */
+       if((target_p = find_client(parv[1])) == NULL)
+       {
+               sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name, source_p->name, parv[1]);
+               return 0;
+       }
+
+       if(!IsPerson(target_p))
+               return 0;
+
+       sendto_wallops_flags(UMODE_WALLOP, &me,
+                            "FORCEJOIN called for %s %s by %s!%s@%s",
+                            parv[1], parv[2], source_p->name, source_p->username, source_p->host);
+       ilog(L_MAIN, "FORCEJOIN called for %s %s by %s!%s@%s",
+            parv[1], parv[2], source_p->name, source_p->username, source_p->host);
+       sendto_server(NULL, NULL, NOCAPS, NOCAPS,
+                       ":%s WALLOPS :FORCEJOIN called for %s %s by %s!%s@%s",
+                       me.name, parv[1], parv[2],
+                       source_p->name, source_p->username, source_p->host);
+
+       /* select our modes from parv[2] if they exist... (chanop) */
+       if(*parv[2] == '@')
+       {
+               type = CHFL_CHANOP;
+               mode = 'o';
+               sjmode = '@';
+       }
+       else if(*parv[2] == '+')
+       {
+               type = CHFL_VOICE;
+               mode = 'v';
+               sjmode = '+';
+       }
+       else
+       {
+               type = CHFL_PEON;
+               mode = sjmode = '\0';
+       }
+
+       if(mode != '\0')
+               parv[2]++;
+
+       if((chptr = find_channel(parv[2])) != NULL)
+       {
+               if(IsMember(target_p, chptr))
+               {
+                       /* debugging is fun... */
+                       sendto_one(source_p, ":%s NOTICE %s :*** Notice -- %s is already in %s",
+                                  me.name, source_p->name, target_p->name, chptr->chname);
+                       return 0;
+               }
+
+               add_user_to_channel(chptr, target_p, type);
+
+               sendto_server(target_p, chptr, NOCAPS, NOCAPS,
+                             ":%s SJOIN %ld %s + :%c%s",
+                             me.name, (long) chptr->channelts,
+                             chptr->chname, type ? sjmode : ' ', target_p->name);
+
+               sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s",
+                                    target_p->name, target_p->username,
+                                    target_p->host, chptr->chname);
+
+               if(type)
+                       sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +%c %s",
+                                            me.name, chptr->chname, mode, target_p->name);
+
+               if(chptr->topic != NULL)
+               {
+                       sendto_one(target_p, form_str(RPL_TOPIC), me.name,
+                                  target_p->name, chptr->chname, chptr->topic);
+                       sendto_one(target_p, form_str(RPL_TOPICWHOTIME),
+                                  me.name, source_p->name, chptr->chname,
+                                  chptr->topic_info, chptr->topic_time);
+               }
+
+               channel_member_names(chptr, target_p, 1);
+       }
+       else
+       {
+               newch = LOCAL_COPY(parv[2]);
+               if(!check_channel_name(newch))
+               {
+                       sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name,
+                                  source_p->name, (unsigned char *) newch);
+                       return 0;
+               }
+
+               /* channel name must begin with & or # */
+               if(!IsChannelName(newch))
+               {
+                       sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name,
+                                  source_p->name, (unsigned char *) newch);
+                       return 0;
+               }
+
+               /* newch can't be longer than CHANNELLEN */
+               if(strlen(newch) > CHANNELLEN)
+               {
+                       sendto_one(source_p, ":%s NOTICE %s :Channel name is too long", me.name,
+                                  source_p->name);
+                       return 0;
+               }
+
+               chptr = get_or_create_channel(target_p, newch, NULL);
+               add_user_to_channel(chptr, target_p, CHFL_CHANOP);
+
+               /* send out a join, make target_p join chptr */
+               sendto_server(target_p, chptr, NOCAPS, NOCAPS,
+                             ":%s SJOIN %ld %s +nt :@%s", me.name,
+                             (long) chptr->channelts, chptr->chname, target_p->name);
+
+               sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s",
+                                    target_p->name, target_p->username,
+                                    target_p->host, chptr->chname);
+
+               chptr->mode.mode |= MODE_TOPICLIMIT;
+               chptr->mode.mode |= MODE_NOPRIVMSGS;
+
+               sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +nt", me.name, chptr->chname);
+
+               target_p->localClient->last_join_time = CurrentTime;
+               channel_member_names(chptr, target_p, 1);
+
+               /* we do this to let the oper know that a channel was created, this will be
+                * seen from the server handling the command instead of the server that
+                * the oper is on.
+                */
+               sendto_one(source_p, ":%s NOTICE %s :*** Notice -- Creating channel %s", me.name,
+                          source_p->name, chptr->chname);
+       }
+       return 0;
+}
+
+
+static int
+mo_forcepart(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+       struct Client *target_p;
+       struct Channel *chptr;
+       struct membership *msptr;
+
+       if(!IsOperAdmin(source_p))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "forcepart");
+               return 0;
+       }
+
+       if((hunt_server(client_p, source_p, ":%s FORCEPART %s %s", 1, parc, parv)) != HUNTED_ISME)
+               return 0;
+
+       /* if target_p == NULL then let the oper know */
+       if((target_p = find_client(parv[1])) == NULL)
+       {
+               sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name, source_p->name, parv[1]);
+               return 0;
+       }
+
+       if(!IsClient(target_p))
+               return 0;
+
+       sendto_wallops_flags(UMODE_WALLOP, &me,
+                            "FORCEPART called for %s %s by %s!%s@%s",
+                            parv[1], parv[2], source_p->name, source_p->username, source_p->host);
+       ilog(L_MAIN, "FORCEPART called for %s %s by %s!%s@%s",
+            parv[1], parv[2], source_p->name, source_p->username, source_p->host);
+       sendto_server(NULL, NULL, NOCAPS, NOCAPS,
+                       ":%s WALLOPS :FORCEPART called for %s %s by %s!%s@%s",
+                       me.name, parv[1], parv[2],
+                       source_p->name, source_p->username, source_p->host);
+
+       if((chptr = find_channel(parv[2])) == NULL)
+       {
+               sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
+                                  form_str(ERR_NOSUCHCHANNEL), parv[1]);
+               return 0;
+       }
+
+       if((msptr = find_channel_membership(chptr, target_p)) == NULL)
+       {
+               sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,
+                               form_str(ERR_USERNOTINCHANNEL),
+                               parv[1], parv[2]);
+               return 0;
+       }
+
+       sendto_server(target_p, chptr, NOCAPS, NOCAPS,
+                     ":%s PART %s :%s", target_p->name, chptr->chname, target_p->name);
+
+       sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s :%s",
+                            target_p->name, target_p->username,
+                            target_p->host, chptr->chname, target_p->name);
+
+
+       remove_user_from_channel(msptr);
+
+       return 0;
+}