summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormichael <michael@82007160-df01-0410-b94d-b575c5fd34c7>2012-10-27 21:02:32 +0000
committermichael <michael@82007160-df01-0410-b94d-b575c5fd34c7>2012-10-27 21:02:32 +0000
commit70f1558a2eca8295e30bb1e381d948056333634d (patch)
tree3051cb6afbc7d5ebae4381e54c70d9cbe54005a4 /src
parent4f1edcf052857117fd51e878c362f878961c4dc9 (diff)
- Second time's the charm? Moving svnroot/ircd-hybrid-8 to
svnroot/ircd-hybrid/trunk git-svn-id: svn://svn.ircd-hybrid.org/svnroot/ircd-hybrid/trunk@1592 82007160-df01-0410-b94d-b575c5fd34c7
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am62
-rw-r--r--src/Makefile.in728
-rw-r--r--src/balloc.c503
-rw-r--r--src/channel.c864
-rw-r--r--src/channel_mode.c1797
-rw-r--r--src/client.c1205
-rw-r--r--src/conf.c3622
-rw-r--r--src/conf_lexer.c4278
-rw-r--r--src/conf_lexer.l489
-rw-r--r--src/conf_parser.c7071
-rw-r--r--src/conf_parser.h513
-rw-r--r--src/conf_parser.y3072
-rw-r--r--src/csvlib.c671
-rw-r--r--src/dbuf.c112
-rw-r--r--src/event.c292
-rw-r--r--src/fdlist.c243
-rw-r--r--src/getopt.c127
-rw-r--r--src/hash.c907
-rw-r--r--src/hook.c216
-rw-r--r--src/hostmask.c820
-rw-r--r--src/irc_res.c836
-rw-r--r--src/irc_reslib.c1168
-rw-r--r--src/irc_string.c263
-rw-r--r--src/ircd.c658
-rw-r--r--src/ircd_signal.c135
-rw-r--r--src/list.c277
-rw-r--r--src/listener.c429
-rw-r--r--src/log.c123
-rw-r--r--src/match.c616
-rw-r--r--src/memory.c114
-rw-r--r--src/messages.tab1029
-rw-r--r--src/modules.c401
-rw-r--r--src/motd.c283
-rw-r--r--src/numeric.c226
-rw-r--r--src/packet.c414
-rw-r--r--src/parse.c815
-rw-r--r--src/restart.c94
-rw-r--r--src/resv.c230
-rw-r--r--src/rng_mt.c167
-rw-r--r--src/rsa.c120
-rw-r--r--src/s_auth.c598
-rw-r--r--src/s_bsd.c757
-rw-r--r--src/s_bsd_devpoll.c186
-rw-r--r--src/s_bsd_epoll.c221
-rw-r--r--src/s_bsd_kqueue.c199
-rw-r--r--src/s_bsd_poll.c224
-rw-r--r--src/s_bsd_select.c204
-rw-r--r--src/s_bsd_sigio.c318
-rw-r--r--src/s_gline.c114
-rw-r--r--src/s_misc.c131
-rw-r--r--src/s_serv.c1503
-rw-r--r--src/s_user.c1484
-rw-r--r--src/send.c1111
-rw-r--r--src/sprintf_irc.c472
-rw-r--r--src/version.c105
-rw-r--r--src/watch.c235
-rw-r--r--src/whowas.c142
57 files changed, 43994 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..2f51356
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,62 @@
+AUTOMAKE_OPTIONS = foreign
+
+sbin_PROGRAMS = ircd
+
+AM_YFLAGS = -d
+
+AM_CPPFLAGS = $(LTDLINCL) -I$(top_srcdir)/include
+ircd_LDFLAGS = -export-dynamic
+ircd_LDADD = $(LIBLTDL)
+ircd_DEPENDENCIES = $(LTDLDEPS)
+
+ircd_SOURCES = balloc.c \
+ channel.c \
+ channel_mode.c \
+ client.c \
+ conf.c \
+ conf_parser.y \
+ conf_lexer.l \
+ csvlib.c \
+ dbuf.c \
+ event.c \
+ fdlist.c \
+ getopt.c \
+ hash.c \
+ hook.c \
+ hostmask.c \
+ irc_res.c \
+ irc_reslib.c \
+ irc_string.c \
+ ircd.c \
+ ircd_signal.c \
+ list.c \
+ listener.c \
+ log.c \
+ match.c \
+ memory.c \
+ modules.c \
+ motd.c \
+ rng_mt.c \
+ numeric.c \
+ packet.c \
+ parse.c \
+ s_bsd_epoll.c \
+ s_bsd_poll.c \
+ s_bsd_sigio.c \
+ s_bsd_devpoll.c \
+ s_bsd_kqueue.c \
+ s_bsd_select.c \
+ restart.c \
+ resv.c \
+ rsa.c \
+ s_auth.c \
+ s_bsd.c \
+ s_gline.c \
+ s_misc.c \
+ s_serv.c \
+ s_user.c \
+ send.c \
+ sprintf_irc.c \
+ version.c \
+ watch.c \
+ whowas.c
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..a8102c7
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,728 @@
+# Makefile.in generated by automake 1.12.4 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2012 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__make_dryrun = \
+ { \
+ am__dry=no; \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
+ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
+ *) \
+ for am__flg in $$MAKEFLAGS; do \
+ case $$am__flg in \
+ *=*|--*) ;; \
+ *n*) am__dry=yes; break;; \
+ esac; \
+ done;; \
+ esac; \
+ test $$am__dry = yes; \
+ }
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+sbin_PROGRAMS = ircd$(EXEEXT)
+subdir = src
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(top_srcdir)/depcomp $(top_srcdir)/ylwrap conf_lexer.c \
+ conf_parser.c conf_parser.h
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(sbindir)"
+PROGRAMS = $(sbin_PROGRAMS)
+am_ircd_OBJECTS = balloc.$(OBJEXT) channel.$(OBJEXT) \
+ channel_mode.$(OBJEXT) client.$(OBJEXT) conf.$(OBJEXT) \
+ conf_parser.$(OBJEXT) conf_lexer.$(OBJEXT) csvlib.$(OBJEXT) \
+ dbuf.$(OBJEXT) event.$(OBJEXT) fdlist.$(OBJEXT) \
+ getopt.$(OBJEXT) hash.$(OBJEXT) hook.$(OBJEXT) \
+ hostmask.$(OBJEXT) irc_res.$(OBJEXT) irc_reslib.$(OBJEXT) \
+ irc_string.$(OBJEXT) ircd.$(OBJEXT) ircd_signal.$(OBJEXT) \
+ list.$(OBJEXT) listener.$(OBJEXT) log.$(OBJEXT) \
+ match.$(OBJEXT) memory.$(OBJEXT) modules.$(OBJEXT) \
+ motd.$(OBJEXT) rng_mt.$(OBJEXT) numeric.$(OBJEXT) \
+ packet.$(OBJEXT) parse.$(OBJEXT) s_bsd_epoll.$(OBJEXT) \
+ s_bsd_poll.$(OBJEXT) s_bsd_sigio.$(OBJEXT) \
+ s_bsd_devpoll.$(OBJEXT) s_bsd_kqueue.$(OBJEXT) \
+ s_bsd_select.$(OBJEXT) restart.$(OBJEXT) resv.$(OBJEXT) \
+ rsa.$(OBJEXT) s_auth.$(OBJEXT) s_bsd.$(OBJEXT) \
+ s_gline.$(OBJEXT) s_misc.$(OBJEXT) s_serv.$(OBJEXT) \
+ s_user.$(OBJEXT) send.$(OBJEXT) sprintf_irc.$(OBJEXT) \
+ version.$(OBJEXT) watch.$(OBJEXT) whowas.$(OBJEXT)
+ircd_OBJECTS = $(am_ircd_OBJECTS)
+am__DEPENDENCIES_1 =
+ircd_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(ircd_LDFLAGS) \
+ $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@MAINTAINER_MODE_FALSE@am__skiplex = test -f $@ ||
+LEXCOMPILE = $(LEX) $(AM_LFLAGS) $(LFLAGS)
+LTLEXCOMPILE = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(LEX) $(AM_LFLAGS) $(LFLAGS)
+YLWRAP = $(top_srcdir)/ylwrap
+@MAINTAINER_MODE_FALSE@am__skipyacc = test -f $@ ||
+am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \
+ -e s/c++$$/h++/ -e s/c$$/h/
+YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS)
+LTYACCCOMPILE = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(YACC) $(AM_YFLAGS) $(YFLAGS)
+SOURCES = $(ircd_SOURCES)
+DIST_SOURCES = $(ircd_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+ARGZ_H = @ARGZ_H@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIR = @DATADIR@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INCLTDL = @INCLTDL@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBADD_DL = @LIBADD_DL@
+LIBADD_DLD_LINK = @LIBADD_DLD_LINK@
+LIBADD_DLOPEN = @LIBADD_DLOPEN@
+LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@
+LIBDIR = @LIBDIR@
+LIBLTDL = @LIBLTDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALSTATEDIR = @LOCALSTATEDIR@
+LTDLDEPS = @LTDLDEPS@
+LTDLINCL = @LTDLINCL@
+LTDLOPEN = @LTDLOPEN@
+LTLIBOBJS = @LTLIBOBJS@
+LT_CONFIG_H = @LT_CONFIG_H@
+LT_DLLOADERS = @LT_DLLOADERS@
+LT_DLPREOPEN = @LT_DLPREOPEN@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PREFIX = @PREFIX@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+SYSCONFDIR = @SYSCONFDIR@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+ltdl_LIBOBJS = @ltdl_LIBOBJS@
+ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sys_symbol_underscore = @sys_symbol_underscore@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AUTOMAKE_OPTIONS = foreign
+AM_YFLAGS = -d
+AM_CPPFLAGS = $(LTDLINCL) -I$(top_srcdir)/include
+ircd_LDFLAGS = -export-dynamic
+ircd_LDADD = $(LIBLTDL)
+ircd_DEPENDENCIES = $(LTDLDEPS)
+ircd_SOURCES = balloc.c \
+ channel.c \
+ channel_mode.c \
+ client.c \
+ conf.c \
+ conf_parser.y \
+ conf_lexer.l \
+ csvlib.c \
+ dbuf.c \
+ event.c \
+ fdlist.c \
+ getopt.c \
+ hash.c \
+ hook.c \
+ hostmask.c \
+ irc_res.c \
+ irc_reslib.c \
+ irc_string.c \
+ ircd.c \
+ ircd_signal.c \
+ list.c \
+ listener.c \
+ log.c \
+ match.c \
+ memory.c \
+ modules.c \
+ motd.c \
+ rng_mt.c \
+ numeric.c \
+ packet.c \
+ parse.c \
+ s_bsd_epoll.c \
+ s_bsd_poll.c \
+ s_bsd_sigio.c \
+ s_bsd_devpoll.c \
+ s_bsd_kqueue.c \
+ s_bsd_select.c \
+ restart.c \
+ resv.c \
+ rsa.c \
+ s_auth.c \
+ s_bsd.c \
+ s_gline.c \
+ s_misc.c \
+ s_serv.c \
+ s_user.c \
+ send.c \
+ sprintf_irc.c \
+ version.c \
+ watch.c \
+ whowas.c
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .l .lo .o .obj .y
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p || test -f $$p1; \
+ then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-sbinPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(sbindir)" && rm -f $$files
+
+clean-sbinPROGRAMS:
+ @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+conf_parser.h: conf_parser.c
+ @if test ! -f $@; then rm -f conf_parser.c; else :; fi
+ @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) conf_parser.c; else :; fi
+ircd$(EXEEXT): $(ircd_OBJECTS) $(ircd_DEPENDENCIES) $(EXTRA_ircd_DEPENDENCIES)
+ @rm -f ircd$(EXEEXT)
+ $(ircd_LINK) $(ircd_OBJECTS) $(ircd_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/balloc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/channel.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/channel_mode.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf_lexer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf_parser.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/csvlib.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbuf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdlist.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hook.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hostmask.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irc_res.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irc_reslib.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irc_string.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ircd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ircd_signal.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/listener.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/match.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memory.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/modules.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/motd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/numeric.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/restart.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resv.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rng_mt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rsa.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_auth.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_bsd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_bsd_devpoll.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_bsd_epoll.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_bsd_kqueue.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_bsd_poll.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_bsd_select.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_bsd_sigio.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_gline.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_misc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_serv.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_user.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/send.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sprintf_irc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/watch.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/whowas.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+.l.c:
+ $(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $@ -- $(LEXCOMPILE)
+
+.y.c:
+ $(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h `echo $@ | $(am__yacc_c2h)` y.output $*.output -- $(YACCCOMPILE)
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+cscopelist: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+ for dir in "$(DESTDIR)$(sbindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -rm -f conf_lexer.c
+ -rm -f conf_parser.c
+ -rm -f conf_parser.h
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-sbinPROGRAMS \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-sbinPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-sbinPROGRAMS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-sbinPROGRAMS cscopelist ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-sbinPROGRAMS install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-sbinPROGRAMS
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/balloc.c b/src/balloc.c
new file mode 100644
index 0000000..c2c0733
--- /dev/null
+++ b/src/balloc.c
@@ -0,0 +1,503 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ *
+ * Copyright (C) 2002 by the past and present ircd coders, and others.
+ * Original credit lines follow:
+ *
+ * File: balloc.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
+ */
+
+/*! \file balloc.c
+ * \brief A block allocator
+ * \version $Id$
+ *
+ * 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.\n
+ * 2. mmap() via the /dev/zero trick.\n
+ * 3. malloc()\n
+ *
+ * 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.
+ */
+
+
+#include "stdinc.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 /* MAP_ANONYMOUS */
+#endif
+
+#include "list.h"
+#include "balloc.h"
+#include "memory.h"
+#include "irc_string.h"
+#include "client.h"
+#include "send.h"
+#include "numeric.h"
+#include "fdlist.h"
+#include "event.h"
+
+
+static BlockHeap *heap_list = NULL;
+
+static int BlockHeapGarbageCollect(BlockHeap *);
+static void heap_garbage_collection(void *);
+
+/*! \brief Returns memory for the block back to either the malloc heap
+ * in case of !HAVE_MMAP, or back to the OS otherwise.
+ * \param ptr Pointer to memory to be freed
+ * \param size The size of the memory space
+ */
+static void
+free_block(void *ptr, size_t size)
+{
+#ifdef HAVE_MMAP
+ munmap(ptr, size);
+#else
+ free(ptr);
+#endif
+}
+
+#ifdef HAVE_MMAP
+#ifndef MAP_ANON /* But we cannot mmap() anonymous pages */
+ /* So we mmap() /dev/zero, which is just as good */
+static fde_t dpfd;
+#endif
+#endif
+
+/*! \brief Opens /dev/zero and saves the file handle for
+ * future allocations.
+ */
+void
+initBlockHeap(void)
+{
+#ifdef HAVE_MMAP
+#ifndef MAP_ANON
+ int zero_fd = open("/dev/zero", O_RDWR);
+
+ if (zero_fd < 0)
+ outofmemory();
+ fd_open(&dpfd, zero_fd, 0, "Anonymous mmap()");
+#endif
+ eventAdd("heap_garbage_collection", &heap_garbage_collection, NULL, 119);
+#endif
+}
+
+/*!
+ * \param size Size of block to allocate
+ * \return Address pointer to allocated data space
+ */
+static void *
+get_block(size_t size)
+{
+#ifdef HAVE_MMAP
+ void *ptr = NULL;
+
+#ifndef MAP_ANON
+ ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, dpfd.fd, 0);
+#else
+ ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+#endif
+ return ptr == MAP_FAILED ? NULL : ptr;
+#else
+ return malloc(size);
+#endif
+}
+
+static void
+heap_garbage_collection(void *arg)
+{
+ BlockHeap *bh;
+
+ for (bh = heap_list; bh != NULL; bh = bh->next)
+ BlockHeapGarbageCollect(bh);
+}
+
+/*! \brief Allocates a new block for addition to a blockheap
+ * \param bh Pointer to parent blockheap
+ * \return 0 if successful, 1 if not
+ */
+static int
+newblock(BlockHeap *bh)
+{
+ MemBlock *newblk = NULL;
+ Block *b = NULL;
+ int i = 0;
+ void *offset = NULL;
+
+ /* Setup the initial data structure. */
+ if ((b = calloc(1, sizeof(Block))) == NULL)
+ return 1;
+
+ b->freeElems = bh->elemsPerBlock;
+ b->next = bh->base;
+ b->alloc_size = bh->elemsPerBlock * (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 < bh->elemsPerBlock; ++i)
+ {
+ void *data;
+
+ newblk = offset;
+ newblk->block = b;
+ data = (void *)((size_t)offset + sizeof(MemBlock));
+
+ dlinkAdd(data, &newblk->self, &b->free_list);
+ offset = (void *)((size_t)offset + bh->elemSize + sizeof(MemBlock));
+ }
+
+ ++bh->blocksAllocated;
+ bh->freeElems += bh->elemsPerBlock;
+ bh->base = b;
+
+ return 0;
+}
+
+/*! \brief Creates a new blockheap
+ *
+ * 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.
+ *
+ * \param name Name of the blockheap
+ * \param elemsize Size of the basic element to be stored
+ * \param elemsperblock 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.
+ * \return Pointer to new BlockHeap, or NULL if unsuccessful
+ */
+BlockHeap *
+BlockHeapCreate(const char *const name, size_t elemsize, int elemsperblock)
+{
+ BlockHeap *bh = NULL;
+ assert(elemsize > 0 && elemsperblock > 0);
+
+ /* Catch idiotic requests up front */
+ if ((elemsize <= 0) || (elemsperblock <= 0))
+ outofmemory(); /* die.. out of memory */
+
+ /* Allocate our new BlockHeap */
+ if ((bh = calloc(1, sizeof(BlockHeap))) == NULL)
+ outofmemory(); /* die.. out of memory */
+
+ if ((elemsize % sizeof(void *)) != 0)
+ {
+ /* Pad to even pointer boundary */
+ elemsize += sizeof(void *);
+ elemsize &= ~(sizeof(void *) - 1);
+ }
+
+ bh->name = name;
+ bh->elemSize = elemsize;
+ bh->elemsPerBlock = elemsperblock;
+
+ /* Be sure our malloc was successful */
+ if (newblock(bh))
+ {
+ if (bh != NULL)
+ free(bh);
+
+ outofmemory(); /* die.. out of memory */
+ }
+
+ bh->next = heap_list;
+ heap_list = bh;
+
+ return bh;
+}
+
+/*! \brief Returns a pointer to a struct within our BlockHeap that's free for
+ * the taking.
+ * \param bh Pointer to the Blockheap
+ * \return Address pointer to allocated data space, or NULL if unsuccessful
+ */
+void *
+BlockHeapAlloc(BlockHeap *bh)
+{
+ Block *walker = NULL;
+ dlink_node *new_node = NULL;
+
+ assert(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 (newblock(bh))
+ outofmemory(); /* Well that didn't work either...bail */
+ }
+ }
+
+ for (walker = bh->base; walker != NULL; walker = walker->next)
+ {
+ if (walker->freeElems > 0)
+ {
+ --bh->freeElems;
+ --walker->freeElems;
+ new_node = walker->free_list.head;
+
+ dlinkDelete(new_node, &walker->free_list);
+ assert(new_node->data != NULL);
+
+ memset(new_node->data, 0, bh->elemSize);
+ return new_node->data;
+ }
+ }
+
+ assert(0 == 1);
+ outofmemory();
+ return NULL;
+}
+
+/*! \brief Returns an element to the free pool, does not free()
+ * \param bh Pointer to BlockHeap containing element
+ * \param ptr Pointer to element to be "freed"
+ * \return 0 if successful, 1 if element not contained within BlockHeap
+ */
+int
+BlockHeapFree(BlockHeap *bh, void *ptr)
+{
+ Block *block = NULL;
+ struct MemBlock *memblock = NULL;
+
+ assert(bh != NULL);
+ assert(ptr != NULL);
+
+ memblock = (void *)((size_t)ptr - sizeof(MemBlock));
+ assert(memblock->block != NULL);
+
+ if (memblock->block == NULL)
+ outofmemory();
+
+ block = memblock->block;
+ ++bh->freeElems;
+ ++block->freeElems;
+ mem_frob(ptr, bh->elemSize);
+
+ dlinkAdd(ptr, &memblock->self, &block->free_list);
+ return 0;
+}
+
+/*! \brief Performs garbage collection on the block heap.
+ *
+ * Performs garbage collection on the block heap. Any blocks that are
+ * completely unallocated are removed from the heap. Garbage collection
+ * will \b never remove the root node of the heap.
+ *
+ * \param bh Pointer to the BlockHeap to be cleaned up
+ * \return 0 if successful, 1 if bh == NULL
+ */
+static int
+BlockHeapGarbageCollect(BlockHeap *bh)
+{
+ Block *walker = NULL, *last = NULL;
+
+ assert(bh != NULL);
+
+ if (bh->freeElems < bh->elemsPerBlock || bh->blocksAllocated == 1)
+ {
+ /* There couldn't possibly be an entire free block. Return. */
+ return 0;
+ }
+
+ walker = bh->base;
+
+ while (walker != NULL)
+ {
+ if (walker->freeElems == bh->elemsPerBlock)
+ {
+ 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;
+}
+
+/*! \brief Completely free()s a BlockHeap. Use for cleanup.
+ * \param bh Pointer to the BlockHeap to be destroyed
+ * \return 0 if successful, 1 if bh == NULL
+ */
+int
+BlockHeapDestroy(BlockHeap *bh)
+{
+ Block *walker = NULL, *next = NULL;
+
+ 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);
+ }
+
+ if (heap_list == bh)
+ heap_list = bh->next;
+ else {
+ BlockHeap *prev;
+
+ for (prev = heap_list; prev->next != bh; prev = prev->next)
+ /* nothing */ ;
+ prev->next = bh->next;
+ }
+
+ free(bh);
+ return 0;
+}
+
+/*! \brief Returns the number of bytes being used
+ * \param bh Pointer to a BlockHeap
+ * \return Number of bytes being used
+ */
+static size_t
+block_heap_get_used_mem(const BlockHeap *const bh)
+{
+ return(((bh->blocksAllocated *
+ bh->elemsPerBlock)-bh->freeElems) *
+ (bh->elemSize + sizeof(MemBlock)));
+}
+
+/*! \brief Returns the number of bytes being free for further allocations
+ * \param bh Pointer to a BlockHeap
+ * \return Number of bytes being free for further allocations
+ */
+static size_t
+block_heap_get_free_mem(const BlockHeap *const bh)
+{
+ return(bh->freeElems * (bh->elemSize + sizeof(MemBlock)));
+}
+
+/*! \brief Returns the total number of bytes of memory belonging to a heap
+ * \param bh Pointer to a BlockHeap
+ * \return Total number of bytes of memory belonging to a heap
+ */
+static size_t
+block_heap_get_size_mem(const BlockHeap *const bh)
+{
+ return(((bh->blocksAllocated *
+ bh->elemsPerBlock)) *
+ (bh->elemSize + sizeof(MemBlock)));
+}
+
+/*! \brief Returns the number of elements being used.
+ * \param bh Pointer to a BlockHeap
+ * \return Number of elements being free for further allocations
+ */
+static unsigned int
+block_heap_get_used_elm(const BlockHeap *const bh)
+{
+ return((bh->blocksAllocated *
+ bh->elemsPerBlock)-bh->freeElems);
+}
+
+/*! \brief Returns the number of elements being free for further allocations.
+ * \param bh Pointer to a BlockHeap
+ * \return Number of elements being free for further allocations
+ */
+static unsigned int
+block_heap_get_free_elm(const BlockHeap *const bh)
+{
+ return(bh->freeElems);
+}
+
+/*! \brief Returns the number of total elements belonging to a heap.
+ * Includes \b free and \b used elements.
+ * \param bh Pointer to a BlockHeap
+ * \return Number of total elements belonging to a heap
+ */
+static unsigned int
+block_heap_get_size_elm(const BlockHeap *const bh)
+{
+ return(bh->blocksAllocated * bh->elemsPerBlock);
+}
+
+void
+block_heap_report_stats(struct Client *client_p)
+{
+ const BlockHeap *bh = NULL;
+
+ for (bh = heap_list; bh != NULL; bh = bh->next)
+ sendto_one(client_p, ":%s %d %s z :%s mempool: used %u/%u free %u/%u (size %u/%u)",
+ me.name, RPL_STATSDEBUG, client_p->name, bh->name,
+ block_heap_get_used_elm(bh),
+ block_heap_get_used_mem(bh),
+ block_heap_get_free_elm(bh),
+ block_heap_get_free_mem(bh),
+ block_heap_get_size_elm(bh),
+ block_heap_get_size_mem(bh));
+}
diff --git a/src/channel.c b/src/channel.c
new file mode 100644
index 0000000..14e6a14
--- /dev/null
+++ b/src/channel.c
@@ -0,0 +1,864 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ *
+ * 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
+ */
+
+/*! \file channel.c
+ * \brief Responsible for managing channels, members, bans and topics
+ * \version $Id$
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "channel.h"
+#include "channel_mode.h"
+#include "client.h"
+#include "hash.h"
+#include "hostmask.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 "conf.h" /* ConfigFileEntry, ConfigChannel */
+#include "event.h"
+#include "memory.h"
+#include "balloc.h"
+
+struct config_channel_entry ConfigChannel;
+dlink_list global_channel_list = { NULL, NULL, 0 };
+BlockHeap *ban_heap; /*! \todo ban_heap shouldn't be a global var */
+
+static BlockHeap *member_heap = NULL;
+static BlockHeap *channel_heap = NULL;
+
+static char buf[IRCD_BUFSIZE];
+static char modebuf[MODEBUFLEN];
+static char parabuf[MODEBUFLEN];
+
+
+/*! \brief Initializes the channel blockheap, adds known channel CAPAB
+ */
+void
+init_channels(void)
+{
+ add_capability("EX", CAP_EX, 1);
+ add_capability("IE", CAP_IE, 1);
+ add_capability("CHW", CAP_CHW, 1);
+
+ channel_heap = BlockHeapCreate("channel", sizeof(struct Channel), CHANNEL_HEAP_SIZE);
+ ban_heap = BlockHeapCreate("ban", sizeof(struct Ban), BAN_HEAP_SIZE);
+ member_heap = BlockHeapCreate("member", sizeof(struct Membership), CHANNEL_HEAP_SIZE*2);
+}
+
+/*! \brief adds a user to a channel by adding another link to the
+ * channels member chain.
+ * \param chptr pointer to channel to add client to
+ * \param who pointer to client (who) to add
+ * \param flags flags for chanops etc
+ * \param flood_ctrl whether to count this join in flood calculations
+ */
+void
+add_user_to_channel(struct Channel *chptr, struct Client *who,
+ unsigned int flags, int flood_ctrl)
+{
+ struct Membership *ms = NULL;
+
+ if (GlobalSetOptions.joinfloodtime > 0)
+ {
+ if (flood_ctrl)
+ chptr->number_joined++;
+
+ chptr->number_joined -= (CurrentTime - chptr->last_join_time) *
+ (((float)GlobalSetOptions.joinfloodcount) /
+ (float)GlobalSetOptions.joinfloodtime);
+
+ if (chptr->number_joined <= 0)
+ {
+ chptr->number_joined = 0;
+ ClearJoinFloodNoticed(chptr);
+ }
+ else if (chptr->number_joined >= GlobalSetOptions.joinfloodcount)
+ {
+ chptr->number_joined = GlobalSetOptions.joinfloodcount;
+
+ if (!IsSetJoinFloodNoticed(chptr))
+ {
+ SetJoinFloodNoticed(chptr);
+ sendto_realops_flags(UMODE_BOTS, L_ALL,
+ "Possible Join Flooder %s on %s target: %s",
+ get_client_name(who, HIDE_IP),
+ who->servptr->name, chptr->chname);
+ }
+ }
+
+ chptr->last_join_time = CurrentTime;
+ }
+
+ ms = BlockHeapAlloc(member_heap);
+ ms->client_p = who;
+ ms->chptr = chptr;
+ ms->flags = flags;
+
+ dlinkAdd(ms, &ms->channode, &chptr->members);
+ dlinkAdd(ms, &ms->usernode, &who->channel);
+}
+
+/*! \brief deletes an user from a channel by removing a link in the
+ * channels member chain.
+ * \param member pointer to Membership struct
+ */
+void
+remove_user_from_channel(struct Membership *member)
+{
+ struct Client *client_p = member->client_p;
+ struct Channel *chptr = member->chptr;
+
+ dlinkDelete(&member->channode, &chptr->members);
+ dlinkDelete(&member->usernode, &client_p->channel);
+
+ BlockHeapFree(member_heap, member);
+
+ if (chptr->members.head == NULL)
+ destroy_channel(chptr);
+}
+
+/* send_members()
+ *
+ * inputs -
+ * output - NONE
+ * side effects -
+ */
+static void
+send_members(struct Client *client_p, struct Channel *chptr,
+ char *lmodebuf, char *lparabuf)
+{
+ struct Membership *ms;
+ dlink_node *ptr;
+ int tlen; /* length of text to append */
+ char *t, *start; /* temp char pointer */
+
+ start = t = buf + ircsprintf(buf, ":%s SJOIN %lu %s %s %s:",
+ ID_or_name(&me, client_p),
+ (unsigned long)chptr->channelts,
+ chptr->chname, lmodebuf, lparabuf);
+
+ DLINK_FOREACH(ptr, chptr->members.head)
+ {
+ ms = ptr->data;
+
+ tlen = strlen(IsCapable(client_p, CAP_TS6) ?
+ ID(ms->client_p) : ms->client_p->name) + 1; /* nick + space */
+
+ if (ms->flags & CHFL_CHANOP)
+ tlen++;
+#ifdef HALFOPS
+ else if (ms->flags & CHFL_HALFOP)
+ tlen++;
+#endif
+ if (ms->flags & CHFL_VOICE)
+ tlen++;
+
+ /* space will be converted into CR, but we also need space for LF..
+ * That's why we use '- 1' here
+ * -adx */
+ if (t + tlen - buf > IRCD_BUFSIZE - 1)
+ {
+ *(t - 1) = '\0'; /* kill the space and terminate the string */
+ sendto_one(client_p, "%s", buf);
+ t = start;
+ }
+
+ if ((ms->flags & (CHFL_CHANOP | CHFL_HALFOP)))
+ *t++ = (!(ms->flags & CHFL_CHANOP) && IsCapable(client_p, CAP_HOPS)) ?
+ '%' : '@';
+ if ((ms->flags & CHFL_VOICE))
+ *t++ = '+';
+
+ if (IsCapable(client_p, CAP_TS6))
+ strcpy(t, ID(ms->client_p));
+ else
+ strcpy(t, ms->client_p->name);
+ t += strlen(t);
+ *t++ = ' ';
+ }
+
+ /* should always be non-NULL unless we have a kind of persistent channels */
+ if (chptr->members.head != NULL)
+ t--; /* take the space out */
+ *t = '\0';
+ sendto_one(client_p, "%s", buf);
+}
+
+/*! \brief sends +b/+e/+I
+ * \param client_p client pointer to server
+ * \param chptr pointer to channel
+ * \param top pointer to top of mode link list to send
+ * \param flag char flag flagging type of mode. Currently this can be 'b', e' or 'I'
+ */
+static void
+send_mode_list(struct Client *client_p, struct Channel *chptr,
+ dlink_list *top, char flag)
+{
+ int ts5 = !IsCapable(client_p, CAP_TS6);
+ dlink_node *lp;
+ struct Ban *banptr;
+ char pbuf[IRCD_BUFSIZE];
+ int tlen, mlen, cur_len, count = 0;
+ char *mp = NULL, *pp = pbuf;
+
+ if (top == NULL || top->length == 0)
+ return;
+
+ if (ts5)
+ mlen = ircsprintf(buf, ":%s MODE %s +", me.name, chptr->chname);
+ else
+ mlen = ircsprintf(buf, ":%s BMASK %lu %s %c :", me.id,
+ (unsigned long)chptr->channelts, chptr->chname, flag);
+
+ /* MODE needs additional one byte for space between buf and pbuf */
+ cur_len = mlen + ts5;
+ mp = buf + mlen;
+
+ DLINK_FOREACH(lp, top->head)
+ {
+ banptr = lp->data;
+
+ /* must add another b/e/I letter if we use MODE */
+ tlen = banptr->len + 3 + ts5;
+
+ /*
+ * send buffer and start over if we cannot fit another ban,
+ * or if the target is non-ts6 and we have too many modes in
+ * in this line.
+ */
+ if (cur_len + (tlen - 1) > IRCD_BUFSIZE - 2 ||
+ (!IsCapable(client_p, CAP_TS6) &&
+ (count >= MAXMODEPARAMS || pp - pbuf >= MODEBUFLEN)))
+ {
+ *(pp - 1) = '\0'; /* get rid of trailing space on buffer */
+ sendto_one(client_p, "%s%s%s", buf, ts5 ? " " : "", pbuf);
+
+ cur_len = mlen + ts5;
+ mp = buf + mlen;
+ pp = pbuf;
+ count = 0;
+ }
+
+ count++;
+ if (ts5)
+ {
+ *mp++ = flag;
+ *mp = '\0';
+ }
+
+ pp += ircsprintf(pp, "%s!%s@%s ", banptr->name, banptr->username,
+ banptr->host);
+ cur_len += tlen;
+ }
+
+ *(pp - 1) = '\0'; /* get rid of trailing space on buffer */
+ sendto_one(client_p, "%s%s%s", buf, ts5 ? " " : "", pbuf);
+}
+
+/*! \brief send "client_p" a full list of the modes for channel chptr
+ * \param client_p pointer to client client_p
+ * \param chptr pointer to channel pointer
+ */
+void
+send_channel_modes(struct Client *client_p, struct Channel *chptr)
+{
+ *modebuf = *parabuf = '\0';
+ channel_modes(chptr, client_p, modebuf, parabuf);
+ send_members(client_p, chptr, modebuf, parabuf);
+
+ send_mode_list(client_p, chptr, &chptr->banlist, 'b');
+
+ if (IsCapable(client_p, CAP_EX))
+ send_mode_list(client_p, chptr, &chptr->exceptlist, 'e');
+ if (IsCapable(client_p, CAP_IE))
+ send_mode_list(client_p, chptr, &chptr->invexlist, 'I');
+}
+
+/*! \brief check channel name for invalid characters
+ * \param name pointer to channel name string
+ * \param local indicates whether it's a local or remote creation
+ * \return 0 if invalid, 1 otherwise
+ */
+int
+check_channel_name(const char *name, int local)
+{
+ const char *p = name;
+ const int max_length = local ? LOCAL_CHANNELLEN : CHANNELLEN;
+ assert(name != NULL);
+
+ if (!IsChanPrefix(*p))
+ return 0;
+
+ if (!local || !ConfigChannel.disable_fake_channels)
+ {
+ while (*++p)
+ if (!IsChanChar(*p))
+ return 0;
+ }
+ else
+ {
+ while (*++p)
+ if (!IsVisibleChanChar(*p))
+ return 0;
+ }
+
+ return p - name <= max_length;
+}
+
+void
+remove_ban(struct Ban *bptr, dlink_list *list)
+{
+ dlinkDelete(&bptr->node, list);
+
+ MyFree(bptr->name);
+ MyFree(bptr->username);
+ MyFree(bptr->host);
+ MyFree(bptr->who);
+
+ BlockHeapFree(ban_heap, bptr);
+}
+
+/* free_channel_list()
+ *
+ * inputs - pointer to dlink_list
+ * output - NONE
+ * side effects -
+ */
+void
+free_channel_list(dlink_list *list)
+{
+ dlink_node *ptr = NULL, *next_ptr = NULL;
+
+ DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
+ remove_ban(ptr->data, list);
+
+ assert(list->tail == NULL && list->head == NULL);
+}
+
+/*! \brief Get Channel block for chname (and allocate a new channel
+ * block, if it didn't exist before)
+ * \param chname channel name
+ * \return channel block
+ */
+struct Channel *
+make_channel(const char *chname)
+{
+ struct Channel *chptr = NULL;
+
+ assert(!EmptyString(chname));
+
+ chptr = BlockHeapAlloc(channel_heap);
+
+ /* doesn't hurt to set it here */
+ chptr->channelts = CurrentTime;
+ chptr->last_join_time = CurrentTime;
+
+ strlcpy(chptr->chname, chname, sizeof(chptr->chname));
+ dlinkAdd(chptr, &chptr->node, &global_channel_list);
+
+ hash_add_channel(chptr);
+
+ return chptr;
+}
+
+/*! \brief walk through this channel, and destroy it.
+ * \param chptr channel pointer
+ */
+void
+destroy_channel(struct Channel *chptr)
+{
+ dlink_node *ptr = NULL, *ptr_next = NULL;
+
+ DLINK_FOREACH_SAFE(ptr, ptr_next, chptr->invites.head)
+ del_invite(chptr, ptr->data);
+
+ /* free ban/exception/invex lists */
+ free_channel_list(&chptr->banlist);
+ free_channel_list(&chptr->exceptlist);
+ free_channel_list(&chptr->invexlist);
+
+ dlinkDelete(&chptr->node, &global_channel_list);
+ hash_del_channel(chptr);
+
+ BlockHeapFree(channel_heap, chptr);
+}
+
+/*!
+ * \param chptr pointer to channel
+ * \return string pointer "=" if public, "@" if secret else "*"
+ */
+static const char *
+channel_pub_or_secret(const struct Channel *chptr)
+{
+ if (SecretChannel(chptr))
+ return "@";
+ if (PrivateChannel(chptr))
+ return "*";
+ return "=";
+}
+
+/*! \brief lists all names on given channel
+ * \param source_p pointer to client struct requesting names
+ * \param chptr pointer to channel block
+ * \param show_eon show ENDOFNAMES numeric or not
+ * (don't want it with /names with no params)
+ */
+void
+channel_member_names(struct Client *source_p, struct Channel *chptr,
+ int show_eon)
+{
+ struct Client *target_p = NULL;
+ struct Membership *ms = NULL;
+ dlink_node *ptr = NULL;
+ char lbuf[IRCD_BUFSIZE + 1];
+ char *t = NULL, *start = NULL;
+ int tlen = 0;
+ int is_member = IsMember(source_p, chptr);
+ int multi_prefix = HasCap(source_p, CAP_MULTI_PREFIX) != 0;
+
+ if (PubChannel(chptr) || is_member)
+ {
+ t = lbuf + ircsprintf(lbuf, form_str(RPL_NAMREPLY),
+ me.name, source_p->name,
+ channel_pub_or_secret(chptr),
+ chptr->chname);
+ start = t;
+
+ DLINK_FOREACH(ptr, chptr->members.head)
+ {
+ ms = ptr->data;
+ target_p = ms->client_p;
+
+ if (HasUMode(target_p, UMODE_INVISIBLE) && !is_member)
+ continue;
+
+ tlen = strlen(target_p->name) + 1; /* nick + space */
+
+ if (!multi_prefix)
+ {
+ if (ms->flags & (CHFL_CHANOP | CHFL_HALFOP | CHFL_VOICE))
+ ++tlen;
+ }
+ else
+ {
+ if (ms->flags & CHFL_CHANOP)
+ ++tlen;
+ if (ms->flags & CHFL_HALFOP)
+ ++tlen;
+ if (ms->flags & CHFL_VOICE)
+ ++tlen;
+ }
+
+ if (t + tlen - lbuf > IRCD_BUFSIZE - 2)
+ {
+ *(t - 1) = '\0';
+ sendto_one(source_p, "%s", lbuf);
+ t = start;
+ }
+
+ t += ircsprintf(t, "%s%s ", get_member_status(ms, multi_prefix),
+ target_p->name);
+ }
+
+ if (tlen != 0)
+ {
+ *(t - 1) = '\0';
+ sendto_one(source_p, "%s", lbuf);
+ }
+ }
+
+ if (show_eon)
+ sendto_one(source_p, form_str(RPL_ENDOFNAMES),
+ me.name, source_p->name, chptr->chname);
+}
+
+/*! \brief adds client to invite list
+ * \param chptr pointer to channel block
+ * \param who pointer to client to add invite to
+ */
+void
+add_invite(struct Channel *chptr, struct Client *who)
+{
+ del_invite(chptr, who);
+
+ /*
+ * delete last link in chain if the list is max length
+ */
+ if (dlink_list_length(&who->localClient->invited) >=
+ ConfigChannel.max_chans_per_user)
+ del_invite(who->localClient->invited.tail->data, who);
+
+ /* add client to channel invite list */
+ dlinkAdd(who, make_dlink_node(), &chptr->invites);
+
+ /* add channel to the end of the client invite list */
+ dlinkAdd(chptr, make_dlink_node(), &who->localClient->invited);
+}
+
+/*! \brief Delete Invite block from channel invite list
+ * and client invite list
+ * \param chptr pointer to Channel struct
+ * \param who pointer to client to remove invites from
+ */
+void
+del_invite(struct Channel *chptr, struct Client *who)
+{
+ dlink_node *ptr = NULL;
+
+ if ((ptr = dlinkFindDelete(&who->localClient->invited, chptr)))
+ free_dlink_node(ptr);
+
+ if ((ptr = dlinkFindDelete(&chptr->invites, who)))
+ free_dlink_node(ptr);
+}
+
+/* get_member_status()
+ *
+ * inputs - pointer to struct Membership
+ * - YES if we can combine different flags
+ * output - string either @, +, % or "" depending on whether
+ * chanop, voiced or user
+ * side effects -
+ *
+ * NOTE: Returned string is usually a static buffer
+ * (like in get_client_name)
+ */
+const char *
+get_member_status(const struct Membership *ms, int combine)
+{
+ static char buffer[4];
+ char *p = NULL;
+
+ if (ms == NULL)
+ return "";
+ p = buffer;
+
+ if (ms->flags & CHFL_CHANOP)
+ {
+ if (!combine)
+ return "@";
+ *p++ = '@';
+ }
+
+#ifdef HALFOPS
+ if (ms->flags & CHFL_HALFOP)
+ {
+ if (!combine)
+ return "%";
+ *p++ = '%';
+ }
+#endif
+
+ if (ms->flags & CHFL_VOICE)
+ *p++ = '+';
+ *p = '\0';
+
+ return buffer;
+}
+
+/*!
+ * \param who pointer to Client to check
+ * \param list pointer to ban list to search
+ * \return 1 if ban found for given n!u\@h mask, 0 otherwise
+ *
+ */
+static int
+find_bmask(const struct Client *who, const dlink_list *const list)
+{
+ const dlink_node *ptr = NULL;
+
+ DLINK_FOREACH(ptr, list->head)
+ {
+ const struct Ban *bp = ptr->data;
+
+ if (match(bp->name, who->name) && match(bp->username, who->username))
+ {
+ switch (bp->type)
+ {
+ case HM_HOST:
+ if (match(bp->host, who->host) || match(bp->host, who->sockhost))
+ return 1;
+ break;
+ case HM_IPV4:
+ if (who->localClient->aftype == AF_INET)
+ if (match_ipv4(&who->localClient->ip, &bp->addr, bp->bits))
+ return 1;
+ break;
+#ifdef IPV6
+ case HM_IPV6:
+ if (who->localClient->aftype == AF_INET6)
+ if (match_ipv6(&who->localClient->ip, &bp->addr, bp->bits))
+ return 1;
+ break;
+#endif
+ default:
+ assert(0);
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*!
+ * \param chptr pointer to channel block
+ * \param who pointer to client to check access fo
+ * \return 0 if not banned, 1 otherwise
+ */
+int
+is_banned(const struct Channel *chptr, const struct Client *who)
+{
+ if (find_bmask(who, &chptr->banlist))
+ if (!find_bmask(who, &chptr->exceptlist))
+ return 1;
+
+ return 0;
+}
+
+/*!
+ * \param source_p pointer to client attempting to join
+ * \param chptr pointer to channel
+ * \param key key sent by client attempting to join if present
+ * \return ERR_BANNEDFROMCHAN, ERR_INVITEONLYCHAN, ERR_CHANNELISFULL
+ * or 0 if allowed to join.
+ */
+int
+can_join(struct Client *source_p, struct Channel *chptr, const char *key)
+{
+ if (is_banned(chptr, source_p))
+ return ERR_BANNEDFROMCHAN;
+
+#ifdef HAVE_LIBCRYPTO
+ if ((chptr->mode.mode & MODE_SSLONLY) && !source_p->localClient->fd.ssl)
+ return ERR_SSLONLYCHAN;
+#endif
+
+ if ((chptr->mode.mode & MODE_REGONLY) && !HasUMode(source_p, UMODE_REGISTERED))
+ return ERR_NEEDREGGEDNICK;
+
+ if ((chptr->mode.mode & MODE_OPERONLY) && !HasUMode(source_p, UMODE_OPER))
+ return ERR_OPERONLYCHAN;
+
+ if (chptr->mode.mode & MODE_INVITEONLY)
+ if (!dlinkFind(&source_p->localClient->invited, chptr))
+ if (!find_bmask(source_p, &chptr->invexlist))
+ return ERR_INVITEONLYCHAN;
+
+ if (chptr->mode.key[0] && (!key || strcmp(chptr->mode.key, key)))
+ return ERR_BADCHANNELKEY;
+
+ if (chptr->mode.limit && dlink_list_length(&chptr->members) >=
+ chptr->mode.limit)
+ return ERR_CHANNELISFULL;
+
+ return 0;
+}
+
+int
+has_member_flags(struct Membership *ms, unsigned int flags)
+{
+ if (ms != NULL)
+ return ms->flags & flags;
+ return 0;
+}
+
+struct Membership *
+find_channel_link(struct Client *client_p, struct Channel *chptr)
+{
+ dlink_node *ptr = NULL;
+
+ if (!IsClient(client_p))
+ return NULL;
+
+ DLINK_FOREACH(ptr, client_p->channel.head)
+ if (((struct Membership *)ptr->data)->chptr == chptr)
+ return ptr->data;
+
+ return NULL;
+}
+
+/*!
+ * \param chptr pointer to Channel struct
+ * \param source_p pointer to Client struct
+ * \param ms pointer to Membership struct (can be NULL)
+ * \return CAN_SEND_OPV if op or voiced on channel\n
+ * CAN_SEND_NONOP if can send to channel but is not an op\n
+ * ERR_CANNOTSENDTOCHAN or ERR_NEEDREGGEDNICK if they cannot send to channel\n
+ */
+int
+can_send(struct Channel *chptr, struct Client *source_p, struct Membership *ms)
+{
+ if (IsServer(source_p) || HasFlag(source_p, FLAGS_SERVICE))
+ return CAN_SEND_OPV;
+
+ if (MyClient(source_p) && !IsExemptResv(source_p))
+ if (!(HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.oper_pass_resv))
+ if (!hash_find_resv(chptr->chname) == ConfigChannel.restrict_channels)
+ return ERR_CANNOTSENDTOCHAN;
+
+ if (ms != NULL || (ms = find_channel_link(source_p, chptr)))
+ {
+ if (ms->flags & (CHFL_CHANOP|CHFL_HALFOP|CHFL_VOICE))
+ return CAN_SEND_OPV;
+
+ /* cache can send if quiet_on_ban and banned */
+ if (ConfigChannel.quiet_on_ban && MyClient(source_p))
+ {
+ if (ms->flags & CHFL_BAN_SILENCED)
+ return ERR_CANNOTSENDTOCHAN;
+
+ if (!(ms->flags & CHFL_BAN_CHECKED))
+ {
+ if (is_banned(chptr, source_p))
+ {
+ ms->flags |= (CHFL_BAN_CHECKED|CHFL_BAN_SILENCED);
+ return ERR_CANNOTSENDTOCHAN;
+ }
+
+ ms->flags |= CHFL_BAN_CHECKED;
+ }
+ }
+ }
+ else if (chptr->mode.mode & MODE_NOPRIVMSGS)
+ return ERR_CANNOTSENDTOCHAN;
+
+ if (chptr->mode.mode & MODE_MODERATED)
+ return ERR_CANNOTSENDTOCHAN;
+
+ return CAN_SEND_NONOP;
+}
+
+/*! \brief Updates the client's oper_warn_count_down, warns the
+ * IRC operators if necessary, and updates
+ * join_leave_countdown as needed.
+ * \param source_p pointer to struct Client to check
+ * \param name channel name or NULL if this is a part.
+ */
+void
+check_spambot_warning(struct Client *source_p, const char *name)
+{
+ int t_delta = 0;
+ int decrement_count = 0;
+
+ 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_flags(UMODE_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_flags(UMODE_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;
+ }
+}
+
+/*! \brief compares usercount and servercount against their split
+ * values and adjusts splitmode accordingly
+ * \param unused Unused address pointer
+ */
+void
+check_splitmode(void *unused)
+{
+ if (splitchecking && (ConfigChannel.no_join_on_split ||
+ ConfigChannel.no_create_on_split))
+ {
+ const unsigned int server = dlink_list_length(&global_serv_list);
+
+ if (!splitmode && ((server < split_servers) || (Count.total < split_users)))
+ {
+ splitmode = 1;
+
+ sendto_realops_flags(UMODE_ALL,L_ALL,
+ "Network split, activating splitmode");
+ eventAddIsh("check_splitmode", check_splitmode, NULL, 10);
+ }
+ else if (splitmode && (server > split_servers) && (Count.total > split_users))
+ {
+ splitmode = 0;
+
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Network rejoined, deactivating splitmode");
+ eventDelete(check_splitmode, NULL);
+ }
+ }
+}
+
+/*! \brief Sets the channel topic for chptr
+ * \param chptr Pointer to struct Channel
+ * \param topic The topic string
+ * \param topic_info n!u\@h formatted string of the topic setter
+ * \param topicts timestamp on the topic
+ */
+void
+set_channel_topic(struct Channel *chptr, const char *topic,
+ const char *topic_info, time_t topicts)
+{
+ strlcpy(chptr->topic, topic, sizeof(chptr->topic));
+ strlcpy(chptr->topic_info, topic_info, sizeof(chptr->topic_info));
+ chptr->topic_time = topicts;
+}
diff --git a/src/channel_mode.c b/src/channel_mode.c
new file mode 100644
index 0000000..4751ec4
--- /dev/null
+++ b/src/channel_mode.c
@@ -0,0 +1,1797 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * channel_mode.c: Controls modes on channels.
+ *
+ * Copyright (C) 2005 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$
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "channel.h"
+#include "channel_mode.h"
+#include "client.h"
+#include "hash.h"
+#include "hostmask.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 "conf.h" /* ConfigFileEntry, ConfigChannel */
+#include "event.h"
+#include "memory.h"
+#include "balloc.h"
+#include "log.h"
+#include "parse.h"
+
+/* some small utility functions */
+static char *check_string(char *);
+static char *fix_key(char *);
+static char *fix_key_old(char *);
+static void chm_nosuch(struct Client *, struct Client *,
+ struct Channel *, int, int *, char **, int *, int,
+ int, char, void *, const char *);
+static void chm_simple(struct Client *, struct Client *, struct Channel *,
+ int, int *, char **, int *, int, int, char, void *,
+ const char *);
+static void chm_registered(struct Client *, struct Client *, struct Channel *,
+ int, int *, char **, int *, int, int, char, void *,
+ const char *);
+static void chm_limit(struct Client *, struct Client *, struct Channel *,
+ int, int *, char **, int *, int, int, char, void *,
+ const char *);
+static void chm_key(struct Client *, struct Client *, struct Channel *,
+ int, int *, char **, int *, int, int, char, void *,
+ const char *);
+static void chm_op(struct Client *, struct Client *, struct Channel *, int,
+ int *, char **, int *, int, int, char, void *,
+ const char *);
+#ifdef HALFOPS
+static void chm_hop(struct Client *, struct Client *, struct Channel *, int,
+ int *, char **, int *, int, int, char, void *,
+ const char *);
+#endif
+static void chm_voice(struct Client *, struct Client *, struct Channel *,
+ int, int *, char **, int *, int, int, char, void *,
+ const char *);
+static void chm_ban(struct Client *, struct Client *, struct Channel *, int,
+ int *, char **, int *, int, int, char, void *,
+ const char *);
+static void chm_except(struct Client *, struct Client *, struct Channel *,
+ int, int *, char **, int *, int, int, char, void *,
+ const char *);
+static void chm_invex(struct Client *, struct Client *, struct Channel *,
+ int, int *, char **, int *, int, int, char, void *,
+ const char *);
+static void send_cap_mode_changes(struct Client *, struct Client *,
+ struct Channel *, unsigned int, unsigned int);
+static void send_mode_changes(struct Client *, struct Client *,
+ struct Channel *, char *);
+
+/* 10 is a magic number in hybrid 6 NFI where it comes from -db */
+#define BAN_FUDGE 10
+#define NCHCAPS (sizeof(channel_capabs)/sizeof(int))
+#define NCHCAP_COMBOS (1 << NCHCAPS)
+
+static char nuh_mask[MAXPARA][IRCD_BUFSIZE];
+/* some buffers for rebuilding channel/nick lists with ,'s */
+static char modebuf[IRCD_BUFSIZE];
+static char parabuf[MODEBUFLEN];
+static struct ChModeChange mode_changes[IRCD_BUFSIZE];
+static int mode_count;
+static int mode_limit; /* number of modes set other than simple */
+static int simple_modes_mask; /* bit mask of simple modes already set */
+#ifdef HALFOPS
+static int channel_capabs[] = { CAP_EX, CAP_IE, CAP_TS6, CAP_HOPS };
+#else
+static int channel_capabs[] = { CAP_EX, CAP_IE, CAP_TS6 };
+#endif
+static struct ChCapCombo chcap_combos[NCHCAP_COMBOS];
+extern BlockHeap *ban_heap;
+
+
+/* XXX check_string is propably not longer required in add_id and del_id */
+/* check_string()
+ *
+ * inputs - string to check
+ * output - pointer to modified string
+ * side effects - Fixes a string so that the first white space found
+ * becomes an end of string marker (`\0`).
+ * returns the 'fixed' string or "*" if the string
+ * was NULL length or a NULL pointer.
+ */
+static char *
+check_string(char *s)
+{
+ char *str = s;
+ static char star[] = "*";
+
+ if (EmptyString(s))
+ return star;
+
+ for (; *s; ++s)
+ {
+ if (IsSpace(*s))
+ {
+ *s = '\0';
+ break;
+ }
+ }
+
+ return str;
+}
+
+/*
+ * Ban functions to work with mode +b/e/d/I
+ */
+/* add the specified ID to the channel..
+ * -is 8/9/00
+ */
+
+int
+add_id(struct Client *client_p, struct Channel *chptr, char *banid, int type)
+{
+ dlink_list *list = NULL;
+ dlink_node *ban = NULL;
+ size_t len = 0;
+ struct Ban *ban_p = NULL;
+ unsigned int num_mask;
+ char name[NICKLEN + 1];
+ char user[USERLEN + 1];
+ char host[HOSTLEN + 1];
+ struct split_nuh_item nuh;
+
+ /* dont let local clients overflow the b/e/I lists */
+ if (MyClient(client_p))
+ {
+ num_mask = dlink_list_length(&chptr->banlist) +
+ dlink_list_length(&chptr->exceptlist) +
+ dlink_list_length(&chptr->invexlist);
+
+ if (num_mask >= ConfigChannel.max_bans)
+ {
+ sendto_one(client_p, form_str(ERR_BANLISTFULL),
+ me.name, client_p->name, chptr->chname, banid);
+ return 0;
+ }
+
+ collapse(banid);
+ }
+
+ nuh.nuhmask = check_string(banid);
+ nuh.nickptr = name;
+ nuh.userptr = user;
+ nuh.hostptr = host;
+
+ nuh.nicksize = sizeof(name);
+ nuh.usersize = sizeof(user);
+ nuh.hostsize = sizeof(host);
+
+ split_nuh(&nuh);
+
+ /*
+ * Re-assemble a new n!u@h and print it back to banid for sending
+ * the mode to the channel.
+ */
+ len = ircsprintf(banid, "%s!%s@%s", name, user, host);
+
+ switch (type)
+ {
+ case CHFL_BAN:
+ list = &chptr->banlist;
+ clear_ban_cache(chptr);
+ break;
+ case CHFL_EXCEPTION:
+ list = &chptr->exceptlist;
+ clear_ban_cache(chptr);
+ break;
+ case CHFL_INVEX:
+ list = &chptr->invexlist;
+ break;
+ default:
+ assert(0);
+ return 0;
+ }
+
+ DLINK_FOREACH(ban, list->head)
+ {
+ ban_p = ban->data;
+ if (!irccmp(ban_p->name, name) &&
+ !irccmp(ban_p->username, user) &&
+ !irccmp(ban_p->host, host))
+ {
+ return 0;
+ }
+ }
+
+ ban_p = BlockHeapAlloc(ban_heap);
+
+ DupString(ban_p->name, name);
+ DupString(ban_p->username, user);
+ DupString(ban_p->host, host);
+
+ ban_p->when = CurrentTime;
+ ban_p->len = len - 2; /* -2 for @ and ! */
+ ban_p->type = parse_netmask(host, &ban_p->addr, &ban_p->bits);
+
+ if (IsClient(client_p))
+ {
+ ban_p->who = MyMalloc(strlen(client_p->name) +
+ strlen(client_p->username) +
+ strlen(client_p->host) + 3);
+ ircsprintf(ban_p->who, "%s!%s@%s", client_p->name,
+ client_p->username, client_p->host);
+ }
+ else
+ DupString(ban_p->who, client_p->name);
+
+ dlinkAdd(ban_p, &ban_p->node, list);
+
+ return 1;
+}
+
+/*
+ * inputs - pointer to channel
+ * - pointer to ban id
+ * - type of ban, i.e. ban, exception, invex
+ * output - 0 for failure, 1 for success
+ * side effects -
+ */
+static int
+del_id(struct Channel *chptr, char *banid, int type)
+{
+ dlink_list *list;
+ dlink_node *ban;
+ struct Ban *banptr;
+ char name[NICKLEN + 1];
+ char user[USERLEN + 1];
+ char host[HOSTLEN + 1];
+ struct split_nuh_item nuh;
+
+ if (banid == NULL)
+ return 0;
+
+ nuh.nuhmask = check_string(banid);
+ nuh.nickptr = name;
+ nuh.userptr = user;
+ nuh.hostptr = host;
+
+ nuh.nicksize = sizeof(name);
+ nuh.usersize = sizeof(user);
+ nuh.hostsize = sizeof(host);
+
+ split_nuh(&nuh);
+
+ /*
+ * Re-assemble a new n!u@h and print it back to banid for sending
+ * the mode to the channel.
+ */
+ ircsprintf(banid, "%s!%s@%s", name, user, host);
+
+ switch (type)
+ {
+ case CHFL_BAN:
+ list = &chptr->banlist;
+ clear_ban_cache(chptr);
+ break;
+ case CHFL_EXCEPTION:
+ list = &chptr->exceptlist;
+ clear_ban_cache(chptr);
+ break;
+ case CHFL_INVEX:
+ list = &chptr->invexlist;
+ break;
+ default:
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "del_id() called with unknown ban type %d!", type);
+ return 0;
+ }
+
+ DLINK_FOREACH(ban, list->head)
+ {
+ banptr = ban->data;
+
+ if (!irccmp(name, banptr->name) &&
+ !irccmp(user, banptr->username) &&
+ !irccmp(host, banptr->host))
+ {
+ remove_ban(banptr, list);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+const struct mode_letter chan_modes[] = {
+ { MODE_INVITEONLY, 'i' },
+ { MODE_MODERATED, 'm' },
+ { MODE_NOPRIVMSGS, 'n' },
+ { MODE_PRIVATE, 'p' },
+ { MODE_REGISTERED, 'r' },
+ { MODE_SECRET, 's' },
+ { MODE_TOPICLIMIT, 't' },
+ { MODE_OPERONLY, 'O' },
+ { MODE_REGONLY, 'R' },
+ { MODE_SSLONLY, 'S' },
+ { 0, '\0' }
+};
+
+/* channel_modes()
+ *
+ * inputs - pointer to channel
+ * - pointer to client
+ * - pointer to mode buf
+ * - pointer to parameter buf
+ * output - NONE
+ * side effects - write the "simple" list of channel modes for channel
+ * chptr onto buffer mbuf with the parameters in pbuf.
+ */
+void
+channel_modes(struct Channel *chptr, struct Client *client_p,
+ char *mbuf, char *pbuf)
+{
+ const struct mode_letter *tab = chan_modes;
+
+ *mbuf++ = '+';
+ *pbuf = '\0';
+
+ for (; tab->mode; ++tab)
+ if (chptr->mode.mode & tab->mode)
+ *mbuf++ = tab->letter;
+
+ if (chptr->mode.limit)
+ {
+ *mbuf++ = 'l';
+
+ if (IsServer(client_p) || HasFlag(client_p, FLAGS_SERVICE) || IsMember(client_p, chptr))
+ pbuf += ircsprintf(pbuf, "%d ", chptr->mode.limit);
+ }
+
+ if (chptr->mode.key[0])
+ {
+ *mbuf++ = 'k';
+
+ if (IsServer(client_p) || HasFlag(client_p, FLAGS_SERVICE) || IsMember(client_p, chptr))
+ ircsprintf(pbuf, "%s ", chptr->mode.key);
+ }
+
+ *mbuf = '\0';
+}
+
+/* fix_key()
+ *
+ * inputs - pointer to key to clean up
+ * output - pointer to cleaned up key
+ * side effects - input string is modified
+ *
+ * stolen from Undernet's ircd -orabidoo
+ */
+static char *
+fix_key(char *arg)
+{
+ unsigned char *s, *t, c;
+
+ for (s = t = (unsigned char *)arg; (c = *s); s++)
+ {
+ c &= 0x7f;
+ if (c != ':' && c > ' ' && c != ',')
+ *t++ = c;
+ }
+
+ *t = '\0';
+ return(arg);
+}
+
+/* fix_key_old()
+ *
+ * inputs - pointer to key to clean up
+ * output - pointer to cleaned up key
+ * side effects - input string is modifed
+ *
+ * Here we attempt to be compatible with older non-hybrid servers.
+ * We can't back down from the ':' issue however. --Rodder
+ */
+static char *
+fix_key_old(char *arg)
+{
+ unsigned char *s, *t, c;
+
+ for (s = t = (unsigned char *)arg; (c = *s); s++)
+ {
+ c &= 0x7f;
+ if ((c != 0x0a) && (c != ':') && (c != 0x0d) && (c != ','))
+ *t++ = c;
+ }
+
+ *t = '\0';
+ return(arg);
+}
+
+/* bitmasks for various error returns that set_channel_mode should only return
+ * once per call -orabidoo
+ */
+
+#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_B 0x00000008
+#define SM_ERR_RPL_E 0x00000010
+#define SM_ERR_NOTONCHANNEL 0x00000020 /* Not on channel */
+#define SM_ERR_RPL_I 0x00000040
+#define SM_ERR_NOTOPER 0x00000080
+#define SM_ERR_ONLYSERVER 0x00000100
+
+/* 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 (((serv_p->localClient->caps & chcap_combos[n].cap_yes) ==
+ chcap_combos[n].cap_yes) &&
+ ((serv_p->localClient->caps & chcap_combos[n].cap_no) == 0))
+ {
+ chcap_combos[n].count++;
+ return;
+ }
+ }
+
+ /* This should be impossible -A1kmm. */
+ 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 ((serv_p->localClient->caps & chcap_combos[n].cap_yes) ==
+ chcap_combos[n].cap_yes &&
+ (serv_p->localClient->caps & chcap_combos[n].cap_no) == 0)
+ {
+ /* Hopefully capabs can't change dynamically or anything... */
+ assert(chcap_combos[n].count > 0);
+ chcap_combos[n].count--;
+ return;
+ }
+ }
+
+ /* This should be impossible -A1kmm. */
+ assert(0);
+}
+
+/* Mode functions handle mode changes for a particular mode... */
+static void
+chm_nosuch(struct Client *client_p, struct Client *source_p,
+ struct Channel *chptr, int parc, int *parn,
+ char **parv, int *errors, int alev, int dir, char c, void *d,
+ const char *chname)
+{
+ if (*errors & SM_ERR_UNKNOWN)
+ return;
+
+ *errors |= SM_ERR_UNKNOWN;
+ sendto_one(source_p, form_str(ERR_UNKNOWNMODE), me.name,
+ source_p->name, c);
+}
+
+static void
+chm_simple(struct Client *client_p, struct Client *source_p, struct Channel *chptr,
+ int parc, int *parn, char **parv, int *errors, int alev, int dir,
+ char c, void *d, const char *chname)
+{
+ long mode_type;
+
+ mode_type = (long)d;
+
+ if ((alev < CHACCESS_HALFOP) ||
+ ((mode_type == MODE_PRIVATE) && (alev < CHACCESS_CHANOP)))
+ {
+ if (!(*errors & SM_ERR_NOOPS))
+ sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
+ ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
+ me.name, source_p->name, chname);
+ *errors |= SM_ERR_NOOPS;
+ return;
+ }
+
+ /* If have already dealt with this simple mode, ignore it */
+ if (simple_modes_mask & mode_type)
+ return;
+
+ simple_modes_mask |= mode_type;
+
+ /* setting + */
+ /* Apparently, (though no one has ever told the hybrid group directly)
+ * admins don't like redundant mode checking. ok. It would have been nice
+ * if you had have told us directly. I've left the original code snippets
+ * in place.
+ *
+ * -Dianora
+ */
+ 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)) */
+ {
+ /* setting - */
+
+ 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;
+ }
+}
+
+static void
+chm_registered(struct Client *client_p, struct Client *source_p, struct Channel *chptr,
+ int parc, int *parn, char **parv, int *errors, int alev, int dir,
+ char c, void *d, const char *chname)
+{
+ long mode_type;
+
+ mode_type = (long)d;
+
+
+ if (!IsServer(source_p) && !HasFlag(source_p, FLAGS_SERVICE))
+ {
+ if (!(*errors & SM_ERR_ONLYSERVER))
+ sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
+ ERR_NOTONCHANNEL : ERR_ONLYSERVERSCANCHANGE),
+ me.name, source_p->name, chname);
+ *errors |= SM_ERR_ONLYSERVER;
+ return;
+ }
+
+ /* If have already dealt with this simple mode, ignore it */
+ if (simple_modes_mask & mode_type)
+ return;
+
+ simple_modes_mask |= mode_type;
+
+ /* setting + */
+ /* Apparently, (though no one has ever told the hybrid group directly)
+ * admins don't like redundant mode checking. ok. It would have been nice
+ * if you had have told us directly. I've left the original code snippets
+ * in place.
+ *
+ * -Dianora
+ */
+ 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)) */
+ {
+ /* setting - */
+
+ 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;
+ }
+}
+
+static void
+chm_operonly(struct Client *client_p, struct Client *source_p, struct Channel *chptr,
+ int parc, int *parn, char **parv, int *errors, int alev, int dir,
+ char c, void *d, const char *chname)
+{
+ long mode_type;
+
+ mode_type = (long)d;
+
+ if ((alev < CHACCESS_HALFOP) ||
+ ((mode_type == MODE_PRIVATE) && (alev < CHACCESS_CHANOP)))
+ {
+ if (!(*errors & SM_ERR_NOOPS))
+ sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
+ ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
+ me.name, source_p->name, chname);
+ *errors |= SM_ERR_NOOPS;
+ return;
+ }
+ else if (MyClient(source_p) && !HasUMode(source_p, UMODE_OPER))
+ {
+ if (!(*errors & SM_ERR_NOTOPER))
+ {
+ if (alev == CHACCESS_NOTONCHAN)
+ sendto_one(source_p, form_str(ERR_NOTONCHANNEL),
+ me.name, source_p->name, chname);
+ else
+ sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
+ me.name, source_p->name);
+ }
+
+ *errors |= SM_ERR_NOTOPER;
+ return;
+ }
+
+ /* If have already dealt with this simple mode, ignore it */
+ if (simple_modes_mask & mode_type)
+ return;
+
+ simple_modes_mask |= mode_type;
+
+ 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].mems = ALL_MEMBERS;
+ mode_changes[mode_count++].arg = NULL;
+ }
+ else if ((dir == MODE_DEL)) /* && (chptr->mode.mode & mode_type)) */
+ {
+ /* setting - */
+
+ 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;
+ }
+}
+
+static void
+chm_ban(struct Client *client_p, struct Client *source_p,
+ struct Channel *chptr, int parc, int *parn,
+ char **parv, int *errors, int alev, int dir, char c, void *d,
+ const char *chname)
+{
+ char *mask = NULL;
+
+ if (dir == MODE_QUERY || parc <= *parn)
+ {
+ dlink_node *ptr = NULL;
+
+ if (*errors & SM_ERR_RPL_B)
+ return;
+
+ *errors |= SM_ERR_RPL_B;
+
+ DLINK_FOREACH(ptr, chptr->banlist.head)
+ {
+ const struct Ban *banptr = ptr->data;
+ sendto_one(client_p, form_str(RPL_BANLIST),
+ me.name, client_p->name, chname,
+ banptr->name, banptr->username, banptr->host,
+ banptr->who, banptr->when);
+ }
+
+ sendto_one(source_p, form_str(RPL_ENDOFBANLIST), me.name,
+ source_p->name, chname);
+ return;
+ }
+
+ if (alev < CHACCESS_HALFOP)
+ {
+ if (!(*errors & SM_ERR_NOOPS))
+ sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
+ ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
+ me.name, source_p->name, chname);
+ *errors |= SM_ERR_NOOPS;
+ return;
+ }
+
+ if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
+ return;
+
+ mask = nuh_mask[*parn];
+ memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
+ ++*parn;
+
+ if (IsServer(client_p))
+ if (strchr(mask, ' '))
+ return;
+
+ switch (dir)
+ {
+ case MODE_ADD:
+ if (!add_id(source_p, chptr, mask, CHFL_BAN))
+ return;
+ break;
+ case MODE_DEL:
+ if (!del_id(chptr, mask, CHFL_BAN))
+ return;
+ break;
+ default:
+ assert(0);
+ }
+
+ mode_changes[mode_count].letter = c;
+ mode_changes[mode_count].dir = dir;
+ 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 = mask;
+}
+
+static void
+chm_except(struct Client *client_p, struct Client *source_p,
+ struct Channel *chptr, int parc, int *parn,
+ char **parv, int *errors, int alev, int dir, char c, void *d,
+ const char *chname)
+{
+ char *mask = NULL;
+
+ if (alev < CHACCESS_HALFOP)
+ {
+ if (!(*errors & SM_ERR_NOOPS))
+ sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
+ ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
+ me.name, source_p->name, chname);
+ *errors |= SM_ERR_NOOPS;
+ return;
+ }
+
+ if (dir == MODE_QUERY || parc <= *parn)
+ {
+ dlink_node *ptr = NULL;
+
+ if (*errors & SM_ERR_RPL_E)
+ return;
+
+ *errors |= SM_ERR_RPL_E;
+
+ DLINK_FOREACH(ptr, chptr->exceptlist.head)
+ {
+ const struct Ban *banptr = ptr->data;
+ sendto_one(client_p, form_str(RPL_EXCEPTLIST),
+ me.name, client_p->name, chname,
+ banptr->name, banptr->username, banptr->host,
+ banptr->who, banptr->when);
+ }
+
+ sendto_one(source_p, form_str(RPL_ENDOFEXCEPTLIST), me.name,
+ source_p->name, chname);
+ return;
+ }
+
+ if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
+ return;
+
+ mask = nuh_mask[*parn];
+ memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
+ ++*parn;
+
+ if (IsServer(client_p))
+ if (strchr(mask, ' '))
+ return;
+
+ switch (dir)
+ {
+ case MODE_ADD:
+ if (!add_id(source_p, chptr, mask, CHFL_EXCEPTION))
+ return;
+ break;
+ case MODE_DEL:
+ if (!del_id(chptr, mask, CHFL_EXCEPTION))
+ return;
+ break;
+ default:
+ assert(0);
+ }
+
+ mode_changes[mode_count].letter = c;
+ mode_changes[mode_count].dir = dir;
+ mode_changes[mode_count].caps = CAP_EX;
+ mode_changes[mode_count].nocaps = 0;
+ mode_changes[mode_count].mems = ONLY_CHANOPS;
+ mode_changes[mode_count].id = NULL;
+ mode_changes[mode_count++].arg = mask;
+}
+
+static void
+chm_invex(struct Client *client_p, struct Client *source_p,
+ struct Channel *chptr, int parc, int *parn,
+ char **parv, int *errors, int alev, int dir, char c, void *d,
+ const char *chname)
+{
+ char *mask = NULL;
+
+ if (alev < CHACCESS_HALFOP)
+ {
+ if (!(*errors & SM_ERR_NOOPS))
+ sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
+ ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
+ me.name, source_p->name, chname);
+ *errors |= SM_ERR_NOOPS;
+ return;
+ }
+
+ if (dir == MODE_QUERY || parc <= *parn)
+ {
+ dlink_node *ptr = NULL;
+
+ if (*errors & SM_ERR_RPL_I)
+ return;
+
+ *errors |= SM_ERR_RPL_I;
+
+ DLINK_FOREACH(ptr, chptr->invexlist.head)
+ {
+ const struct Ban *banptr = ptr->data;
+ sendto_one(client_p, form_str(RPL_INVITELIST), me.name,
+ client_p->name, chname,
+ banptr->name, banptr->username, banptr->host,
+ banptr->who, banptr->when);
+ }
+
+ sendto_one(source_p, form_str(RPL_ENDOFINVITELIST), me.name,
+ source_p->name, chname);
+ return;
+ }
+
+ if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
+ return;
+
+ mask = nuh_mask[*parn];
+ memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
+ ++*parn;
+
+ if (IsServer(client_p))
+ if (strchr(mask, ' '))
+ return;
+
+ switch (dir)
+ {
+ case MODE_ADD:
+ if (!add_id(source_p, chptr, mask, CHFL_INVEX))
+ return;
+ break;
+ case MODE_DEL:
+ if (!del_id(chptr, mask, CHFL_INVEX))
+ return;
+ break;
+ default:
+ assert(0);
+ }
+
+ mode_changes[mode_count].letter = c;
+ mode_changes[mode_count].dir = dir;
+ mode_changes[mode_count].caps = CAP_IE;
+ mode_changes[mode_count].nocaps = 0;
+ mode_changes[mode_count].mems = ONLY_CHANOPS;
+ mode_changes[mode_count].id = NULL;
+ mode_changes[mode_count++].arg = mask;
+}
+
+/*
+ * inputs - pointer to channel
+ * output - none
+ * side effects - clear ban cache
+ */
+void
+clear_ban_cache(struct Channel *chptr)
+{
+ dlink_node *ptr = NULL;
+
+ DLINK_FOREACH(ptr, chptr->members.head)
+ {
+ struct Membership *ms = ptr->data;
+
+ if (MyConnect(ms->client_p))
+ ms->flags &= ~(CHFL_BAN_SILENCED|CHFL_BAN_CHECKED);
+ }
+}
+
+void
+clear_ban_cache_client(struct Client *client_p)
+{
+ dlink_node *ptr = NULL;
+
+ DLINK_FOREACH(ptr, client_p->channel.head)
+ {
+ struct Membership *ms = ptr->data;
+ ms->flags &= ~(CHFL_BAN_SILENCED|CHFL_BAN_CHECKED);
+ }
+}
+
+static void
+chm_op(struct Client *client_p, struct Client *source_p,
+ struct Channel *chptr, int parc, int *parn,
+ char **parv, int *errors, int alev, int dir, char c, void *d,
+ const char *chname)
+{
+ char *opnick;
+ struct Client *targ_p;
+ struct Membership *member;
+ int caps = 0;
+
+ if (alev < CHACCESS_CHANOP)
+ {
+ if (!(*errors & SM_ERR_NOOPS))
+ sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
+ ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
+ me.name, source_p->name, chname);
+ *errors |= SM_ERR_NOOPS;
+ return;
+ }
+
+ if ((dir == MODE_QUERY) || (parc <= *parn))
+ return;
+
+ opnick = parv[(*parn)++];
+
+ if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
+ return;
+ if (!IsClient(targ_p))
+ return;
+
+ if ((member = find_channel_link(targ_p, chptr)) == NULL)
+ {
+ if (!(*errors & SM_ERR_NOTONCHANNEL))
+ sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
+ me.name, source_p->name, opnick, chname);
+ *errors |= SM_ERR_NOTONCHANNEL;
+ return;
+ }
+
+ if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
+ return;
+
+ /* no redundant mode changes */
+ if (dir == MODE_ADD && has_member_flags(member, CHFL_CHANOP))
+ return;
+ if (dir == MODE_DEL && !has_member_flags(member, CHFL_CHANOP))
+ {
+#ifdef HALFOPS
+ if (has_member_flags(member, CHFL_HALFOP))
+ {
+ --*parn;
+ chm_hop(client_p, source_p, chptr, parc, parn, parv, errors, alev,
+ dir, c, d, chname);
+ }
+#endif
+ return;
+ }
+
+#ifdef HALFOPS
+ if (dir == MODE_ADD && has_member_flags(member, CHFL_HALFOP))
+ {
+ /* promoting from % to @ is visible only to CAP_HOPS servers */
+ mode_changes[mode_count].letter = 'h';
+ mode_changes[mode_count].dir = MODE_DEL;
+ mode_changes[mode_count].caps = caps = CAP_HOPS;
+ mode_changes[mode_count].nocaps = 0;
+ mode_changes[mode_count].mems = ALL_MEMBERS;
+ mode_changes[mode_count].id = NULL;
+ mode_changes[mode_count].arg = targ_p->name;
+ mode_changes[mode_count++].client = targ_p;
+ }
+#endif
+
+ mode_changes[mode_count].letter = 'o';
+ mode_changes[mode_count].dir = dir;
+ mode_changes[mode_count].caps = caps;
+ 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;
+
+ if (dir == MODE_ADD)
+ {
+ AddMemberFlag(member, CHFL_CHANOP);
+ DelMemberFlag(member, CHFL_DEOPPED | CHFL_HALFOP);
+ }
+ else
+ DelMemberFlag(member, CHFL_CHANOP);
+}
+
+#ifdef HALFOPS
+static void
+chm_hop(struct Client *client_p, struct Client *source_p,
+ struct Channel *chptr, int parc, int *parn,
+ char **parv, int *errors, int alev, int dir, char c, void *d,
+ const char *chname)
+{
+ char *opnick;
+ struct Client *targ_p;
+ struct Membership *member;
+
+ /* *sigh* - dont allow halfops to set +/-h, they could fully control a
+ * channel if there were no ops - it doesnt solve anything.. MODE_PRIVATE
+ * when used with MODE_SECRET is paranoid - cant use +p
+ *
+ * it needs to be optional per channel - but not via +p, that or remove
+ * paranoid.. -- fl_
+ *
+ * +p means paranoid, it is useless for anything else on modern IRC, as
+ * list isn't really usable. If you want to have a private channel these
+ * days, you set it +s. Halfops can no longer remove simple modes when
+ * +p is set (although they can set +p) so it is safe to use this to
+ * control whether they can (de)halfop...
+ */
+ if (alev <
+ ((chptr->mode.mode & MODE_PRIVATE) ? CHACCESS_CHANOP : CHACCESS_HALFOP))
+ {
+ if (!(*errors & SM_ERR_NOOPS))
+ sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
+ ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
+ me.name, source_p->name, chname);
+ *errors |= SM_ERR_NOOPS;
+ return;
+ }
+
+ if ((dir == MODE_QUERY) || (parc <= *parn))
+ return;
+
+ opnick = parv[(*parn)++];
+
+ if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
+ return;
+ if (!IsClient(targ_p))
+ return;
+
+ if ((member = find_channel_link(targ_p, chptr)) == NULL)
+ {
+ if (!(*errors & SM_ERR_NOTONCHANNEL))
+ sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
+ me.name, source_p->name, opnick, chname);
+ *errors |= SM_ERR_NOTONCHANNEL;
+ return;
+ }
+
+ if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
+ return;
+
+ /* no redundant mode changes */
+ if (dir == MODE_ADD && has_member_flags(member, CHFL_HALFOP | CHFL_CHANOP))
+ return;
+ if (dir == MODE_DEL && !has_member_flags(member, CHFL_HALFOP))
+ return;
+
+ mode_changes[mode_count].letter = 'h';
+ mode_changes[mode_count].dir = dir;
+ mode_changes[mode_count].caps = CAP_HOPS;
+ 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;
+
+ mode_changes[mode_count].letter = 'o';
+ mode_changes[mode_count].dir = dir;
+ mode_changes[mode_count].caps = 0;
+ mode_changes[mode_count].nocaps = CAP_HOPS;
+ mode_changes[mode_count].mems = ONLY_SERVERS;
+ mode_changes[mode_count].id = targ_p->id;
+ mode_changes[mode_count].arg = targ_p->name;
+ mode_changes[mode_count++].client = targ_p;
+
+ if (dir == MODE_ADD)
+ {
+ AddMemberFlag(member, CHFL_HALFOP);
+ DelMemberFlag(member, CHFL_DEOPPED);
+ }
+ else
+ DelMemberFlag(member, CHFL_HALFOP);
+}
+#endif
+
+static void
+chm_voice(struct Client *client_p, struct Client *source_p,
+ struct Channel *chptr, int parc, int *parn,
+ char **parv, int *errors, int alev, int dir, char c, void *d,
+ const char *chname)
+{
+ char *opnick;
+ struct Client *targ_p;
+ struct Membership *member;
+
+ if (alev < CHACCESS_HALFOP)
+ {
+ if (!(*errors & SM_ERR_NOOPS))
+ sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
+ ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
+ me.name, source_p->name, chname);
+ *errors |= SM_ERR_NOOPS;
+ return;
+ }
+
+ if ((dir == MODE_QUERY) || parc <= *parn)
+ return;
+
+ opnick = parv[(*parn)++];
+
+ if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
+ return;
+ if (!IsClient(targ_p))
+ return;
+
+ if ((member = find_channel_link(targ_p, chptr)) == NULL)
+ {
+ if (!(*errors & SM_ERR_NOTONCHANNEL))
+ sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
+ me.name, source_p->name, opnick, chname);
+ *errors |= SM_ERR_NOTONCHANNEL;
+ return;
+ }
+
+ if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
+ return;
+
+ /* no redundant mode changes */
+ if (dir == MODE_ADD && has_member_flags(member, CHFL_VOICE))
+ return;
+ if (dir == MODE_DEL && !has_member_flags(member, CHFL_VOICE))
+ return;
+
+ mode_changes[mode_count].letter = 'v';
+ mode_changes[mode_count].dir = dir;
+ 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;
+
+ if (dir == MODE_ADD)
+ AddMemberFlag(member, CHFL_VOICE);
+ else
+ DelMemberFlag(member, CHFL_VOICE);
+}
+
+static void
+chm_limit(struct Client *client_p, struct Client *source_p,
+ struct Channel *chptr, int parc, int *parn,
+ char **parv, int *errors, int alev, int dir, char c, void *d,
+ const char *chname)
+{
+ int i, limit;
+ char *lstr;
+
+ if (alev < CHACCESS_HALFOP)
+ {
+ if (!(*errors & SM_ERR_NOOPS))
+ sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
+ ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
+ me.name, source_p->name, chname);
+ *errors |= SM_ERR_NOOPS;
+ return;
+ }
+
+ if (dir == MODE_QUERY)
+ return;
+
+ if ((dir == MODE_ADD) && parc > *parn)
+ {
+ lstr = parv[(*parn)++];
+
+ if ((limit = atoi(lstr)) <= 0)
+ return;
+
+ ircsprintf(lstr, "%d", limit);
+
+ /* if somebody sets MODE #channel +ll 1 2, accept latter --fl */
+ for (i = 0; i < mode_count; i++)
+ {
+ if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
+ mode_changes[i].letter = 0;
+ }
+
+ 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 = lstr;
+
+ 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;
+ }
+}
+
+static void
+chm_key(struct Client *client_p, struct Client *source_p,
+ struct Channel *chptr, int parc, int *parn,
+ char **parv, int *errors, int alev, int dir, char c, void *d,
+ const char *chname)
+{
+ int i;
+ char *key;
+
+ if (alev < CHACCESS_HALFOP)
+ {
+ if (!(*errors & SM_ERR_NOOPS))
+ sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
+ ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
+ me.name, source_p->name, chname);
+ *errors |= SM_ERR_NOOPS;
+ return;
+ }
+
+ if (dir == MODE_QUERY)
+ return;
+
+ if ((dir == MODE_ADD) && parc > *parn)
+ {
+ key = parv[(*parn)++];
+
+ if (MyClient(source_p))
+ fix_key(key);
+ else
+ fix_key_old(key);
+
+ if (*key == '\0')
+ return;
+
+ assert(key[0] != ' ');
+ strlcpy(chptr->mode.key, key, sizeof(chptr->mode.key));
+
+ /* if somebody does MODE #channel +kk a b, accept latter --fl */
+ for (i = 0; i < mode_count; i++)
+ {
+ if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
+ mode_changes[i].letter = 0;
+ }
+
+ 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)
+ {
+ if (parc > *parn)
+ (*parn)++;
+
+ if (chptr->mode.key[0] == '\0')
+ return;
+
+ chptr->mode.key[0] = '\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 = "*";
+ }
+}
+
+struct ChannelMode
+{
+ void (*func) (struct Client *client_p, struct Client *source_p,
+ struct Channel *chptr, int parc, int *parn, char **parv,
+ int *errors, int alev, int dir, char c, void *d,
+ const char *chname);
+ void *d;
+};
+
+static struct ChannelMode ModeTable[255] =
+{
+ {chm_nosuch, NULL},
+ {chm_nosuch, NULL}, /* A */
+ {chm_nosuch, NULL}, /* B */
+ {chm_nosuch, NULL}, /* C */
+ {chm_nosuch, NULL}, /* D */
+ {chm_nosuch, NULL}, /* E */
+ {chm_nosuch, NULL}, /* F */
+ {chm_nosuch, NULL}, /* G */
+ {chm_nosuch, NULL}, /* H */
+ {chm_invex, NULL}, /* I */
+ {chm_nosuch, NULL}, /* J */
+ {chm_nosuch, NULL}, /* K */
+ {chm_nosuch, NULL}, /* L */
+ {chm_nosuch, NULL}, /* M */
+ {chm_nosuch, NULL}, /* N */
+ {chm_operonly, (void *) MODE_OPERONLY}, /* O */
+ {chm_nosuch, NULL}, /* P */
+ {chm_nosuch, NULL}, /* Q */
+ {chm_simple, (void *) MODE_REGONLY}, /* R */
+ {chm_simple, (void *) MODE_SSLONLY}, /* S */
+ {chm_nosuch, NULL}, /* T */
+ {chm_nosuch, NULL}, /* U */
+ {chm_nosuch, NULL}, /* V */
+ {chm_nosuch, NULL}, /* W */
+ {chm_nosuch, NULL}, /* X */
+ {chm_nosuch, NULL}, /* Y */
+ {chm_nosuch, NULL}, /* Z */
+ {chm_nosuch, NULL},
+ {chm_nosuch, NULL},
+ {chm_nosuch, NULL},
+ {chm_nosuch, NULL},
+ {chm_nosuch, NULL},
+ {chm_nosuch, NULL},
+ {chm_nosuch, NULL}, /* a */
+ {chm_ban, NULL}, /* b */
+ {chm_nosuch, NULL}, /* c */
+ {chm_nosuch, NULL}, /* d */
+ {chm_except, NULL}, /* e */
+ {chm_nosuch, NULL}, /* f */
+ {chm_nosuch, NULL}, /* g */
+#ifdef HALFOPS
+ {chm_hop, NULL}, /* h */
+#else
+ {chm_nosuch, NULL}, /* h */
+#endif
+ {chm_simple, (void *) MODE_INVITEONLY}, /* i */
+ {chm_nosuch, NULL}, /* j */
+ {chm_key, NULL}, /* k */
+ {chm_limit, NULL}, /* l */
+ {chm_simple, (void *) MODE_MODERATED}, /* m */
+ {chm_simple, (void *) MODE_NOPRIVMSGS}, /* n */
+ {chm_op, NULL}, /* o */
+ {chm_simple, (void *) MODE_PRIVATE}, /* p */
+ {chm_nosuch, NULL}, /* q */
+ {chm_registered, (void *) MODE_REGISTERED}, /* r */
+ {chm_simple, (void *) MODE_SECRET}, /* s */
+ {chm_simple, (void *) MODE_TOPICLIMIT}, /* t */
+ {chm_nosuch, NULL}, /* u */
+ {chm_voice, NULL}, /* v */
+ {chm_nosuch, NULL}, /* w */
+ {chm_nosuch, NULL}, /* x */
+ {chm_nosuch, NULL}, /* y */
+ {chm_nosuch, NULL}, /* z */
+};
+
+/* get_channel_access()
+ *
+ * inputs - pointer to Client struct
+ * - pointer to Membership struct
+ * output - CHACCESS_CHANOP if we should let them have
+ * chanop level access, 0 for peon level access.
+ * side effects - NONE
+ */
+static int
+get_channel_access(struct Client *source_p, struct Membership *member)
+{
+ /* Let hacked servers in for now... */
+ if (!MyClient(source_p))
+ return CHACCESS_CHANOP;
+
+ if (member == NULL)
+ return CHACCESS_NOTONCHAN;
+
+ /* just to be sure.. */
+ assert(source_p == member->client_p);
+
+ if (has_member_flags(member, CHFL_CHANOP))
+ return CHACCESS_CHANOP;
+
+#ifdef HALFOPS
+ if (has_member_flags(member, CHFL_HALFOP))
+ return CHACCESS_HALFOP;
+#endif
+
+ return CHACCESS_PEON;
+}
+
+/* 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.
+ *
+ * send_cap_mode_changes() will loop the server list itself, because
+ * at this point in time we have 4 capabs for channels, CAP_IE, CAP_EX,
+ * and a server could support any number of these..
+ * so we make the modebufs per server, tailoring them to each servers
+ * specific demand. Its not very pretty, but its one of the few realistic
+ * ways to handle having this many capabs for channel modes.. --fl_
+ *
+ * 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
+ */
+/* rewritten to ensure parabuf < MODEBUFLEN -db */
+
+static void
+send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
+ struct Channel *chptr, unsigned int cap, unsigned int nocap)
+{
+ int i, mbl, pbl, arglen, nc, mc;
+ int len;
+ const char *arg = NULL;
+ char *parptr;
+ int dir = MODE_QUERY;
+
+ mc = 0;
+ nc = 0;
+ pbl = 0;
+
+ parabuf[0] = '\0';
+ parptr = parabuf;
+
+ if ((cap & CAP_TS6) && source_p->id[0] != '\0')
+ mbl = ircsprintf(modebuf, ":%s TMODE %lu %s ", source_p->id,
+ (unsigned long)chptr->channelts, chptr->chname);
+ else
+ mbl = 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;
+
+ arg = "";
+
+ if ((cap & CAP_TS6) && mode_changes[i].id)
+ arg = mode_changes[i].id;
+ if (*arg == '\0')
+ arg = mode_changes[i].arg;
+
+ /* 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 != NULL)
+ arglen = strlen(arg);
+ else
+ arglen = 0;
+
+ if ((mc == MAXMODEPARAMS) ||
+ ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
+ (pbl + arglen + BAN_FUDGE) >= MODEBUFLEN)
+ {
+ if (nc != 0)
+ sendto_server(client_p, cap, nocap,
+ "%s %s",
+ modebuf, parabuf);
+ nc = 0;
+ mc = 0;
+
+ if ((cap & CAP_TS6) && source_p->id[0] != '\0')
+ mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->id,
+ chptr->chname);
+ else
+ mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->name,
+ chptr->chname);
+
+ pbl = 0;
+ parabuf[0] = '\0';
+ parptr = parabuf;
+ 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(parptr, "%s ", arg);
+ pbl += len;
+ parptr += len;
+ mc++;
+ }
+ }
+
+ if (pbl && parabuf[pbl - 1] == ' ')
+ parabuf[pbl - 1] = 0;
+
+ if (nc != 0)
+ sendto_server(client_p, cap, nocap,
+ "%s %s", modebuf, parabuf);
+}
+
+/* void send_mode_changes(struct Client *client_p,
+ * struct Client *source_p,
+ * struct Channel *chptr)
+ * Input: The client sending(client_p), the source client(source_p),
+ * the channel to send mode changes for(chptr),
+ * mode change globals.
+ * Output: None.
+ * Side-effects: Sends the appropriate mode changes to other clients
+ * and propagates to servers.
+ */
+/* ensure parabuf < MODEBUFLEN -db */
+static void
+send_mode_changes(struct Client *client_p, struct Client *source_p,
+ struct Channel *chptr, char *chname)
+{
+ int i, mbl, pbl, arglen, nc, mc;
+ int len;
+ const char *arg = NULL;
+ char *parptr;
+ int dir = MODE_QUERY;
+
+ /* bail out if we have nothing to do... */
+ if (!mode_count)
+ return;
+
+ if (IsServer(source_p))
+ mbl = ircsprintf(modebuf, ":%s MODE %s ", (IsHidden(source_p) ||
+ ConfigServerHide.hide_servers) ?
+ me.name : source_p->name, chname);
+ else
+ mbl = ircsprintf(modebuf, ":%s!%s@%s MODE %s ", source_p->name,
+ source_p->username, source_p->host, chname);
+
+ mc = 0;
+ nc = 0;
+ pbl = 0;
+
+ parabuf[0] = '\0';
+ parptr = parabuf;
+
+ for (i = 0; i < mode_count; i++)
+ {
+ if (mode_changes[i].letter == 0 ||
+ mode_changes[i].mems == NON_CHANOPS ||
+ mode_changes[i].mems == ONLY_SERVERS)
+ continue;
+
+ arg = mode_changes[i].arg;
+ if (arg != NULL)
+ arglen = strlen(arg);
+ else
+ arglen = 0;
+
+ if ((mc == MAXMODEPARAMS) ||
+ ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
+ ((arglen + pbl + BAN_FUDGE) >= MODEBUFLEN))
+ {
+ if (mbl && modebuf[mbl - 1] == '-')
+ modebuf[mbl - 1] = '\0';
+
+ if (nc != 0)
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, "%s %s", modebuf, parabuf);
+
+ nc = 0;
+ mc = 0;
+
+ if (IsServer(source_p))
+ mbl = ircsprintf(modebuf, ":%s MODE %s ", me.name, chname);
+ else
+ mbl = ircsprintf(modebuf, ":%s!%s@%s MODE %s ", source_p->name,
+ source_p->username, source_p->host, chname);
+
+ pbl = 0;
+ parabuf[0] = '\0';
+ parptr = parabuf;
+ 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(parptr, "%s ", arg);
+ pbl += len;
+ parptr += len;
+ mc++;
+ }
+ }
+
+ if (pbl && parabuf[pbl - 1] == ' ')
+ parabuf[pbl - 1] = 0;
+
+ if (nc != 0)
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, "%s %s", modebuf, parabuf);
+
+ nc = 0;
+ mc = 0;
+
+ /* Now send to servers... */
+ for (i = 0; i < NCHCAP_COMBOS; i++)
+ if (chcap_combos[i].count != 0)
+ send_cap_mode_changes(client_p, source_p, chptr,
+ chcap_combos[i].cap_yes,
+ chcap_combos[i].cap_no);
+}
+
+/* void set_channel_mode(struct Client *client_p, struct Client *source_p,
+ * struct Channel *chptr, int parc, char **parv,
+ * char *chname)
+ * Input: The client we received this from, the client this originated
+ * from, the channel, the parameter count starting at the modes,
+ * the parameters, the channel name.
+ * Output: None.
+ * Side-effects: Changes the channel membership and modes appropriately,
+ * sends the appropriate MODE messages to the appropriate
+ * clients.
+ */
+void
+set_channel_mode(struct Client *client_p, struct Client *source_p, struct Channel *chptr,
+ struct Membership *member, int parc, char *parv[], char *chname)
+{
+ int dir = MODE_ADD;
+ int parn = 1;
+ int alevel, errors = 0;
+ char *ml = parv[0], c;
+ int table_position;
+
+ mode_count = 0;
+ mode_limit = 0;
+ simple_modes_mask = 0;
+
+ alevel = get_channel_access(source_p, member);
+
+ for (; (c = *ml) != '\0'; ml++)
+ {
+#if 0
+ if(mode_count > 20)
+ break;
+#endif
+ switch (c)
+ {
+ case '+':
+ dir = MODE_ADD;
+ break;
+ case '-':
+ dir = MODE_DEL;
+ break;
+ case '=':
+ dir = MODE_QUERY;
+ break;
+ default:
+ if (c < 'A' || c > 'z')
+ table_position = 0;
+ else
+ table_position = c - 'A' + 1;
+ ModeTable[table_position].func(client_p, source_p, chptr,
+ parc, &parn,
+ parv, &errors, alevel, dir, c,
+ ModeTable[table_position].d,
+ chname);
+ break;
+ }
+ }
+
+ send_mode_changes(client_p, source_p, chptr, chname);
+}
diff --git a/src/client.c b/src/client.c
new file mode 100644
index 0000000..4341716
--- /dev/null
+++ b/src/client.c
@@ -0,0 +1,1205 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * client.c: Controls clients.
+ *
+ * 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$
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "client.h"
+#include "channel_mode.h"
+#include "event.h"
+#include "fdlist.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "s_gline.h"
+#include "numeric.h"
+#include "packet.h"
+#include "s_auth.h"
+#include "s_bsd.h"
+#include "conf.h"
+#include "log.h"
+#include "s_misc.h"
+#include "s_serv.h"
+#include "send.h"
+#include "whowas.h"
+#include "s_user.h"
+#include "dbuf.h"
+#include "memory.h"
+#include "hostmask.h"
+#include "balloc.h"
+#include "listener.h"
+#include "irc_res.h"
+#include "userhost.h"
+#include "watch.h"
+
+dlink_list listing_client_list = { NULL, NULL, 0 };
+/* Pointer to beginning of Client list */
+dlink_list global_client_list = {NULL, NULL, 0};
+/* unknown/client pointer lists */
+dlink_list unknown_list = {NULL, NULL, 0};
+dlink_list local_client_list = {NULL, NULL, 0};
+dlink_list serv_list = {NULL, NULL, 0};
+dlink_list global_serv_list = {NULL, NULL, 0};
+dlink_list oper_list = {NULL, NULL, 0};
+
+static EVH check_pings;
+
+static BlockHeap *client_heap = NULL;
+static BlockHeap *lclient_heap = NULL;
+
+static dlink_list dead_list = { NULL, NULL, 0};
+static dlink_list abort_list = { NULL, NULL, 0};
+
+static dlink_node *eac_next; /* next aborted client to exit */
+
+static void check_pings_list(dlink_list *);
+static void check_unknowns_list(void);
+static void ban_them(struct Client *, struct ConfItem *);
+
+
+/* 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("client", sizeof(struct Client), CLIENT_HEAP_SIZE);
+ lclient_heap = BlockHeapCreate("local client", sizeof(struct LocalUser), LCLIENT_HEAP_SIZE);
+ eventAdd("check_pings", check_pings, NULL, 5);
+}
+
+/*
+ * make_client - create a new Client struct and set it to initial state.
+ *
+ * from == NULL, create local client (a client connected
+ * to a socket).
+ * WARNING: This leaves the client in a dangerous
+ * state where fd == -1, dead flag is not set and
+ * the client is on the unknown_list; therefore,
+ * the first thing to do after calling make_client(NULL)
+ * is setting fd to something reasonable. -adx
+ *
+ * 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 = BlockHeapAlloc(client_heap);
+
+ if (from == NULL)
+ {
+ client_p->from = client_p; /* 'from' of local client is self! */
+ client_p->localClient = BlockHeapAlloc(lclient_heap);
+ client_p->localClient->since = CurrentTime;
+ client_p->localClient->lasttime = CurrentTime;
+ client_p->localClient->firsttime = CurrentTime;
+ client_p->localClient->registration = REG_INIT;
+
+ /* as good a place as any... */
+ dlinkAdd(client_p, &client_p->localClient->lclient_node, &unknown_list);
+ }
+ else
+ client_p->from = from; /* 'from' of local client is self! */
+
+ client_p->idhnext = client_p;
+ client_p->hnext = client_p;
+ client_p->status = STAT_UNKNOWN;
+ strcpy(client_p->username, "unknown");
+ strcpy(client_p->svid, "0");
+
+ return client_p;
+}
+
+/*
+ * free_client
+ *
+ * inputs - pointer to client
+ * output - NONE
+ * side effects - client pointed to has its memory freed
+ */
+static void
+free_client(struct Client *client_p)
+{
+ assert(client_p != NULL);
+ assert(client_p != &me);
+ assert(client_p->hnext == client_p);
+ assert(client_p->idhnext == client_p);
+ assert(client_p->channel.head == NULL);
+ assert(dlink_list_length(&client_p->channel) == 0);
+ assert(dlink_list_length(&client_p->whowas) == 0);
+ assert(!IsServer(client_p) || IsServer(client_p) && client_p->serv);
+
+ MyFree(client_p->serv);
+
+ if (MyConnect(client_p))
+ {
+ assert(client_p->localClient->invited.head == NULL);
+ assert(dlink_list_length(&client_p->localClient->invited) == 0);
+ assert(dlink_list_length(&client_p->localClient->watches) == 0);
+ assert(IsClosing(client_p) && IsDead(client_p));
+
+ MyFree(client_p->localClient->response);
+ MyFree(client_p->localClient->auth_oper);
+
+ /*
+ * clean up extra sockets from P-lines which have been discarded.
+ */
+ if (client_p->localClient->listener)
+ {
+ 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);
+ }
+
+ dbuf_clear(&client_p->localClient->buf_recvq);
+ dbuf_clear(&client_p->localClient->buf_sendq);
+
+ BlockHeapFree(lclient_heap, client_p->localClient);
+ }
+
+ 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(&local_client_list);
+ check_pings_list(&serv_list);
+ check_unknowns_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, pingwarn; /* 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 (IsDead(client_p))
+ {
+ /* Ignore it, its been exited already */
+ continue;
+ }
+
+ if (!IsRegistered(client_p))
+ ping = CONNECTTIMEOUT, pingwarn = 0;
+ else
+ ping = get_client_ping(client_p, &pingwarn);
+
+ if (ping < CurrentTime - client_p->localClient->lasttime)
+ {
+ if (!IsPingSent(client_p))
+ {
+ /*
+ * if we havent PINGed the connection and we havent
+ * heard from it in a while, PING it to make sure
+ * it is still alive.
+ */
+ SetPingSent(client_p);
+ ClearPingWarning(client_p);
+ client_p->localClient->lasttime = CurrentTime - ping;
+ sendto_one(client_p, "PING :%s", ID_or_name(&me, client_p));
+ }
+ else
+ {
+ if (CurrentTime - client_p->localClient->lasttime >= 2 * ping)
+ {
+ /*
+ * If the client/server hasn't talked to us in 2*ping seconds
+ * and it has a ping time, then close its connection.
+ */
+ if (IsServer(client_p) || IsHandshake(client_p))
+ {
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "No response from %s, closing link",
+ get_client_name(client_p, HIDE_IP));
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "No response from %s, closing link",
+ get_client_name(client_p, MASK_IP));
+ ilog(LOG_TYPE_IRCD, "No response from %s, closing link",
+ get_client_name(client_p, HIDE_IP));
+ }
+
+ snprintf(scratch, sizeof(scratch), "Ping timeout: %d seconds",
+ (int)(CurrentTime - client_p->localClient->lasttime));
+ exit_client(client_p, &me, scratch);
+ }
+ else if (!IsPingWarning(client_p) && pingwarn > 0 &&
+ (IsServer(client_p) || IsHandshake(client_p)) &&
+ CurrentTime - client_p->localClient->lasttime >= ping + pingwarn)
+ {
+ /*
+ * If the server hasn't replied in pingwarn seconds after sending
+ * the PING, notify the opers so that they are aware of the problem.
+ */
+ SetPingWarning(client_p);
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "Warning, no response from %s in %d seconds",
+ get_client_name(client_p, HIDE_IP), pingwarn);
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "Warning, no response from %s in %d seconds",
+ get_client_name(client_p, MASK_IP), pingwarn);
+ ilog(LOG_TYPE_IRCD, "No response from %s in %d seconds",
+ get_client_name(client_p, HIDE_IP), pingwarn);
+ }
+ }
+ }
+ }
+}
+
+/* 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(void)
+{
+ dlink_node *ptr, *next_ptr;
+
+ DLINK_FOREACH_SAFE(ptr, next_ptr, unknown_list.head)
+ {
+ struct Client *client_p = ptr->data;
+
+ /*
+ * Check UNKNOWN connections - if they have been in this state
+ * for > 30s, close them.
+ */
+ if (IsAuthFinished(client_p) && (CurrentTime - client_p->localClient->firsttime) > 30)
+ exit_client(client_p, &me, "Registration timed out");
+ }
+}
+
+/* check_conf_klines()
+ *
+ * inputs - NONE
+ * output - NONE
+ * side effects - Check all connections for a pending kline against the
+ * client, exit the client if a kline matches.
+ */
+void
+check_conf_klines(void)
+{
+ struct Client *client_p = NULL; /* current local client_p being examined */
+ struct AccessItem *aconf = NULL;
+ struct ConfItem *conf = NULL;
+ dlink_node *ptr, *next_ptr;
+
+ DLINK_FOREACH_SAFE(ptr, next_ptr, local_client_list.head)
+ {
+ client_p = ptr->data;
+
+ /* If a client is already being exited
+ */
+ if (IsDead(client_p) || !IsClient(client_p))
+ continue;
+
+ /* if there is a returned struct ConfItem then kill it */
+ if ((aconf = find_dline_conf(&client_p->localClient->ip,
+ client_p->localClient->aftype)) != NULL)
+ {
+ if (aconf->status & CONF_EXEMPTDLINE)
+ continue;
+
+ conf = unmap_conf_item(aconf);
+ ban_them(client_p, conf);
+ continue; /* and go examine next fd/client_p */
+ }
+
+ if (ConfigFileEntry.glines && (aconf = find_gline(client_p)))
+ {
+ if (IsExemptKline(client_p) ||
+ IsExemptGline(client_p))
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "GLINE over-ruled for %s, client is %sline_exempt",
+ get_client_name(client_p, HIDE_IP), IsExemptKline(client_p) ? "k" : "g");
+ continue;
+ }
+
+ conf = unmap_conf_item(aconf);
+ ban_them(client_p, conf);
+ /* and go examine next fd/client_p */
+ continue;
+ }
+
+ if ((aconf = find_kill(client_p)) != NULL)
+ {
+
+ /* if there is a returned struct AccessItem.. then kill it */
+ if (IsExemptKline(client_p))
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "KLINE over-ruled for %s, client is kline_exempt",
+ get_client_name(client_p, HIDE_IP));
+ continue;
+ }
+
+ conf = unmap_conf_item(aconf);
+ ban_them(client_p, conf);
+ continue;
+ }
+
+ /* if there is a returned struct MatchItem then kill it */
+ if ((conf = find_matching_name_conf(XLINE_TYPE, client_p->info,
+ NULL, NULL, 0)) != NULL ||
+ (conf = find_matching_name_conf(RXLINE_TYPE, client_p->info,
+ NULL, NULL, 0)) != NULL)
+ {
+ ban_them(client_p, conf);
+ 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_conf(&client_p->localClient->ip,
+ client_p->localClient->aftype)))
+ {
+ if (aconf->status & CONF_EXEMPTDLINE)
+ continue;
+
+ exit_client(client_p, &me, "D-lined");
+ }
+ }
+}
+
+/*
+ * ban_them
+ *
+ * inputs - pointer to client to ban
+ * - pointer to ConfItem
+ * output - NONE
+ * side effects - given client_p is banned
+ */
+static void
+ban_them(struct Client *client_p, struct ConfItem *conf)
+{
+ const char *user_reason = NULL; /* What is sent to user */
+ struct AccessItem *aconf = NULL;
+ struct MatchItem *xconf = NULL;
+ const char *type_string = NULL;
+ const char dline_string[] = "D-line";
+ const char kline_string[] = "K-line";
+ const char gline_string[] = "G-line";
+ const char xline_string[] = "X-line";
+
+ switch (conf->type)
+ {
+ case RKLINE_TYPE:
+ case KLINE_TYPE:
+ type_string = kline_string;
+ aconf = map_to_conf(conf);
+ break;
+ case DLINE_TYPE:
+ type_string = dline_string;
+ aconf = map_to_conf(conf);
+ break;
+ case GLINE_TYPE:
+ type_string = gline_string;
+ aconf = map_to_conf(conf);
+ break;
+ case RXLINE_TYPE:
+ case XLINE_TYPE:
+ type_string = xline_string;
+ xconf = map_to_conf(conf);
+ ++xconf->count;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ if (aconf != NULL)
+ user_reason = aconf->reason ? aconf->reason : type_string;
+ if (xconf != NULL)
+ user_reason = xconf->reason ? xconf->reason : type_string;
+
+ sendto_realops_flags(UMODE_ALL, L_ALL, "%s active for %s",
+ type_string, get_client_name(client_p, HIDE_IP));
+
+ if (IsClient(client_p))
+ sendto_one(client_p, form_str(ERR_YOUREBANNEDCREEP),
+ me.name, client_p->name, user_reason);
+
+ exit_client(client_p, &me, user_reason);
+}
+
+/* update_client_exit_stats()
+ *
+ * input - pointer to client
+ * output - NONE
+ * side effects -
+ */
+static void
+update_client_exit_stats(struct Client *client_p)
+{
+ if (IsClient(client_p))
+ {
+ assert(Count.total > 0);
+ --Count.total;
+ if (HasUMode(client_p, UMODE_OPER))
+ --Count.oper;
+ if (HasUMode(client_p, UMODE_INVISIBLE))
+ --Count.invisi;
+ }
+ else if (IsServer(client_p))
+ sendto_realops_flags(UMODE_EXTERNAL, L_ALL, "Server %s split from %s",
+ client_p->name, client_p->servptr->name);
+
+ if (splitchecking && !splitmode)
+ check_splitmode(NULL);
+}
+
+/* find_person()
+ *
+ * inputs - pointer to name
+ * output - return client pointer
+ * side effects - find person by (nick)name
+ */
+struct Client *
+find_person(const struct Client *client_p, const char *name)
+{
+ struct Client *c2ptr = NULL;
+
+ if (IsDigit(*name))
+ {
+ if ((c2ptr = hash_find_id(name)) != NULL)
+ {
+ /* invisible users shall not be found by UID guessing */
+ if (HasUMode(c2ptr, UMODE_INVISIBLE))
+ if (!IsServer(client_p) && !HasFlag(client_p, FLAGS_SERVICE))
+ c2ptr = NULL;
+ }
+ }
+ else
+ c2ptr = hash_find_client(name);
+
+ return ((c2ptr != NULL && IsClient(c2ptr)) ? c2ptr : 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 *client_p, struct Client *source_p, const char *user, int *chasing)
+{
+ struct Client *who = find_person(client_p, user);
+
+ if (chasing)
+ *chasing = 0;
+
+ if (who)
+ return who;
+
+ if (IsDigit(*user))
+ return NULL;
+
+ if ((who = get_history(user,
+ (time_t)ConfigFileEntry.kill_chase_time_limit))
+ == NULL)
+ {
+ sendto_one(source_p, form_str(ERR_NOSUCHNICK),
+ me.name, source_p->name, 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(const struct Client *client, enum addr_mask_type type)
+{
+ static char nbuf[HOSTLEN * 2 + USERLEN + 5];
+
+ assert(client != NULL);
+
+ if (!MyConnect(client))
+ return client->name;
+
+ if (IsServer(client) || IsConnecting(client) || IsHandshake(client))
+ {
+ if (!irccmp(client->name, client->host))
+ return client->name;
+ else if (ConfigServerHide.hide_server_ips)
+ type = MASK_IP;
+ }
+
+ if (ConfigFileEntry.hide_spoof_ips)
+ if (type == SHOW_IP && IsIPSpoof(client))
+ type = MASK_IP;
+
+ /* And finally, let's get the host information, ip or name */
+ switch (type)
+ {
+ case SHOW_IP:
+ snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
+ client->name,
+ client->username, client->sockhost);
+ break;
+ case MASK_IP:
+ if (client->localClient->aftype == AF_INET)
+ snprintf(nbuf, sizeof(nbuf), "%s[%s@255.255.255.255]",
+ client->name, client->username);
+ else
+ snprintf(nbuf, sizeof(nbuf), "%s[%s@ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]",
+ client->name, client->username);
+ break;
+ default:
+ snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
+ client->name,
+ client->username, client->host);
+ }
+
+ return nbuf;
+}
+
+void
+free_exited_clients(void)
+{
+ dlink_node *ptr = NULL, *next = NULL;
+
+ DLINK_FOREACH_SAFE(ptr, next, dead_list.head)
+ {
+ free_client(ptr->data);
+ dlinkDelete(ptr, &dead_list);
+ free_dlink_node(ptr);
+ }
+}
+
+/*
+ * Exit one client, local or remote. Assuming all dependents have
+ * been already removed, and socket closed for local client.
+ *
+ * The only messages generated are QUITs on channels.
+ */
+static void
+exit_one_client(struct Client *source_p, const char *quitmsg)
+{
+ dlink_node *lp = NULL, *next_lp = NULL;
+
+ assert(!IsMe(source_p));
+
+ if (IsClient(source_p))
+ {
+ if (source_p->servptr->serv != NULL)
+ dlinkDelete(&source_p->lnode, &source_p->servptr->serv->client_list);
+
+ /*
+ * If a person is on a channel, send a QUIT notice
+ * to every client (person) on the same channel (so
+ * that the client can show the "**signoff" message).
+ * (Note: The notice is to the local clients *only*)
+ */
+ sendto_common_channels_local(source_p, 0, ":%s!%s@%s QUIT :%s",
+ source_p->name, source_p->username,
+ source_p->host, quitmsg);
+ DLINK_FOREACH_SAFE(lp, next_lp, source_p->channel.head)
+ remove_user_from_channel(lp->data);
+
+ add_history(source_p, 0);
+ off_history(source_p);
+
+ watch_check_hash(source_p, RPL_LOGOFF);
+
+ if (MyConnect(source_p))
+ {
+ /* Clean up invitefield */
+ DLINK_FOREACH_SAFE(lp, next_lp, source_p->localClient->invited.head)
+ del_invite(lp->data, source_p);
+
+ del_all_accepts(source_p);
+ }
+ }
+ else if (IsServer(source_p))
+ {
+ dlinkDelete(&source_p->lnode, &source_p->servptr->serv->server_list);
+
+ if ((lp = dlinkFindDelete(&global_serv_list, source_p)) != NULL)
+ free_dlink_node(lp);
+ }
+
+ /* Remove source_p from the client lists */
+ if (HasID(source_p))
+ hash_del_id(source_p);
+ if (source_p->name[0])
+ hash_del_client(source_p);
+
+ if (IsUserHostIp(source_p))
+ delete_user_host(source_p->username, source_p->host, !MyConnect(source_p));
+
+ /* remove from global client list
+ * NOTE: source_p->node.next cannot be NULL if the client is added
+ * to global_client_list (there is always &me at its end)
+ */
+ if (source_p != NULL && source_p->node.next != NULL)
+ dlinkDelete(&source_p->node, &global_client_list);
+
+ update_client_exit_stats(source_p);
+
+ /* Check to see if the client isn't already on the dead list */
+ assert(dlinkFind(&dead_list, source_p) == NULL);
+
+ /* add to dead client dlist */
+ SetDead(source_p);
+ dlinkAdd(source_p, make_dlink_node(), &dead_list);
+}
+
+/* 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
+ *
+ * This is now called on each local server -adx
+ */
+static void
+recurse_send_quits(struct Client *original_source_p, struct Client *source_p,
+ struct Client *from, struct Client *to, const char *comment,
+ const char *splitstr)
+{
+ dlink_node *ptr, *next;
+ struct Client *target_p;
+
+ assert(to != source_p); /* should be already removed from serv_list */
+
+ /* If this server can handle quit storm (QS) removal
+ * of dependents, just send the SQUIT
+ */
+ if (!IsCapable(to, CAP_QS))
+ DLINK_FOREACH_SAFE(ptr, next, source_p->serv->client_list.head)
+ {
+ target_p = ptr->data;
+ sendto_one(to, ":%s QUIT :%s", target_p->name, splitstr);
+ }
+
+ DLINK_FOREACH_SAFE(ptr, next, source_p->serv->server_list.head)
+ recurse_send_quits(original_source_p, ptr->data, from, to,
+ comment, splitstr);
+
+ if ((source_p == original_source_p && to != from) ||
+ !IsCapable(to, CAP_QS))
+ {
+ /* don't use a prefix here - we have to be 100% sure the message
+ * will be accepted without Unknown prefix etc.. */
+ sendto_one(to, "SQUIT %s :%s", ID_or_name(source_p, to), 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
+ */
+static void
+recurse_remove_clients(struct Client *source_p, const char *quitmsg)
+{
+ dlink_node *ptr, *next;
+
+ DLINK_FOREACH_SAFE(ptr, next, source_p->serv->client_list.head)
+ exit_one_client(ptr->data, quitmsg);
+
+ DLINK_FOREACH_SAFE(ptr, next, source_p->serv->server_list.head)
+ {
+ recurse_remove_clients(ptr->data, quitmsg);
+ exit_one_client(ptr->data, quitmsg);
+ }
+}
+
+/*
+** 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 *source_p, struct Client *from,
+ const char *comment, const char *splitstr)
+{
+ dlink_node *ptr = NULL;
+
+ DLINK_FOREACH(ptr, serv_list.head)
+ recurse_send_quits(source_p, source_p, from, ptr->data,
+ comment, splitstr);
+
+ recurse_remove_clients(source_p, splitstr);
+}
+
+/*
+ * exit_client - exit a client of any type. Generally, you can use
+ * this on any struct Client, regardless of its state.
+ *
+ * Note, you shouldn't exit remote _users_ without first doing
+ * AddFlag(x, FLAGS_KILLED) and propagating a kill or similar message.
+ * However, it is perfectly correct to call exit_client to force a _server_
+ * quit (either local or remote one).
+ *
+ * inputs: - a client pointer that is going to be exited
+ * - for servers, the second argument is a pointer to who
+ * is firing the server. This side won't get any generated
+ * messages. NEVER NULL!
+ * output: none
+ * side effects: the client is delinked from all lists, disconnected,
+ * and the rest of IRC network is notified of the exit.
+ * Client memory is scheduled to be freed
+ */
+void
+exit_client(struct Client *source_p, struct Client *from, const char *comment)
+{
+ dlink_node *m = NULL;
+
+ if (MyConnect(source_p))
+ {
+ /* DO NOT REMOVE. exit_client can be called twice after a failed
+ * read/write.
+ */
+ if (IsClosing(source_p))
+ return;
+
+ SetClosing(source_p);
+
+ if (IsIpHash(source_p))
+ remove_one_ip(&source_p->localClient->ip);
+
+ if (source_p->localClient->auth)
+ {
+ delete_auth(source_p->localClient->auth);
+ source_p->localClient->auth = NULL;
+ }
+
+ /*
+ * This source_p could have status of one of STAT_UNKNOWN, STAT_CONNECTING
+ * STAT_HANDSHAKE or STAT_UNKNOWN
+ * all of which are lumped together into unknown_list
+ *
+ * In all above cases IsRegistered() will not be true.
+ */
+ if (!IsRegistered(source_p))
+ {
+ assert(dlinkFind(&unknown_list, source_p));
+
+ dlinkDelete(&source_p->localClient->lclient_node, &unknown_list);
+ }
+ else if (IsClient(source_p))
+ {
+ time_t on_for = CurrentTime - source_p->localClient->firsttime;
+ assert(Count.local > 0);
+ Count.local--;
+
+ if (HasUMode(source_p, UMODE_OPER))
+ if ((m = dlinkFindDelete(&oper_list, source_p)) != NULL)
+ free_dlink_node(m);
+
+ assert(dlinkFind(&local_client_list, source_p));
+ dlinkDelete(&source_p->localClient->lclient_node, &local_client_list);
+
+ if (source_p->localClient->list_task != NULL)
+ free_list_task(source_p->localClient->list_task, source_p);
+
+ watch_del_watch_list(source_p);
+ sendto_realops_flags(UMODE_CCONN, L_ALL, "Client exiting: %s (%s@%s) [%s] [%s]",
+ source_p->name, source_p->username, source_p->host, comment,
+ ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ?
+ "255.255.255.255" : source_p->sockhost);
+ sendto_realops_flags(UMODE_CCONN_FULL, L_ALL, "CLIEXIT: %s %s %s %s 0 %s",
+ source_p->name,
+ source_p->username,
+ source_p->host,
+ ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ?
+ "255.255.255.255" : source_p->sockhost,
+ comment);
+ ilog(LOG_TYPE_USER, "%s (%3u:%02u:%02u): %s!%s@%s %llu/%llu",
+ myctime(source_p->localClient->firsttime), (unsigned int)(on_for / 3600),
+ (unsigned int)((on_for % 3600)/60), (unsigned int)(on_for % 60),
+ source_p->name, source_p->username, source_p->host,
+ source_p->localClient->send.bytes>>10,
+ source_p->localClient->recv.bytes>>10);
+ }
+ else if (IsServer(source_p))
+ {
+ assert(Count.myserver > 0);
+ --Count.myserver;
+
+ assert(dlinkFind(&serv_list, source_p));
+ dlinkDelete(&source_p->localClient->lclient_node, &serv_list);
+ unset_chcap_usage_counts(source_p);
+ }
+
+ if (!IsDead(source_p))
+ {
+ if (IsServer(source_p))
+ {
+ /* for them, we are exiting the network */
+ sendto_one(source_p, ":%s SQUIT %s :%s",
+ ID_or_name(from, source_p), me.name, comment);
+ }
+
+ sendto_one(source_p, "ERROR :Closing Link: %s (%s)",
+ source_p->host, comment);
+ }
+
+ /*
+ ** Currently only server connections can have
+ ** depending remote clients here, but it does no
+ ** harm to check for all local clients. In
+ ** future some other clients than servers might
+ ** have remotes too...
+ **
+ ** Close the Client connection first and mark it
+ ** so that no messages are attempted to send to it.
+ ** Remember it makes source_p->from == NULL.
+ */
+ close_connection(source_p);
+ }
+
+ if (IsServer(source_p))
+ {
+ char splitstr[HOSTLEN + HOSTLEN + 2];
+
+ /* This shouldn't ever happen */
+ assert(source_p->serv != NULL && source_p->servptr != NULL);
+
+ if (ConfigServerHide.hide_servers)
+ /*
+ * Set netsplit message to "*.net *.split" to still show
+ * that its a split, but hide the servers splitting
+ */
+ strcpy(splitstr, "*.net *.split");
+ else
+ snprintf(splitstr, sizeof(splitstr), "%s %s",
+ source_p->servptr->name, source_p->name);
+
+ remove_dependents(source_p, from->from, comment, splitstr);
+
+ if (source_p->servptr == &me)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s was connected for %d seconds. %llu/%llu sendK/recvK.",
+ source_p->name, (int)(CurrentTime - source_p->localClient->firsttime),
+ source_p->localClient->send.bytes >> 10,
+ source_p->localClient->recv.bytes >> 10);
+ ilog(LOG_TYPE_IRCD, "%s was connected for %d seconds. %llu/%llu sendK/recvK.",
+ source_p->name, (int)(CurrentTime - source_p->localClient->firsttime),
+ source_p->localClient->send.bytes >> 10,
+ source_p->localClient->recv.bytes >> 10);
+ }
+ }
+ else if (IsClient(source_p) && !HasFlag(source_p, FLAGS_KILLED))
+ {
+ sendto_server(from->from, CAP_TS6, NOCAPS,
+ ":%s QUIT :%s", ID(source_p), comment);
+ sendto_server(from->from, NOCAPS, CAP_TS6,
+ ":%s QUIT :%s", source_p->name, comment);
+ }
+
+ /* The client *better* be off all of the lists */
+ assert(dlinkFind(&unknown_list, source_p) == NULL);
+ assert(dlinkFind(&local_client_list, source_p) == NULL);
+ assert(dlinkFind(&serv_list, source_p) == NULL);
+ assert(dlinkFind(&oper_list, source_p) == NULL);
+
+ exit_one_client(source_p, comment);
+}
+
+/*
+ * dead_link_on_write - report a write error if not already dead,
+ * mark it as dead then exit it
+ */
+void
+dead_link_on_write(struct Client *client_p, int ierrno)
+{
+ dlink_node *ptr;
+
+ if (IsDefunct(client_p))
+ return;
+
+ dbuf_clear(&client_p->localClient->buf_recvq);
+ dbuf_clear(&client_p->localClient->buf_sendq);
+
+ assert(dlinkFind(&abort_list, client_p) == NULL);
+ ptr = make_dlink_node();
+ /* don't let exit_aborted_clients() finish yet */
+ dlinkAddTail(client_p, ptr, &abort_list);
+
+ if (eac_next == NULL)
+ eac_next = ptr;
+
+ SetDead(client_p); /* You are dead my friend */
+}
+
+/*
+ * dead_link_on_read - report a read error if not already dead,
+ * mark it as dead then exit it
+ */
+void
+dead_link_on_read(struct Client *client_p, int error)
+{
+ char errmsg[255];
+ int current_error;
+
+ if (IsDefunct(client_p))
+ return;
+
+ dbuf_clear(&client_p->localClient->buf_recvq);
+ dbuf_clear(&client_p->localClient->buf_sendq);
+
+ current_error = get_sockerr(client_p->localClient->fd.fd);
+
+ if (IsServer(client_p) || IsHandshake(client_p))
+ {
+ int connected = CurrentTime - client_p->localClient->firsttime;
+
+ if (error == 0)
+ {
+ /* Admins get the real IP */
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "Server %s closed the connection",
+ get_client_name(client_p, SHOW_IP));
+
+ /* Opers get a masked IP */
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "Server %s closed the connection",
+ get_client_name(client_p, MASK_IP));
+
+ ilog(LOG_TYPE_IRCD, "Server %s closed the connection",
+ get_client_name(client_p, SHOW_IP));
+ }
+ else
+ {
+ report_error(L_ADMIN, "Lost connection to %s: %s",
+ get_client_name(client_p, SHOW_IP), current_error);
+ report_error(L_OPER, "Lost connection to %s: %s",
+ get_client_name(client_p, MASK_IP), current_error);
+ }
+
+ sendto_realops_flags(UMODE_ALL, 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
+ snprintf(errmsg, sizeof(errmsg), "Read error: %s",
+ strerror(current_error));
+
+ exit_client(client_p, &me, errmsg);
+}
+
+void
+exit_aborted_clients(void)
+{
+ dlink_node *ptr;
+ struct Client *target_p;
+ const char *notice;
+
+ DLINK_FOREACH_SAFE(ptr, eac_next, abort_list.head)
+ {
+ target_p = ptr->data;
+ eac_next = ptr->next;
+
+ if (target_p == NULL)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Warning: null client on abort_list!");
+ dlinkDelete(ptr, &abort_list);
+ free_dlink_node(ptr);
+ continue;
+ }
+
+ dlinkDelete(ptr, &abort_list);
+
+ if (IsSendQExceeded(target_p))
+ notice = "Max SendQ exceeded";
+ else
+ notice = "Write error: connection closed";
+
+ exit_client(target_p, &me, notice);
+ free_dlink_node(ptr);
+ }
+}
+
+/*
+ * 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.
+ *
+ * Diane Bruce, "Dianora" db@db.net
+ */
+
+void
+del_accept(struct split_nuh_item *accept_p, struct Client *client_p)
+{
+ dlinkDelete(&accept_p->node, &client_p->localClient->acceptlist);
+
+ MyFree(accept_p->nickptr);
+ MyFree(accept_p->userptr);
+ MyFree(accept_p->hostptr);
+ MyFree(accept_p);
+}
+
+struct split_nuh_item *
+find_accept(const char *nick, const char *user,
+ const char *host, struct Client *client_p, int do_match)
+{
+ dlink_node *ptr = NULL;
+ /* XXX We wouldn't need that if match() would return 0 on match */
+ int (*cmpfunc)(const char *, const char *) = do_match ? match : irccmp;
+
+ DLINK_FOREACH(ptr, client_p->localClient->acceptlist.head)
+ {
+ struct split_nuh_item *accept_p = ptr->data;
+
+ if (cmpfunc(accept_p->nickptr, nick) == do_match &&
+ cmpfunc(accept_p->userptr, user) == do_match &&
+ cmpfunc(accept_p->hostptr, host) == do_match)
+ return accept_p;
+ }
+
+ return NULL;
+}
+
+/* accept_message()
+ *
+ * inputs - pointer to source client
+ * - pointer to target client
+ * output - 1 if accept this message 0 if not
+ * side effects - See if source is on target's allow list
+ */
+int
+accept_message(struct Client *source,
+ struct Client *target)
+{
+ dlink_node *ptr = NULL;
+
+ if (source == target || find_accept(source->name, source->username,
+ source->host, target, 1))
+ return 1;
+
+ if (HasUMode(target, UMODE_SOFTCALLERID))
+ DLINK_FOREACH(ptr, target->channel.head)
+ if (IsMember(source, ((struct Membership *)ptr->data)->chptr))
+ return 1;
+
+ return 0;
+}
+
+/* del_all_accepts()
+ *
+ * inputs - pointer to exiting client
+ * output - NONE
+ * side effects - Walk through given clients acceptlist and remove all entries
+ */
+void
+del_all_accepts(struct Client *client_p)
+{
+ dlink_node *ptr = NULL, *next_ptr = NULL;
+
+ DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->localClient->acceptlist.head)
+ del_accept(ptr->data, client_p);
+}
diff --git a/src/conf.c b/src/conf.c
new file mode 100644
index 0000000..b5adf94
--- /dev/null
+++ b/src/conf.c
@@ -0,0 +1,3622 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * conf.c: Configuration file functions.
+ *
+ * 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$
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "ircd_defs.h"
+#include "balloc.h"
+#include "conf.h"
+#include "s_serv.h"
+#include "resv.h"
+#include "channel.h"
+#include "client.h"
+#include "event.h"
+#include "hook.h"
+#include "irc_string.h"
+#include "s_bsd.h"
+#include "ircd.h"
+#include "listener.h"
+#include "hostmask.h"
+#include "modules.h"
+#include "numeric.h"
+#include "fdlist.h"
+#include "log.h"
+#include "send.h"
+#include "s_gline.h"
+#include "memory.h"
+#include "irc_res.h"
+#include "userhost.h"
+#include "s_user.h"
+#include "channel_mode.h"
+#include "parse.h"
+#include "s_misc.h"
+
+struct Callback *client_check_cb = NULL;
+struct config_server_hide ConfigServerHide;
+
+/* general conf items link list root, other than k lines etc. */
+dlink_list service_items = { NULL, NULL, 0 };
+dlink_list server_items = { NULL, NULL, 0 };
+dlink_list cluster_items = { NULL, NULL, 0 };
+dlink_list oconf_items = { NULL, NULL, 0 };
+dlink_list uconf_items = { NULL, NULL, 0 };
+dlink_list xconf_items = { NULL, NULL, 0 };
+dlink_list rxconf_items = { NULL, NULL, 0 };
+dlink_list rkconf_items = { NULL, NULL, 0 };
+dlink_list nresv_items = { NULL, NULL, 0 };
+dlink_list class_items = { NULL, NULL, 0 };
+
+dlink_list temporary_xlines = { NULL, NULL, 0 };
+dlink_list temporary_resv = { NULL, NULL, 0 };
+
+extern unsigned int lineno;
+extern char linebuf[];
+extern char conffilebuf[IRCD_BUFSIZE];
+extern int yyparse(); /* defined in y.tab.c */
+
+struct conf_parser_context conf_parser_ctx = { 0, 0, NULL };
+
+/* internally defined functions */
+static void read_conf(FILE *);
+static void clear_out_old_conf(void);
+static void flush_deleted_I_P(void);
+static void expire_tklines(dlink_list *);
+static void garbage_collect_ip_entries(void);
+static int hash_ip(struct irc_ssaddr *);
+static int verify_access(struct Client *, const char *);
+static int attach_iline(struct Client *, struct ConfItem *);
+static struct ip_entry *find_or_add_ip(struct irc_ssaddr *);
+static void parse_conf_file(int, int);
+static dlink_list *map_to_list(ConfType);
+static struct AccessItem *find_regexp_kline(const char *[]);
+static int find_user_host(struct Client *, char *, char *, char *, unsigned int);
+
+/*
+ * bit_len
+ */
+static int cidr_limit_reached(int, struct irc_ssaddr *, struct ClassItem *);
+static void remove_from_cidr_check(struct irc_ssaddr *, struct ClassItem *);
+static void destroy_cidr_class(struct ClassItem *);
+
+static void flags_to_ascii(unsigned int, const unsigned int[], char *, int);
+
+/* address of default class conf */
+static struct ConfItem *class_default;
+
+/* usually, with hash tables, you use a prime number...
+ * but in this case I am dealing with ip addresses,
+ * not ascii strings.
+ */
+#define IP_HASH_SIZE 0x1000
+
+struct ip_entry
+{
+ struct irc_ssaddr ip;
+ int count;
+ time_t last_attempt;
+ struct ip_entry *next;
+};
+
+static struct ip_entry *ip_hash_table[IP_HASH_SIZE];
+static BlockHeap *ip_entry_heap = NULL;
+static int ip_entries_count = 0;
+
+
+void *
+map_to_conf(struct ConfItem *aconf)
+{
+ void *conf;
+ conf = (void *)((uintptr_t)aconf +
+ (uintptr_t)sizeof(struct ConfItem));
+ return(conf);
+}
+
+struct ConfItem *
+unmap_conf_item(void *aconf)
+{
+ struct ConfItem *conf;
+
+ conf = (struct ConfItem *)((uintptr_t)aconf -
+ (uintptr_t)sizeof(struct ConfItem));
+ return(conf);
+}
+
+/* conf_dns_callback()
+ *
+ * inputs - pointer to struct AccessItem
+ * - pointer to DNSReply reply
+ * output - none
+ * side effects - 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.
+ * if successful save hp in the conf item it was called with
+ */
+static void
+conf_dns_callback(void *vptr, const struct irc_ssaddr *addr, const char *name)
+{
+ struct AccessItem *aconf = vptr;
+
+ aconf->dns_pending = 0;
+
+ if (addr != NULL)
+ memcpy(&aconf->addr, addr, sizeof(aconf->addr));
+ else
+ aconf->dns_failed = 1;
+}
+
+/* conf_dns_lookup()
+ *
+ * do a nameserver lookup of the conf host
+ * if the conf entry is currently doing a ns lookup do nothing, otherwise
+ * allocate a dns_query and start ns lookup.
+ */
+static void
+conf_dns_lookup(struct AccessItem *aconf)
+{
+ if (!aconf->dns_pending)
+ {
+ aconf->dns_pending = 1;
+ gethost_byname(conf_dns_callback, aconf, aconf->host);
+ }
+}
+
+/* make_conf_item()
+ *
+ * inputs - type of item
+ * output - pointer to new conf entry
+ * side effects - none
+ */
+struct ConfItem *
+make_conf_item(ConfType type)
+{
+ struct ConfItem *conf = NULL;
+ struct AccessItem *aconf = NULL;
+ struct ClassItem *aclass = NULL;
+ int status = 0;
+
+ switch (type)
+ {
+ case DLINE_TYPE:
+ case EXEMPTDLINE_TYPE:
+ case GLINE_TYPE:
+ case KLINE_TYPE:
+ case CLIENT_TYPE:
+ case OPER_TYPE:
+ case SERVER_TYPE:
+ conf = MyMalloc(sizeof(struct ConfItem) +
+ sizeof(struct AccessItem));
+ aconf = map_to_conf(conf);
+ aconf->aftype = AF_INET;
+
+ /* Yes, sigh. switch on type again */
+ switch (type)
+ {
+ case EXEMPTDLINE_TYPE:
+ status = CONF_EXEMPTDLINE;
+ break;
+
+ case DLINE_TYPE:
+ status = CONF_DLINE;
+ break;
+
+ case KLINE_TYPE:
+ status = CONF_KLINE;
+ break;
+
+ case GLINE_TYPE:
+ status = CONF_GLINE;
+ break;
+
+ case CLIENT_TYPE:
+ status = CONF_CLIENT;
+ break;
+
+ case OPER_TYPE:
+ status = CONF_OPERATOR;
+ dlinkAdd(conf, &conf->node, &oconf_items);
+ break;
+
+ case SERVER_TYPE:
+ status = CONF_SERVER;
+ dlinkAdd(conf, &conf->node, &server_items);
+ break;
+
+ default:
+ break;
+ }
+ aconf->status = status;
+ break;
+
+ case ULINE_TYPE:
+ conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) +
+ sizeof(struct MatchItem));
+ dlinkAdd(conf, &conf->node, &uconf_items);
+ break;
+
+ case XLINE_TYPE:
+ conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) +
+ sizeof(struct MatchItem));
+ dlinkAdd(conf, &conf->node, &xconf_items);
+ break;
+#ifdef HAVE_LIBPCRE
+ case RXLINE_TYPE:
+ conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) +
+ sizeof(struct MatchItem));
+ dlinkAdd(conf, &conf->node, &rxconf_items);
+ break;
+
+ case RKLINE_TYPE:
+ conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) +
+ sizeof(struct AccessItem));
+ aconf = map_to_conf(conf);
+ aconf->status = CONF_KLINE;
+ dlinkAdd(conf, &conf->node, &rkconf_items);
+ break;
+#endif
+ case CLUSTER_TYPE:
+ conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem));
+ dlinkAdd(conf, &conf->node, &cluster_items);
+ break;
+
+ case CRESV_TYPE:
+ conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) +
+ sizeof(struct ResvChannel));
+ break;
+
+ case NRESV_TYPE:
+ conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) +
+ sizeof(struct MatchItem));
+ dlinkAdd(conf, &conf->node, &nresv_items);
+ break;
+
+ case SERVICE_TYPE:
+ status = CONF_SERVICE;
+ conf = MyMalloc(sizeof(struct ConfItem));
+ dlinkAdd(conf, &conf->node, &service_items);
+ break;
+
+ case CLASS_TYPE:
+ conf = MyMalloc(sizeof(struct ConfItem) +
+ sizeof(struct ClassItem));
+ dlinkAdd(conf, &conf->node, &class_items);
+
+ aclass = map_to_conf(conf);
+ aclass->active = 1;
+ aclass->con_freq = DEFAULT_CONNECTFREQUENCY;
+ aclass->ping_freq = DEFAULT_PINGFREQUENCY;
+ aclass->max_total = MAXIMUM_LINKS_DEFAULT;
+ aclass->max_sendq = DEFAULT_SENDQ;
+ aclass->max_recvq = DEFAULT_RECVQ;
+
+ break;
+
+ default:
+ conf = NULL;
+ break;
+ }
+
+ /* XXX Yes, this will core if default is hit. I want it to for now - db */
+ conf->type = type;
+
+ return conf;
+}
+
+void
+delete_conf_item(struct ConfItem *conf)
+{
+ dlink_node *m = NULL, *m_next = NULL;
+ struct MatchItem *match_item;
+ struct AccessItem *aconf;
+ ConfType type = conf->type;
+
+ MyFree(conf->name);
+ conf->name = NULL;
+
+ switch(type)
+ {
+ case DLINE_TYPE:
+ case EXEMPTDLINE_TYPE:
+ case GLINE_TYPE:
+ case KLINE_TYPE:
+ case CLIENT_TYPE:
+ case OPER_TYPE:
+ case SERVER_TYPE:
+ aconf = map_to_conf(conf);
+
+ if (aconf->dns_pending)
+ delete_resolver_queries(aconf);
+ if (aconf->passwd != NULL)
+ memset(aconf->passwd, 0, strlen(aconf->passwd));
+ if (aconf->spasswd != NULL)
+ memset(aconf->spasswd, 0, strlen(aconf->spasswd));
+ aconf->class_ptr = NULL;
+
+ MyFree(aconf->passwd);
+ MyFree(aconf->spasswd);
+ MyFree(aconf->reason);
+ MyFree(aconf->oper_reason);
+ MyFree(aconf->user);
+ MyFree(aconf->host);
+#ifdef HAVE_LIBCRYPTO
+ MyFree(aconf->cipher_list);
+
+ if (aconf->rsa_public_key)
+ RSA_free(aconf->rsa_public_key);
+ MyFree(aconf->rsa_public_key_file);
+#endif
+
+ /* Yes, sigh. switch on type again */
+ switch(type)
+ {
+ case EXEMPTDLINE_TYPE:
+ case DLINE_TYPE:
+ case GLINE_TYPE:
+ case KLINE_TYPE:
+ case CLIENT_TYPE:
+ MyFree(conf);
+ break;
+
+ case OPER_TYPE:
+ aconf = map_to_conf(conf);
+ if (!IsConfIllegal(aconf))
+ dlinkDelete(&conf->node, &oconf_items);
+ MyFree(conf);
+ break;
+
+ case SERVER_TYPE:
+ aconf = map_to_conf(conf);
+
+ DLINK_FOREACH_SAFE(m, m_next, aconf->hub_list.head)
+ {
+ MyFree(m->data);
+ free_dlink_node(m);
+ }
+
+ DLINK_FOREACH_SAFE(m, m_next, aconf->leaf_list.head)
+ {
+ MyFree(m->data);
+ free_dlink_node(m);
+ }
+
+ if (!IsConfIllegal(aconf))
+ dlinkDelete(&conf->node, &server_items);
+ MyFree(conf);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case ULINE_TYPE:
+ match_item = map_to_conf(conf);
+ MyFree(match_item->user);
+ MyFree(match_item->host);
+ MyFree(match_item->reason);
+ MyFree(match_item->oper_reason);
+ dlinkDelete(&conf->node, &uconf_items);
+ MyFree(conf);
+ break;
+
+ case XLINE_TYPE:
+ match_item = map_to_conf(conf);
+ MyFree(match_item->user);
+ MyFree(match_item->host);
+ MyFree(match_item->reason);
+ MyFree(match_item->oper_reason);
+ dlinkDelete(&conf->node, &xconf_items);
+ MyFree(conf);
+ break;
+#ifdef HAVE_LIBPCRE
+ case RKLINE_TYPE:
+ aconf = map_to_conf(conf);
+ MyFree(aconf->regexuser);
+ MyFree(aconf->regexhost);
+ MyFree(aconf->user);
+ MyFree(aconf->host);
+ MyFree(aconf->reason);
+ MyFree(aconf->oper_reason);
+ dlinkDelete(&conf->node, &rkconf_items);
+ MyFree(conf);
+ break;
+
+ case RXLINE_TYPE:
+ MyFree(conf->regexpname);
+ match_item = map_to_conf(conf);
+ MyFree(match_item->user);
+ MyFree(match_item->host);
+ MyFree(match_item->reason);
+ MyFree(match_item->oper_reason);
+ dlinkDelete(&conf->node, &rxconf_items);
+ MyFree(conf);
+ break;
+#endif
+ case NRESV_TYPE:
+ match_item = map_to_conf(conf);
+ MyFree(match_item->user);
+ MyFree(match_item->host);
+ MyFree(match_item->reason);
+ MyFree(match_item->oper_reason);
+ dlinkDelete(&conf->node, &nresv_items);
+
+ if (conf->flags & CONF_FLAGS_TEMPORARY)
+ if ((m = dlinkFindDelete(&temporary_resv, conf)) != NULL)
+ free_dlink_node(m);
+
+ MyFree(conf);
+ break;
+
+ case CLUSTER_TYPE:
+ dlinkDelete(&conf->node, &cluster_items);
+ MyFree(conf);
+ break;
+
+ case CRESV_TYPE:
+ if (conf->flags & CONF_FLAGS_TEMPORARY)
+ if ((m = dlinkFindDelete(&temporary_resv, conf)) != NULL)
+ free_dlink_node(m);
+
+ MyFree(conf);
+ break;
+
+ case CLASS_TYPE:
+ dlinkDelete(&conf->node, &class_items);
+ MyFree(conf);
+ break;
+
+ case SERVICE_TYPE:
+ dlinkDelete(&conf->node, &service_items);
+ MyFree(conf);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* free_access_item()
+ *
+ * inputs - pointer to conf to free
+ * output - none
+ * side effects - crucial password fields are zeroed, conf is freed
+ */
+void
+free_access_item(struct AccessItem *aconf)
+{
+ struct ConfItem *conf;
+
+ if (aconf == NULL)
+ return;
+ conf = unmap_conf_item(aconf);
+ delete_conf_item(conf);
+}
+
+static const unsigned int shared_bit_table[] =
+ { 'K', 'k', 'U', 'X', 'x', 'Y', 'Q', 'q', 'R', 'L', 0};
+
+/* report_confitem_types()
+ *
+ * inputs - pointer to client requesting confitem report
+ * - ConfType to report
+ * output - none
+ * side effects -
+ */
+void
+report_confitem_types(struct Client *source_p, ConfType type)
+{
+ dlink_node *ptr = NULL, *dptr = NULL;
+ struct ConfItem *conf = NULL;
+ struct AccessItem *aconf = NULL;
+ struct MatchItem *matchitem = NULL;
+ struct ClassItem *classitem = NULL;
+ char buf[12];
+ char *p = NULL;
+
+ switch (type)
+ {
+ case XLINE_TYPE:
+ DLINK_FOREACH(ptr, xconf_items.head)
+ {
+ conf = ptr->data;
+ matchitem = map_to_conf(conf);
+
+ sendto_one(source_p, form_str(RPL_STATSXLINE),
+ me.name, source_p->name,
+ matchitem->hold ? "x": "X", matchitem->count,
+ conf->name, matchitem->reason);
+ }
+ break;
+
+#ifdef HAVE_LIBPCRE
+ case RXLINE_TYPE:
+ DLINK_FOREACH(ptr, rxconf_items.head)
+ {
+ conf = ptr->data;
+ matchitem = map_to_conf(conf);
+
+ sendto_one(source_p, form_str(RPL_STATSXLINE),
+ me.name, source_p->name,
+ "XR", matchitem->count,
+ conf->name, matchitem->reason);
+ }
+ break;
+
+ case RKLINE_TYPE:
+ DLINK_FOREACH(ptr, rkconf_items.head)
+ {
+ aconf = map_to_conf((conf = ptr->data));
+
+ sendto_one(source_p, form_str(RPL_STATSKLINE), me.name,
+ source_p->name, "KR", aconf->host, aconf->user,
+ aconf->reason, aconf->oper_reason ? aconf->oper_reason : "");
+ }
+ break;
+#endif
+
+ case ULINE_TYPE:
+ DLINK_FOREACH(ptr, uconf_items.head)
+ {
+ conf = ptr->data;
+ matchitem = map_to_conf(conf);
+
+ p = buf;
+
+ /* some of these are redundant for the sake of
+ * consistency with cluster{} flags
+ */
+ *p++ = 'c';
+ flags_to_ascii(matchitem->action, shared_bit_table, p, 0);
+
+ sendto_one(source_p, form_str(RPL_STATSULINE),
+ me.name, source_p->name, conf->name,
+ matchitem->user?matchitem->user: "*",
+ matchitem->host?matchitem->host: "*", buf);
+ }
+
+ DLINK_FOREACH(ptr, cluster_items.head)
+ {
+ conf = ptr->data;
+
+ p = buf;
+
+ *p++ = 'C';
+ flags_to_ascii(conf->flags, shared_bit_table, p, 0);
+
+ sendto_one(source_p, form_str(RPL_STATSULINE),
+ me.name, source_p->name, conf->name,
+ "*", "*", buf);
+ }
+
+ break;
+
+ case OPER_TYPE:
+ DLINK_FOREACH(ptr, oconf_items.head)
+ {
+ conf = ptr->data;
+ aconf = map_to_conf(conf);
+
+ /* Don't allow non opers to see oper privs */
+ if (HasUMode(source_p, UMODE_OPER))
+ sendto_one(source_p, form_str(RPL_STATSOLINE),
+ me.name, source_p->name, 'O', aconf->user, aconf->host,
+ conf->name, oper_privs_as_string(aconf->port),
+ aconf->class_ptr ? aconf->class_ptr->name : "<default>");
+ else
+ sendto_one(source_p, form_str(RPL_STATSOLINE),
+ me.name, source_p->name, 'O', aconf->user, aconf->host,
+ conf->name, "0",
+ aconf->class_ptr ? aconf->class_ptr->name : "<default>");
+ }
+ break;
+
+ case CLASS_TYPE:
+ DLINK_FOREACH(ptr, class_items.head)
+ {
+ conf = ptr->data;
+ classitem = map_to_conf(conf);
+ sendto_one(source_p, form_str(RPL_STATSYLINE),
+ me.name, source_p->name, 'Y',
+ conf->name, classitem->ping_freq,
+ classitem->con_freq,
+ classitem->max_total, classitem->max_sendq,
+ classitem->max_recvq,
+ classitem->curr_user_count,
+ classitem->number_per_cidr, classitem->cidr_bitlen_ipv4,
+ classitem->number_per_cidr, classitem->cidr_bitlen_ipv6,
+ classitem->active ? "active" : "disabled");
+ }
+ break;
+
+ case CONF_TYPE:
+ case CLIENT_TYPE:
+ break;
+
+ case SERVICE_TYPE:
+ DLINK_FOREACH(ptr, service_items.head)
+ {
+ conf = ptr->data;
+ sendto_one(source_p, form_str(RPL_STATSSERVICE),
+ me.name, source_p->name, 'S', "*", conf->name, 0, 0);
+ }
+ break;
+
+ case SERVER_TYPE:
+ DLINK_FOREACH(ptr, server_items.head)
+ {
+ p = buf;
+
+ conf = ptr->data;
+ aconf = map_to_conf(conf);
+
+ buf[0] = '\0';
+
+ if (IsConfAllowAutoConn(aconf))
+ *p++ = 'A';
+ if (IsConfSSL(aconf))
+ *p++ = 'S';
+ if (buf[0] == '\0')
+ *p++ = '*';
+
+ *p = '\0';
+
+ /*
+ * Allow admins to see actual ips unless hide_server_ips is enabled
+ */
+ if (!ConfigServerHide.hide_server_ips && HasUMode(source_p, UMODE_ADMIN))
+ sendto_one(source_p, form_str(RPL_STATSCLINE),
+ me.name, source_p->name, 'C', aconf->host,
+ buf, conf->name, aconf->port,
+ aconf->class_ptr ? aconf->class_ptr->name : "<default>");
+ else
+ sendto_one(source_p, form_str(RPL_STATSCLINE),
+ me.name, source_p->name, 'C',
+ "*@127.0.0.1", buf, conf->name, aconf->port,
+ aconf->class_ptr ? aconf->class_ptr->name : "<default>");
+ }
+ break;
+
+ case HUB_TYPE:
+ DLINK_FOREACH(ptr, server_items.head)
+ {
+ conf = ptr->data;
+ aconf = map_to_conf(conf);
+
+ DLINK_FOREACH(dptr, aconf->hub_list.head)
+ sendto_one(source_p, form_str(RPL_STATSHLINE), me.name,
+ source_p->name, 'H', dptr->data, conf->name, 0, "*");
+ }
+ break;
+
+ case LEAF_TYPE:
+ DLINK_FOREACH(ptr, server_items.head)
+ {
+ conf = ptr->data;
+ aconf = map_to_conf(conf);
+
+ DLINK_FOREACH(dptr, aconf->leaf_list.head)
+ sendto_one(source_p, form_str(RPL_STATSLLINE), me.name,
+ source_p->name, 'L', dptr->data, conf->name, 0, "*");
+ }
+ break;
+
+ case GLINE_TYPE:
+ case KLINE_TYPE:
+ case DLINE_TYPE:
+ case EXEMPTDLINE_TYPE:
+ case CRESV_TYPE:
+ case NRESV_TYPE:
+ case CLUSTER_TYPE:
+ default:
+ break;
+ }
+}
+
+/* check_client()
+ *
+ * inputs - pointer to client
+ * output - 0 = Success
+ * NOT_AUTHORIZED (-1) = Access denied (no I line match)
+ * IRCD_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.
+ */
+static void *
+check_client(va_list args)
+{
+ struct Client *source_p = va_arg(args, struct Client *);
+ const char *username = va_arg(args, const char *);
+ int i;
+
+ /* I'm already in big trouble if source_p->localClient is NULL -db */
+ if ((i = verify_access(source_p, username)))
+ ilog(LOG_TYPE_IRCD, "Access denied: %s[%s]",
+ source_p->name, source_p->sockhost);
+
+ switch (i)
+ {
+ case TOO_MANY:
+ sendto_realops_flags(UMODE_FULL, L_ALL,
+ "Too many on IP for %s (%s).",
+ get_client_name(source_p, SHOW_IP),
+ source_p->sockhost);
+ ilog(LOG_TYPE_IRCD, "Too many connections on IP from %s.",
+ get_client_name(source_p, SHOW_IP));
+ ++ServerStats.is_ref;
+ exit_client(source_p, &me, "No more connections allowed on that IP");
+ break;
+
+ case I_LINE_FULL:
+ sendto_realops_flags(UMODE_FULL, L_ALL,
+ "I-line is full for %s (%s).",
+ get_client_name(source_p, SHOW_IP),
+ source_p->sockhost);
+ ilog(LOG_TYPE_IRCD, "Too many connections from %s.",
+ get_client_name(source_p, SHOW_IP));
+ ++ServerStats.is_ref;
+ exit_client(source_p, &me,
+ "No more connections allowed in your connection class");
+ break;
+
+ case NOT_AUTHORIZED:
+ ++ServerStats.is_ref;
+ /* jdc - lists server name & port connections are on */
+ /* a purely cosmetical change */
+ sendto_realops_flags(UMODE_UNAUTH, L_ALL,
+ "Unauthorized client connection from %s [%s] on [%s/%u].",
+ get_client_name(source_p, SHOW_IP),
+ source_p->sockhost,
+ source_p->localClient->listener->name,
+ source_p->localClient->listener->port);
+ ilog(LOG_TYPE_IRCD,
+ "Unauthorized client connection from %s on [%s/%u].",
+ get_client_name(source_p, SHOW_IP),
+ source_p->localClient->listener->name,
+ source_p->localClient->listener->port);
+
+ exit_client(source_p, &me, "You are not authorized to use this server");
+ break;
+
+ case BANNED_CLIENT:
+ exit_client(source_p, &me, "Banned");
+ ++ServerStats.is_ref;
+ break;
+
+ case 0:
+ default:
+ break;
+ }
+
+ return (i < 0 ? NULL : source_p);
+}
+
+/* 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 AccessItem *aconf = NULL, *rkconf = NULL;
+ struct ConfItem *conf = NULL;
+ char non_ident[USERLEN + 1] = { '~', '\0' };
+ const char *uhi[3];
+
+ if (IsGotId(client_p))
+ {
+ aconf = find_address_conf(client_p->host, client_p->username,
+ &client_p->localClient->ip,
+ client_p->localClient->aftype,
+ client_p->localClient->passwd);
+ }
+ else
+ {
+ strlcpy(non_ident+1, username, sizeof(non_ident)-1);
+ aconf = find_address_conf(client_p->host,non_ident,
+ &client_p->localClient->ip,
+ client_p->localClient->aftype,
+ client_p->localClient->passwd);
+ }
+
+ uhi[0] = IsGotId(client_p) ? client_p->username : non_ident;
+ uhi[1] = client_p->host;
+ uhi[2] = client_p->sockhost;
+
+ rkconf = find_regexp_kline(uhi);
+
+ if (aconf != NULL)
+ {
+ if (IsConfClient(aconf) && !rkconf)
+ {
+ conf = unmap_conf_item(aconf);
+
+ if (IsConfRedir(aconf))
+ {
+ sendto_one(client_p, form_str(RPL_REDIR),
+ me.name, client_p->name,
+ conf->name ? conf->name : "",
+ aconf->port);
+ return(NOT_AUTHORIZED);
+ }
+
+ if (IsConfDoIdentd(aconf))
+ SetNeedId(client_p);
+
+ /* Thanks for spoof idea amm */
+ if (IsConfDoSpoofIp(aconf))
+ {
+ conf = unmap_conf_item(aconf);
+
+ if (!ConfigFileEntry.hide_spoof_ips && IsConfSpoofNotice(aconf))
+ sendto_realops_flags(UMODE_ALL, L_ADMIN, "%s spoofing: %s as %s",
+ client_p->name, client_p->host, conf->name);
+ strlcpy(client_p->host, conf->name, sizeof(client_p->host));
+ SetIPSpoof(client_p);
+ }
+
+ return(attach_iline(client_p, conf));
+ }
+ else if (rkconf || IsConfKill(aconf) || (ConfigFileEntry.glines && IsConfGline(aconf)))
+ {
+ /* XXX */
+ aconf = rkconf ? rkconf : aconf;
+ if (IsConfGline(aconf))
+ sendto_one(client_p, ":%s NOTICE %s :*** G-lined", me.name,
+ client_p->name);
+ sendto_one(client_p, ":%s NOTICE %s :*** Banned: %s",
+ me.name, client_p->name, aconf->reason);
+ return(BANNED_CLIENT);
+ }
+ }
+
+ return(NOT_AUTHORIZED);
+}
+
+/* attach_iline()
+ *
+ * inputs - client pointer
+ * - conf pointer
+ * output -
+ * side effects - do actual attach
+ */
+static int
+attach_iline(struct Client *client_p, struct ConfItem *conf)
+{
+ struct AccessItem *aconf;
+ struct ClassItem *aclass;
+ struct ip_entry *ip_found;
+ int a_limit_reached = 0;
+ int local = 0, global = 0, ident = 0;
+
+ ip_found = find_or_add_ip(&client_p->localClient->ip);
+ ip_found->count++;
+ SetIpHash(client_p);
+
+ aconf = map_to_conf(conf);
+ if (aconf->class_ptr == NULL)
+ return NOT_AUTHORIZED; /* If class is missing, this is best */
+
+ aclass = map_to_conf(aconf->class_ptr);
+
+ count_user_host(client_p->username, client_p->host,
+ &global, &local, &ident);
+
+ /* XXX blah. go down checking the various silly limits
+ * setting a_limit_reached if any limit is reached.
+ * - Dianora
+ */
+ if (aclass->max_total != 0 && aclass->curr_user_count >= aclass->max_total)
+ a_limit_reached = 1;
+ else if (aclass->max_perip != 0 && ip_found->count > aclass->max_perip)
+ a_limit_reached = 1;
+ else if (aclass->max_local != 0 && local >= aclass->max_local)
+ a_limit_reached = 1;
+ else if (aclass->max_global != 0 && global >= aclass->max_global)
+ a_limit_reached = 1;
+ else if (aclass->max_ident != 0 && ident >= aclass->max_ident &&
+ client_p->username[0] != '~')
+ a_limit_reached = 1;
+
+ if (a_limit_reached)
+ {
+ if (!IsConfExemptLimits(aconf))
+ return TOO_MANY; /* Already at maximum allowed */
+
+ sendto_one(client_p,
+ ":%s NOTICE %s :*** Your connection class is full, "
+ "but you have exceed_limit = yes;", me.name, client_p->name);
+ }
+
+ return attach_conf(client_p, conf);
+}
+
+/* init_ip_hash_table()
+ *
+ * inputs - NONE
+ * output - NONE
+ * side effects - allocate memory for ip_entry(s)
+ * - clear the ip hash table
+ */
+void
+init_ip_hash_table(void)
+{
+ ip_entry_heap = BlockHeapCreate("ip", sizeof(struct ip_entry),
+ 2 * hard_fdlimit);
+ memset(ip_hash_table, 0, sizeof(ip_hash_table));
+}
+
+/* find_or_add_ip()
+ *
+ * inputs - pointer to struct irc_ssaddr
+ * output - pointer to a struct ip_entry
+ * side effects -
+ *
+ * If the ip # was not found, a new struct ip_entry is created, and the ip
+ * count set to 0.
+ */
+static struct ip_entry *
+find_or_add_ip(struct irc_ssaddr *ip_in)
+{
+ struct ip_entry *ptr, *newptr;
+ int hash_index = hash_ip(ip_in), res;
+ struct sockaddr_in *v4 = (struct sockaddr_in *)ip_in, *ptr_v4;
+#ifdef IPV6
+ struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)ip_in, *ptr_v6;
+#endif
+
+ for (ptr = ip_hash_table[hash_index]; ptr; ptr = ptr->next)
+ {
+#ifdef IPV6
+ if (ptr->ip.ss.ss_family != ip_in->ss.ss_family)
+ continue;
+ if (ip_in->ss.ss_family == AF_INET6)
+ {
+ ptr_v6 = (struct sockaddr_in6 *)&ptr->ip;
+ res = memcmp(&v6->sin6_addr, &ptr_v6->sin6_addr, sizeof(struct in6_addr));
+ }
+ else
+#endif
+ {
+ ptr_v4 = (struct sockaddr_in *)&ptr->ip;
+ res = memcmp(&v4->sin_addr, &ptr_v4->sin_addr, sizeof(struct in_addr));
+ }
+ if (res == 0)
+ {
+ /* Found entry already in hash, return it. */
+ return ptr;
+ }
+ }
+
+ if (ip_entries_count >= 2 * hard_fdlimit)
+ garbage_collect_ip_entries();
+
+ newptr = BlockHeapAlloc(ip_entry_heap);
+ ip_entries_count++;
+ memcpy(&newptr->ip, ip_in, sizeof(struct irc_ssaddr));
+
+ newptr->next = ip_hash_table[hash_index];
+ ip_hash_table[hash_index] = newptr;
+
+ return newptr;
+}
+
+/* remove_one_ip()
+ *
+ * inputs - unsigned long IP address value
+ * output - NONE
+ * side effects - The ip address given, is looked up in ip hash table
+ * and number of ip#'s for that ip decremented.
+ * If ip # count reaches 0 and has expired,
+ * the struct ip_entry is returned to the ip_entry_heap
+ */
+void
+remove_one_ip(struct irc_ssaddr *ip_in)
+{
+ struct ip_entry *ptr;
+ struct ip_entry *last_ptr = NULL;
+ int hash_index = hash_ip(ip_in), res;
+ struct sockaddr_in *v4 = (struct sockaddr_in *)ip_in, *ptr_v4;
+#ifdef IPV6
+ struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)ip_in, *ptr_v6;
+#endif
+
+ for (ptr = ip_hash_table[hash_index]; ptr; ptr = ptr->next)
+ {
+#ifdef IPV6
+ if (ptr->ip.ss.ss_family != ip_in->ss.ss_family)
+ continue;
+ if (ip_in->ss.ss_family == AF_INET6)
+ {
+ ptr_v6 = (struct sockaddr_in6 *)&ptr->ip;
+ res = memcmp(&v6->sin6_addr, &ptr_v6->sin6_addr, sizeof(struct in6_addr));
+ }
+ else
+#endif
+ {
+ ptr_v4 = (struct sockaddr_in *)&ptr->ip;
+ res = memcmp(&v4->sin_addr, &ptr_v4->sin_addr, sizeof(struct in_addr));
+ }
+ if (res)
+ continue;
+ if (ptr->count > 0)
+ ptr->count--;
+ if (ptr->count == 0 &&
+ (CurrentTime-ptr->last_attempt) >= ConfigFileEntry.throttle_time)
+ {
+ if (last_ptr != NULL)
+ last_ptr->next = ptr->next;
+ else
+ ip_hash_table[hash_index] = ptr->next;
+
+ BlockHeapFree(ip_entry_heap, ptr);
+ ip_entries_count--;
+ return;
+ }
+ last_ptr = ptr;
+ }
+}
+
+/* hash_ip()
+ *
+ * input - pointer to an irc_inaddr
+ * output - integer value used as index into hash table
+ * side effects - hopefully, none
+ */
+static int
+hash_ip(struct irc_ssaddr *addr)
+{
+ if (addr->ss.ss_family == AF_INET)
+ {
+ struct sockaddr_in *v4 = (struct sockaddr_in *)addr;
+ int hash;
+ uint32_t ip;
+
+ ip = ntohl(v4->sin_addr.s_addr);
+ hash = ((ip >> 12) + ip) & (IP_HASH_SIZE-1);
+ return hash;
+ }
+#ifdef IPV6
+ else
+ {
+ int hash;
+ struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)addr;
+ uint32_t *ip = (uint32_t *)&v6->sin6_addr.s6_addr;
+
+ hash = ip[0] ^ ip[3];
+ hash ^= hash >> 16;
+ hash ^= hash >> 8;
+ hash = hash & (IP_HASH_SIZE - 1);
+ return hash;
+ }
+#else
+ return 0;
+#endif
+}
+
+/* count_ip_hash()
+ *
+ * inputs - pointer to counter of number of ips hashed
+ * - pointer to memory used for ip hash
+ * output - returned via pointers input
+ * side effects - NONE
+ *
+ * number of hashed ip #'s is counted up, plus the amount of memory
+ * used in the hash.
+ */
+void
+count_ip_hash(unsigned int *number_ips_stored, uint64_t *mem_ips_stored)
+{
+ struct ip_entry *ptr;
+ int i;
+
+ *number_ips_stored = 0;
+ *mem_ips_stored = 0;
+
+ for (i = 0; i < IP_HASH_SIZE; i++)
+ {
+ for (ptr = ip_hash_table[i]; ptr; ptr = ptr->next)
+ {
+ *number_ips_stored += 1;
+ *mem_ips_stored += sizeof(struct ip_entry);
+ }
+ }
+}
+
+/* garbage_collect_ip_entries()
+ *
+ * input - NONE
+ * output - NONE
+ * side effects - free up all ip entries with no connections
+ */
+static void
+garbage_collect_ip_entries(void)
+{
+ struct ip_entry *ptr;
+ struct ip_entry *last_ptr;
+ struct ip_entry *next_ptr;
+ int i;
+
+ for (i = 0; i < IP_HASH_SIZE; i++)
+ {
+ last_ptr = NULL;
+
+ for (ptr = ip_hash_table[i]; ptr; ptr = next_ptr)
+ {
+ next_ptr = ptr->next;
+
+ if (ptr->count == 0 &&
+ (CurrentTime - ptr->last_attempt) >= ConfigFileEntry.throttle_time)
+ {
+ if (last_ptr != NULL)
+ last_ptr->next = ptr->next;
+ else
+ ip_hash_table[i] = ptr->next;
+ BlockHeapFree(ip_entry_heap, ptr);
+ ip_entries_count--;
+ }
+ else
+ last_ptr = ptr;
+ }
+ }
+}
+
+/* detach_conf()
+ *
+ * inputs - pointer to client to detach
+ * - type of conf 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, ConfType type)
+{
+ dlink_node *ptr, *next_ptr;
+ struct ConfItem *conf;
+ struct ClassItem *aclass;
+ struct AccessItem *aconf;
+ struct ConfItem *aclass_conf;
+
+ DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->localClient->confs.head)
+ {
+ conf = ptr->data;
+
+ if (type == CONF_TYPE || conf->type == type)
+ {
+ dlinkDelete(ptr, &client_p->localClient->confs);
+ free_dlink_node(ptr);
+
+ switch (conf->type)
+ {
+ case CLIENT_TYPE:
+ case OPER_TYPE:
+ case SERVER_TYPE:
+ aconf = map_to_conf(conf);
+
+ assert(aconf->clients > 0);
+
+ if ((aclass_conf = aconf->class_ptr) != NULL)
+ {
+ aclass = map_to_conf(aclass_conf);
+
+ assert(aclass->curr_user_count > 0);
+
+ if (conf->type == CLIENT_TYPE)
+ remove_from_cidr_check(&client_p->localClient->ip, aclass);
+ if (--aclass->curr_user_count == 0 && aclass->active == 0)
+ delete_conf_item(aclass_conf);
+ }
+
+ if (--aconf->clients == 0 && IsConfIllegal(aconf))
+ delete_conf_item(conf);
+
+ break;
+ default:
+ break;
+ }
+
+ if (type != CONF_TYPE)
+ 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 *conf)
+{
+ struct AccessItem *aconf = map_to_conf(conf);
+ struct ClassItem *aclass = map_to_conf(aconf->class_ptr);
+
+ if (dlinkFind(&client_p->localClient->confs, conf) != NULL)
+ return 1;
+
+ if (IsConfIllegal(aconf)) /* TBV: can't happen */
+ return NOT_AUTHORIZED;
+
+ if (conf->type == CLIENT_TYPE)
+ if (cidr_limit_reached(IsConfExemptLimits(aconf),
+ &client_p->localClient->ip, aclass))
+ return TOO_MANY; /* Already at maximum allowed */
+
+ aclass->curr_user_count++;
+ aconf->clients++;
+
+ dlinkAdd(conf, make_dlink_node(), &client_p->localClient->confs);
+
+ return 0;
+}
+
+/* attach_connect_block()
+ *
+ * inputs - pointer to server to attach
+ * - name of server
+ * - hostname of server
+ * output - true (1) if both are found, otherwise return false (0)
+ * side effects - find connect block and attach them to connecting client
+ */
+int
+attach_connect_block(struct Client *client_p, const char *name,
+ const char *host)
+{
+ dlink_node *ptr;
+ struct ConfItem *conf;
+ struct AccessItem *aconf;
+
+ assert(client_p != NULL);
+ assert(host != NULL);
+
+ if (client_p == NULL || host == NULL)
+ return 0;
+
+ DLINK_FOREACH(ptr, server_items.head)
+ {
+ conf = ptr->data;
+ aconf = map_to_conf(conf);
+
+ if (match(conf->name, name) == 0 || match(aconf->host, host) == 0)
+ continue;
+
+ attach_conf(client_p, conf);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* find_conf_exact()
+ *
+ * inputs - type of ConfItem
+ * - pointer to name to find
+ * - pointer to username to find
+ * - pointer to host to find
+ * output - NULL or pointer to conf found
+ * side effects - find a conf entry which matches the hostname
+ * and has the same name.
+ */
+struct ConfItem *
+find_conf_exact(ConfType type, const char *name, const char *user,
+ const char *host)
+{
+ dlink_node *ptr;
+ dlink_list *list_p;
+ struct ConfItem *conf = NULL;
+ struct AccessItem *aconf;
+
+ /* Only valid for OPER_TYPE and ...? */
+ list_p = map_to_list(type);
+
+ DLINK_FOREACH(ptr, (*list_p).head)
+ {
+ conf = ptr->data;
+
+ if (conf->name == NULL)
+ continue;
+ aconf = map_to_conf(conf);
+ if (aconf->host == NULL)
+ continue;
+ if (irccmp(conf->name, name) != 0)
+ continue;
+
+ /*
+ ** Accept if the *real* hostname (usually sockethost)
+ ** socket host) matches *either* host or name field
+ ** of the configuration.
+ */
+ if (!match(aconf->host, host) || !match(aconf->user, user))
+ continue;
+ if (type == OPER_TYPE)
+ {
+ struct ClassItem *aclass = map_to_conf(aconf->class_ptr);
+
+ if (aconf->clients >= aclass->max_total)
+ continue;
+ }
+
+ return conf;
+ }
+
+ return NULL;
+}
+
+/* find_conf_name()
+ *
+ * inputs - pointer to conf link list to search
+ * - pointer to name to find
+ * - int mask of type of conf to find
+ * output - NULL or pointer to conf found
+ * side effects - find a conf entry which matches the name
+ * and has the given mask.
+ */
+struct ConfItem *
+find_conf_name(dlink_list *list, const char *name, ConfType type)
+{
+ dlink_node *ptr;
+ struct ConfItem* conf;
+
+ DLINK_FOREACH(ptr, list->head)
+ {
+ conf = ptr->data;
+
+ if (conf->type == type)
+ {
+ if (conf->name && (irccmp(conf->name, name) == 0 ||
+ match(conf->name, name)))
+ return conf;
+ }
+ }
+
+ return NULL;
+}
+
+/* map_to_list()
+ *
+ * inputs - ConfType conf
+ * output - pointer to dlink_list to use
+ * side effects - none
+ */
+static dlink_list *
+map_to_list(ConfType type)
+{
+ switch(type)
+ {
+ case RXLINE_TYPE:
+ return(&rxconf_items);
+ break;
+ case XLINE_TYPE:
+ return(&xconf_items);
+ break;
+ case ULINE_TYPE:
+ return(&uconf_items);
+ break;
+ case NRESV_TYPE:
+ return(&nresv_items);
+ break;
+ case OPER_TYPE:
+ return(&oconf_items);
+ break;
+ case CLASS_TYPE:
+ return(&class_items);
+ break;
+ case SERVER_TYPE:
+ return(&server_items);
+ break;
+ case SERVICE_TYPE:
+ return(&service_items);
+ break;
+ case CLUSTER_TYPE:
+ return(&cluster_items);
+ break;
+ case CONF_TYPE:
+ case GLINE_TYPE:
+ case KLINE_TYPE:
+ case DLINE_TYPE:
+ case CRESV_TYPE:
+ default:
+ return NULL;
+ }
+}
+
+/* find_matching_name_conf()
+ *
+ * inputs - type of link list to look in
+ * - pointer to name string to find
+ * - pointer to user
+ * - pointer to host
+ * - optional action to match on as well
+ * output - NULL or pointer to found struct MatchItem
+ * side effects - looks for a match on name field
+ */
+struct ConfItem *
+find_matching_name_conf(ConfType type, const char *name, const char *user,
+ const char *host, int action)
+{
+ dlink_node *ptr=NULL;
+ struct ConfItem *conf=NULL;
+ struct AccessItem *aconf=NULL;
+ struct MatchItem *match_item=NULL;
+ dlink_list *list_p = map_to_list(type);
+
+ switch (type)
+ {
+#ifdef HAVE_LIBPCRE
+ case RXLINE_TYPE:
+ DLINK_FOREACH(ptr, list_p->head)
+ {
+ conf = ptr->data;
+ assert(conf->regexpname);
+
+ if (!ircd_pcre_exec(conf->regexpname, name))
+ return conf;
+ }
+ break;
+#endif
+ case SERVICE_TYPE:
+ DLINK_FOREACH(ptr, list_p->head)
+ {
+ conf = ptr->data;
+
+ if (EmptyString(conf->name))
+ continue;
+ if ((name != NULL) && !irccmp(name, conf->name))
+ return conf;
+ }
+ break;
+
+ case XLINE_TYPE:
+ case ULINE_TYPE:
+ case NRESV_TYPE:
+ DLINK_FOREACH(ptr, list_p->head)
+ {
+ conf = ptr->data;
+
+ match_item = map_to_conf(conf);
+ if (EmptyString(conf->name))
+ continue;
+ if ((name != NULL) && match_esc(conf->name, name))
+ {
+ if ((user == NULL && (host == NULL)))
+ return conf;
+ if ((match_item->action & action) != action)
+ continue;
+ if (EmptyString(match_item->user) || EmptyString(match_item->host))
+ return conf;
+ if (match(match_item->user, user) && match(match_item->host, host))
+ return conf;
+ }
+ }
+ break;
+
+ case SERVER_TYPE:
+ DLINK_FOREACH(ptr, list_p->head)
+ {
+ conf = ptr->data;
+ aconf = map_to_conf(conf);
+
+ if ((name != NULL) && match_esc(name, conf->name))
+ return conf;
+ else if ((host != NULL) && match_esc(host, aconf->host))
+ return conf;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return NULL;
+}
+
+/* find_exact_name_conf()
+ *
+ * inputs - type of link list to look in
+ * - pointer to name string to find
+ * - pointer to user
+ * - pointer to host
+ * output - NULL or pointer to found struct MatchItem
+ * side effects - looks for an exact match on name field
+ */
+struct ConfItem *
+find_exact_name_conf(ConfType type, const struct Client *who, const char *name,
+ const char *user, const char *host)
+{
+ dlink_node *ptr = NULL;
+ struct AccessItem *aconf;
+ struct ConfItem *conf;
+ struct MatchItem *match_item;
+ dlink_list *list_p;
+
+ list_p = map_to_list(type);
+
+ switch(type)
+ {
+ case RXLINE_TYPE:
+ case XLINE_TYPE:
+ case ULINE_TYPE:
+ case NRESV_TYPE:
+
+ DLINK_FOREACH(ptr, list_p->head)
+ {
+ conf = ptr->data;
+ match_item = (struct MatchItem *)map_to_conf(conf);
+ if (EmptyString(conf->name))
+ continue;
+
+ if (irccmp(conf->name, name) == 0)
+ {
+ if ((user == NULL && (host == NULL)))
+ return (conf);
+ if (EmptyString(match_item->user) || EmptyString(match_item->host))
+ return (conf);
+ if (match(match_item->user, user) && match(match_item->host, host))
+ return (conf);
+ }
+ }
+ break;
+
+ case OPER_TYPE:
+ DLINK_FOREACH(ptr, list_p->head)
+ {
+ conf = ptr->data;
+ aconf = map_to_conf(conf);
+
+ if (EmptyString(conf->name))
+ continue;
+
+ if (!irccmp(conf->name, name))
+ {
+ if (!who)
+ return conf;
+ if (EmptyString(aconf->user) || EmptyString(aconf->host))
+ return conf;
+ if (match(aconf->user, who->username))
+ {
+ switch (aconf->type)
+ {
+ case HM_HOST:
+ if (match(aconf->host, who->host) || match(aconf->host, who->sockhost))
+ return conf;
+ break;
+ case HM_IPV4:
+ if (who->localClient->aftype == AF_INET)
+ if (match_ipv4(&who->localClient->ip, &aconf->addr, aconf->bits))
+ return conf;
+ break;
+#ifdef IPV6
+ case HM_IPV6:
+ if (who->localClient->aftype == AF_INET6)
+ if (match_ipv6(&who->localClient->ip, &aconf->addr, aconf->bits))
+ return conf;
+ break;
+#endif
+ default:
+ assert(0);
+ }
+ }
+ }
+ }
+
+ break;
+
+ case SERVER_TYPE:
+ DLINK_FOREACH(ptr, list_p->head)
+ {
+ conf = ptr->data;
+ aconf = (struct AccessItem *)map_to_conf(conf);
+ if (EmptyString(conf->name))
+ continue;
+
+ if (name == NULL)
+ {
+ if (EmptyString(aconf->host))
+ continue;
+ if (irccmp(aconf->host, host) == 0)
+ return(conf);
+ }
+ else if (irccmp(conf->name, name) == 0)
+ {
+ return (conf);
+ }
+ }
+ break;
+
+ case CLASS_TYPE:
+ DLINK_FOREACH(ptr, list_p->head)
+ {
+ conf = ptr->data;
+ if (EmptyString(conf->name))
+ continue;
+
+ if (irccmp(conf->name, name) == 0)
+ return (conf);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return(NULL);
+}
+
+/* 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_flags(UMODE_ALL, 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 */
+
+ /* Check to see if we magically got(or lost) IPv6 support */
+ check_can_use_v6();
+
+ read_conf_files(0);
+
+ if (ServerInfo.description != NULL)
+ strlcpy(me.info, ServerInfo.description, sizeof(me.info));
+
+ load_conf_modules();
+
+ flush_deleted_I_P();
+
+ rehashed_klines = 1;
+/* XXX */
+ if (ConfigLoggingEntry.use_logging)
+ log_close_all();
+
+ return(0);
+}
+
+/* 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().
+ */
+static void
+set_default_conf(void)
+{
+ /* verify init_class() ran, this should be an unnecessary check
+ * but its not much work.
+ */
+ assert(class_default == (struct ConfItem *) class_items.tail->data);
+
+#ifdef HAVE_LIBCRYPTO
+ ServerInfo.rsa_private_key = NULL;
+ ServerInfo.rsa_private_key_file = NULL;
+#endif
+
+ /* 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;
+ memset(&ServerInfo.ip6, 0, sizeof(ServerInfo.ip6));
+ ServerInfo.specific_ipv6_vhost = 0;
+
+ ServerInfo.max_clients = MAXCLIENTS_MAX;
+
+ ServerInfo.hub = 0;
+ ServerInfo.dns_host.sin_addr.s_addr = 0;
+ ServerInfo.dns_host.sin_port = 0;
+ AdminInfo.name = NULL;
+ AdminInfo.email = NULL;
+ AdminInfo.description = NULL;
+
+ log_close_all();
+
+ ConfigLoggingEntry.use_logging = 1;
+
+ ConfigChannel.disable_fake_channels = 0;
+ ConfigChannel.restrict_channels = 0;
+ ConfigChannel.knock_delay = 300;
+ ConfigChannel.knock_delay_channel = 60;
+ ConfigChannel.max_chans_per_user = 25;
+ ConfigChannel.max_chans_per_oper = 50;
+ ConfigChannel.quiet_on_ban = 1;
+ ConfigChannel.max_bans = 25;
+ ConfigChannel.default_split_user_count = 0;
+ ConfigChannel.default_split_server_count = 0;
+ ConfigChannel.no_join_on_split = 0;
+ ConfigChannel.no_create_on_split = 0;
+
+ ConfigServerHide.flatten_links = 0;
+ ConfigServerHide.links_delay = 300;
+ ConfigServerHide.hidden = 0;
+ ConfigServerHide.hide_servers = 0;
+ DupString(ConfigServerHide.hidden_name, NETWORK_NAME_DEFAULT);
+ ConfigServerHide.hide_server_ips = 0;
+
+
+ DupString(ConfigFileEntry.service_name, SERVICE_NAME_DEFAULT);
+ ConfigFileEntry.max_watch = WATCHSIZE_DEFAULT;
+ ConfigFileEntry.glines = 0;
+ ConfigFileEntry.gline_time = 12 * 3600;
+ ConfigFileEntry.gline_request_time = GLINE_REQUEST_EXPIRE_DEFAULT;
+ ConfigFileEntry.gline_min_cidr = 16;
+ ConfigFileEntry.gline_min_cidr6 = 48;
+ ConfigFileEntry.invisible_on_connect = 1;
+ ConfigFileEntry.tkline_expire_notices = 1;
+ ConfigFileEntry.hide_spoof_ips = 1;
+ ConfigFileEntry.ignore_bogus_ts = 0;
+ ConfigFileEntry.disable_auth = 0;
+ ConfigFileEntry.disable_remote = 0;
+ ConfigFileEntry.kill_chase_time_limit = 90;
+ ConfigFileEntry.default_floodcount = 8;
+ ConfigFileEntry.failed_oper_notice = 1;
+ ConfigFileEntry.dots_in_ident = 0;
+ ConfigFileEntry.min_nonwildcard = 4;
+ ConfigFileEntry.min_nonwildcard_simple = 3;
+ ConfigFileEntry.max_accept = 20;
+ ConfigFileEntry.anti_nick_flood = 0;
+ ConfigFileEntry.max_nick_time = 20;
+ ConfigFileEntry.max_nick_changes = 5;
+ ConfigFileEntry.anti_spam_exit_message_time = 0;
+ ConfigFileEntry.ts_warn_delta = TS_WARN_DELTA_DEFAULT;
+ ConfigFileEntry.ts_max_delta = TS_MAX_DELTA_DEFAULT;
+ ConfigFileEntry.warn_no_nline = 1;
+ ConfigFileEntry.stats_o_oper_only = 0;
+ ConfigFileEntry.stats_k_oper_only = 1; /* masked */
+ ConfigFileEntry.stats_i_oper_only = 1; /* masked */
+ ConfigFileEntry.stats_P_oper_only = 0;
+ ConfigFileEntry.caller_id_wait = 60;
+ ConfigFileEntry.opers_bypass_callerid = 0;
+ ConfigFileEntry.pace_wait = 10;
+ ConfigFileEntry.pace_wait_simple = 1;
+ ConfigFileEntry.short_motd = 0;
+ ConfigFileEntry.ping_cookie = 0;
+ ConfigFileEntry.no_oper_flood = 0;
+ ConfigFileEntry.true_no_oper_flood = 0;
+ ConfigFileEntry.oper_pass_resv = 1;
+ ConfigFileEntry.max_targets = MAX_TARGETS_DEFAULT;
+ ConfigFileEntry.oper_only_umodes = UMODE_DEBUG;
+ ConfigFileEntry.oper_umodes = UMODE_BOTS | UMODE_LOCOPS | UMODE_SERVNOTICE |
+ UMODE_OPERWALL | UMODE_WALLOP;
+ ConfigFileEntry.use_egd = 0;
+ ConfigFileEntry.egdpool_path = NULL;
+ ConfigFileEntry.throttle_time = 10;
+}
+
+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 (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.service_name == NULL)
+ DupString(ConfigFileEntry.service_name, SERVICE_NAME_DEFAULT);
+
+ ConfigFileEntry.max_watch = IRCD_MAX(ConfigFileEntry.max_watch, WATCHSIZE_MIN);
+}
+
+/* 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 */
+ conf_parser_ctx.pass = 1;
+ yyparse(); /* pick up the classes first */
+
+ rewind(file);
+
+ conf_parser_ctx.pass = 2;
+ 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 */
+}
+
+/* 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.
+ */
+static void
+lookup_confhost(struct ConfItem *conf)
+{
+ struct AccessItem *aconf;
+ struct addrinfo hints, *res;
+
+ aconf = map_to_conf(conf);
+
+ if (has_wildcards(aconf->host))
+ {
+ ilog(LOG_TYPE_IRCD, "Host/server name error: (%s) (%s)",
+ aconf->host, conf->name);
+ return;
+ }
+
+ /* Do name lookup now on hostnames given and store the
+ * ip numbers in conf structure.
+ */
+ memset(&hints, 0, sizeof(hints));
+
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+
+ /* Get us ready for a bind() and don't bother doing dns lookup */
+ hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
+
+ if (getaddrinfo(aconf->host, NULL, &hints, &res))
+ {
+ conf_dns_lookup(aconf);
+ return;
+ }
+
+ assert(res != NULL);
+
+ memcpy(&aconf->addr, res->ai_addr, res->ai_addrlen);
+ aconf->addr.ss_len = res->ai_addrlen;
+ aconf->addr.ss.ss_family = res->ai_family;
+ freeaddrinfo(res);
+}
+
+/* conf_connect_allowed()
+ *
+ * inputs - pointer to inaddr
+ * - int type ipv4 or ipv6
+ * output - BANNED or accepted
+ * side effects - none
+ */
+int
+conf_connect_allowed(struct irc_ssaddr *addr, int aftype)
+{
+ struct ip_entry *ip_found;
+ struct AccessItem *aconf = find_dline_conf(addr, aftype);
+
+ /* DLINE exempt also gets you out of static limits/pacing... */
+ if (aconf && (aconf->status & CONF_EXEMPTDLINE))
+ return 0;
+
+ if (aconf != NULL)
+ return BANNED_CLIENT;
+
+ ip_found = find_or_add_ip(addr);
+
+ if ((CurrentTime - ip_found->last_attempt) <
+ ConfigFileEntry.throttle_time)
+ {
+ ip_found->last_attempt = CurrentTime;
+ return TOO_FAST;
+ }
+
+ ip_found->last_attempt = CurrentTime;
+ return 0;
+}
+
+static struct AccessItem *
+find_regexp_kline(const char *uhi[])
+{
+#ifdef HAVE_LIBPCRE
+ const dlink_node *ptr = NULL;
+
+ DLINK_FOREACH(ptr, rkconf_items.head)
+ {
+ struct AccessItem *aptr = map_to_conf(ptr->data);
+
+ assert(aptr->regexuser);
+ assert(aptr->regexhost);
+
+ if (!ircd_pcre_exec(aptr->regexuser, uhi[0]) &&
+ (!ircd_pcre_exec(aptr->regexhost, uhi[1]) ||
+ !ircd_pcre_exec(aptr->regexhost, uhi[2])))
+ return aptr;
+ }
+#endif
+ return NULL;
+}
+
+/* find_kill()
+ *
+ * inputs - pointer to client structure
+ * output - pointer to struct AccessItem if found
+ * side effects - See if this user is klined already,
+ * and if so, return struct AccessItem pointer
+ */
+struct AccessItem *
+find_kill(struct Client *client_p)
+{
+ struct AccessItem *aconf = NULL;
+ const char *uhi[3];
+
+ uhi[0] = client_p->username;
+ uhi[1] = client_p->host;
+ uhi[2] = client_p->sockhost;
+
+ assert(client_p != NULL);
+
+ aconf = find_conf_by_address(client_p->host, &client_p->localClient->ip,
+ CONF_KLINE, client_p->localClient->aftype,
+ client_p->username, NULL, 1);
+ if (aconf == NULL)
+ aconf = find_regexp_kline(uhi);
+
+ return aconf;
+}
+
+struct AccessItem *
+find_gline(struct Client *client_p)
+{
+ struct AccessItem *aconf;
+
+ assert(client_p != NULL);
+
+ aconf = find_conf_by_address(client_p->host, &client_p->localClient->ip,
+ CONF_GLINE, client_p->localClient->aftype,
+ client_p->username, NULL, 1);
+ return aconf;
+}
+
+/* add_temp_line()
+ *
+ * inputs - pointer to struct ConfItem
+ * output - none
+ * Side effects - links in given struct ConfItem into
+ * temporary *line link list
+ */
+void
+add_temp_line(struct ConfItem *conf)
+{
+ if (conf->type == XLINE_TYPE)
+ {
+ conf->flags |= CONF_FLAGS_TEMPORARY;
+ dlinkAdd(conf, make_dlink_node(), &temporary_xlines);
+ }
+ else if ((conf->type == NRESV_TYPE) || (conf->type == CRESV_TYPE))
+ {
+ conf->flags |= CONF_FLAGS_TEMPORARY;
+ dlinkAdd(conf, make_dlink_node(), &temporary_resv);
+ }
+}
+
+/* cleanup_tklines()
+ *
+ * inputs - NONE
+ * output - NONE
+ * side effects - call function to expire temporary k/d lines
+ * This is an event started off in ircd.c
+ */
+void
+cleanup_tklines(void *notused)
+{
+ hostmask_expire_temporary();
+ expire_tklines(&temporary_xlines);
+ expire_tklines(&temporary_resv);
+}
+
+/* expire_tklines()
+ *
+ * inputs - tkline list pointer
+ * output - NONE
+ * side effects - expire tklines
+ */
+static void
+expire_tklines(dlink_list *tklist)
+{
+ dlink_node *ptr;
+ dlink_node *next_ptr;
+ struct ConfItem *conf;
+ struct MatchItem *xconf;
+ struct MatchItem *nconf;
+ struct ResvChannel *cconf;
+
+ DLINK_FOREACH_SAFE(ptr, next_ptr, tklist->head)
+ {
+ conf = ptr->data;
+
+ if (conf->type == XLINE_TYPE)
+ {
+ xconf = (struct MatchItem *)map_to_conf(conf);
+ if (xconf->hold <= CurrentTime)
+ {
+ if (ConfigFileEntry.tkline_expire_notices)
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Temporary X-line for [%s] sexpired", conf->name);
+ dlinkDelete(ptr, tklist);
+ free_dlink_node(ptr);
+ delete_conf_item(conf);
+ }
+ }
+ else if (conf->type == NRESV_TYPE)
+ {
+ nconf = (struct MatchItem *)map_to_conf(conf);
+ if (nconf->hold <= CurrentTime)
+ {
+ if (ConfigFileEntry.tkline_expire_notices)
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Temporary RESV for [%s] expired", conf->name);
+ dlinkDelete(ptr, tklist);
+ free_dlink_node(ptr);
+ delete_conf_item(conf);
+ }
+ }
+ else if (conf->type == CRESV_TYPE)
+ {
+ cconf = (struct ResvChannel *)map_to_conf(conf);
+ if (cconf->hold <= CurrentTime)
+ {
+ if (ConfigFileEntry.tkline_expire_notices)
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Temporary RESV for [%s] expired", cconf->name);
+ delete_channel_resv(cconf);
+ }
+ }
+ }
+}
+
+/* oper_privs_as_string()
+ *
+ * inputs - pointer to client_p
+ * output - pointer to static string showing oper privs
+ * side effects - return as string, the oper privs as derived from port
+ */
+static const struct oper_privs
+{
+ const unsigned int oprivs;
+ const unsigned char c;
+} flag_list[] = {
+ { OPER_FLAG_ADMIN, 'A' },
+ { OPER_FLAG_REMOTEBAN, 'B' },
+ { OPER_FLAG_DIE, 'D' },
+ { OPER_FLAG_GLINE, 'G' },
+ { OPER_FLAG_REHASH, 'H' },
+ { OPER_FLAG_K, 'K' },
+ { OPER_FLAG_OPERWALL, 'L' },
+ { OPER_FLAG_N, 'N' },
+ { OPER_FLAG_GLOBAL_KILL, 'O' },
+ { OPER_FLAG_REMOTE, 'R' },
+ { OPER_FLAG_OPER_SPY, 'S' },
+ { OPER_FLAG_UNKLINE, 'U' },
+ { OPER_FLAG_X, 'X' },
+ { 0, '\0' }
+};
+
+char *
+oper_privs_as_string(const unsigned int port)
+{
+ static char privs_out[16];
+ char *privs_ptr = privs_out;
+ unsigned int i = 0;
+
+ for (; flag_list[i].oprivs; ++i)
+ {
+ if (port & flag_list[i].oprivs)
+ *privs_ptr++ = flag_list[i].c;
+ else
+ *privs_ptr++ = ToLowerTab[flag_list[i].c];
+ }
+
+ *privs_ptr = '\0';
+
+ return privs_out;
+}
+
+/*
+ * 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.
+ */
+const char *
+get_oper_name(const struct Client *client_p)
+{
+ dlink_node *cnode = NULL;
+ /* +5 for !,@,{,} and null */
+ static char buffer[NICKLEN + USERLEN + HOSTLEN + HOSTLEN + 5];
+
+ if (MyConnect(client_p))
+ {
+ if ((cnode = client_p->localClient->confs.head))
+ {
+ struct ConfItem *conf = cnode->data;
+ const struct AccessItem *aconf = map_to_conf(conf);
+
+ if (IsConfOperator(aconf))
+ {
+ snprintf(buffer, sizeof(buffer), "%s!%s@%s{%s}", client_p->name,
+ client_p->username, client_p->host, conf->name);
+ return buffer;
+ }
+ }
+
+ /* Probably should assert here for now. If there is an oper out there
+ * with no oper{} conf attached, it would be good for us to know...
+ */
+ assert(0); /* Oper without oper conf! */
+ }
+
+ snprintf(buffer, sizeof(buffer), "%s!%s@%s{%s}", client_p->name,
+ client_p->username, client_p->host, client_p->servptr->name);
+ return buffer;
+}
+
+/* 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;
+ char chanmodes[32];
+ char chanlimit[32];
+
+ conf_parser_ctx.boot = cold;
+ 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_parser_ctx.conf_file = fopen(filename, "r")) == NULL)
+ {
+ if (cold)
+ {
+ ilog(LOG_TYPE_IRCD, "Unable to read configuration file '%s': %s",
+ filename, strerror(errno));
+ exit(-1);
+ }
+ else
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Unable to read configuration file '%s': %s",
+ filename, strerror(errno));
+ return;
+ }
+ }
+
+ if (!cold)
+ clear_out_old_conf();
+
+ read_conf(conf_parser_ctx.conf_file);
+ fclose(conf_parser_ctx.conf_file);
+
+ add_isupport("NETWORK", ServerInfo.network_name, -1);
+ snprintf(chanmodes, sizeof(chanmodes), "beI:%d",
+ ConfigChannel.max_bans);
+ add_isupport("MAXLIST", chanmodes, -1);
+ add_isupport("MAXTARGETS", NULL, ConfigFileEntry.max_targets);
+
+ add_isupport("CHANTYPES", "#", -1);
+
+ snprintf(chanlimit, sizeof(chanlimit), "#:%d",
+ ConfigChannel.max_chans_per_user);
+ add_isupport("CHANLIMIT", chanlimit, -1);
+ snprintf(chanmodes, sizeof(chanmodes), "%s",
+ "beI,k,l,imnprstORS");
+ add_isupport("CHANNELLEN", NULL, LOCAL_CHANNELLEN);
+
+ add_isupport("EXCEPTS", "e", -1);
+ add_isupport("INVEX", "I", -1);
+ add_isupport("CHANMODES", chanmodes, -1);
+
+ /*
+ * message_locale may have changed. rebuild isupport since it relies
+ * on strlen(form_str(RPL_ISUPPORT))
+ */
+ rebuild_isupport_message_line();
+
+ parse_conf_file(KLINE_TYPE, cold);
+ parse_conf_file(DLINE_TYPE, cold);
+ parse_conf_file(XLINE_TYPE, cold);
+ parse_conf_file(NRESV_TYPE, cold);
+ parse_conf_file(CRESV_TYPE, cold);
+}
+
+/* parse_conf_file()
+ *
+ * inputs - type of conf file to parse
+ * output - none
+ * side effects - conf file for givenconf type is opened and read then parsed
+ */
+static void
+parse_conf_file(int type, int cold)
+{
+ FILE *file = NULL;
+ const char *filename = get_conf_name(type);
+
+ if ((file = fopen(filename, "r")) == NULL)
+ {
+ if (cold)
+ ilog(LOG_TYPE_IRCD, "Unable to read configuration file '%s': %s",
+ filename, strerror(errno));
+ else
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Unable to read configuration file '%s': %s",
+ filename, strerror(errno));
+ }
+ else
+ {
+ parse_csv_file(file, type);
+ fclose(file);
+ }
+}
+
+/* clear_out_old_conf()
+ *
+ * inputs - none
+ * output - none
+ * side effects - Clear out the old configuration
+ */
+static void
+clear_out_old_conf(void)
+{
+ dlink_node *ptr = NULL, *next_ptr = NULL;
+ struct ConfItem *conf;
+ struct AccessItem *aconf;
+ struct ClassItem *cltmp;
+ dlink_list *free_items [] = {
+ &server_items, &oconf_items,
+ &uconf_items, &xconf_items, &rxconf_items, &rkconf_items,
+ &nresv_items, &cluster_items, &service_items, NULL
+ };
+
+ dlink_list ** iterator = free_items; /* C is dumb */
+
+ /* We only need to free anything allocated by yyparse() here.
+ * Resetting structs, etc, is taken care of by set_default_conf().
+ */
+
+ for (; *iterator != NULL; iterator++)
+ {
+ DLINK_FOREACH_SAFE(ptr, next_ptr, (*iterator)->head)
+ {
+ conf = ptr->data;
+ /* XXX This is less than pretty */
+ if (conf->type == SERVER_TYPE)
+ {
+ aconf = map_to_conf(conf);
+
+ if (aconf->clients != 0)
+ {
+ SetConfIllegal(aconf);
+ dlinkDelete(&conf->node, &server_items);
+ }
+ else
+ {
+ delete_conf_item(conf);
+ }
+ }
+ else if (conf->type == OPER_TYPE)
+ {
+ aconf = map_to_conf(conf);
+
+ if (aconf->clients != 0)
+ {
+ SetConfIllegal(aconf);
+ dlinkDelete(&conf->node, &oconf_items);
+ }
+ else
+ {
+ delete_conf_item(conf);
+ }
+ }
+ else if (conf->type == XLINE_TYPE ||
+ conf->type == RXLINE_TYPE ||
+ conf->type == RKLINE_TYPE)
+ {
+ /* temporary (r)xlines are also on
+ * the (r)xconf items list */
+ if (conf->flags & CONF_FLAGS_TEMPORARY)
+ continue;
+
+ delete_conf_item(conf);
+ }
+ else
+ {
+ delete_conf_item(conf);
+ }
+ }
+ }
+
+ /*
+ * 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_items.head)
+ {
+ cltmp = map_to_conf(ptr->data);
+
+ if (ptr != class_items.tail) /* never mark the "default" class */
+ cltmp->active = 0;
+ }
+
+ clear_out_address_conf();
+
+ /* clean out module paths */
+ mod_clear_paths();
+
+ /* 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;
+ MyFree(ConfigFileEntry.egdpool_path);
+ ConfigFileEntry.egdpool_path = NULL;
+#ifdef HAVE_LIBCRYPTO
+ if (ServerInfo.rsa_private_key != NULL)
+ {
+ RSA_free(ServerInfo.rsa_private_key);
+ ServerInfo.rsa_private_key = NULL;
+ }
+
+ MyFree(ServerInfo.rsa_private_key_file);
+ ServerInfo.rsa_private_key_file = NULL;
+
+ if (ServerInfo.server_ctx)
+ SSL_CTX_set_options(ServerInfo.server_ctx, SSL_OP_NO_SSLv2|
+ SSL_OP_NO_SSLv3|
+ SSL_OP_NO_TLSv1);
+ if (ServerInfo.client_ctx)
+ SSL_CTX_set_options(ServerInfo.client_ctx, SSL_OP_NO_SSLv2|
+ SSL_OP_NO_SSLv3|
+ SSL_OP_NO_TLSv1);
+#endif
+
+ /* clean out old resvs from the conf */
+ clear_conf_resv();
+
+ /* 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.service_name);
+ ConfigFileEntry.service_name = NULL;
+
+ delete_isupport("INVEX");
+ delete_isupport("EXCEPTS");
+}
+
+/* flush_deleted_I_P()
+ *
+ * inputs - none
+ * output - none
+ * side effects - This function removes I/P conf items
+ */
+static void
+flush_deleted_I_P(void)
+{
+ dlink_node *ptr;
+ dlink_node *next_ptr;
+ struct ConfItem *conf;
+ struct AccessItem *aconf;
+ dlink_list * free_items [] = {
+ &server_items, &oconf_items, NULL
+ };
+ dlink_list ** iterator = free_items; /* C is dumb */
+
+ /* flush out deleted I and P lines
+ * although still in use.
+ */
+ for (; *iterator != NULL; iterator++)
+ {
+ DLINK_FOREACH_SAFE(ptr, next_ptr, (*iterator)->head)
+ {
+ conf = ptr->data;
+ aconf = (struct AccessItem *)map_to_conf(conf);
+
+ if (IsConfIllegal(aconf))
+ {
+ dlinkDelete(ptr, *iterator);
+
+ if (aconf->clients == 0)
+ delete_conf_item(conf);
+ }
+ }
+ }
+}
+
+/* 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(ConfType type)
+{
+ switch (type)
+ {
+ case CONF_TYPE:
+ return ConfigFileEntry.configfile;
+ break;
+ case KLINE_TYPE:
+ return ConfigFileEntry.klinefile;
+ break;
+ case DLINE_TYPE:
+ return ConfigFileEntry.dlinefile;
+ break;
+ case XLINE_TYPE:
+ return ConfigFileEntry.xlinefile;
+ break;
+ case CRESV_TYPE:
+ return ConfigFileEntry.cresvfile;
+ break;
+ case NRESV_TYPE:
+ return ConfigFileEntry.nresvfile;
+ break;
+ default:
+ return NULL; /* This should NEVER HAPPEN since we call this function
+ only with the above values, this will cause us to core
+ at some point if this happens so we know where it was */
+ }
+}
+
+#define BAD_PING (-1)
+
+/* get_conf_ping()
+ *
+ * inputs - pointer to struct AccessItem
+ * - pointer to a variable that receives ping warning time
+ * output - ping frequency
+ * side effects - NONE
+ */
+static int
+get_conf_ping(struct ConfItem *conf, int *pingwarn)
+{
+ struct ClassItem *aclass;
+ struct AccessItem *aconf;
+
+ if (conf != NULL)
+ {
+ aconf = (struct AccessItem *)map_to_conf(conf);
+ if (aconf->class_ptr != NULL)
+ {
+ aclass = (struct ClassItem *)map_to_conf(aconf->class_ptr);
+ *pingwarn = aclass->ping_warning;
+ return aclass->ping_freq;
+ }
+ }
+
+ 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)
+{
+ dlink_node *cnode = NULL;
+ struct AccessItem *aconf = NULL;
+
+ assert(!IsMe(target_p));
+
+ if ((cnode = target_p->localClient->confs.head))
+ {
+ struct ConfItem *conf = cnode->data;
+
+ assert((conf->type == CLIENT_TYPE) || (conf->type == SERVER_TYPE) ||
+ (conf->type == OPER_TYPE));
+
+ aconf = map_to_conf(conf);
+ if (aconf->class_ptr != NULL)
+ return aconf->class_ptr->name;
+ }
+
+ return "default";
+}
+
+/* get_client_ping()
+ *
+ * inputs - pointer to client struct
+ * - pointer to a variable that receives ping warning time
+ * output - ping frequency
+ * side effects - NONE
+ */
+int
+get_client_ping(struct Client *target_p, int *pingwarn)
+{
+ int ping = 0;
+ dlink_node *cnode = NULL;
+
+ if ((cnode = target_p->localClient->confs.head))
+ {
+ struct ConfItem *conf = cnode->data;
+
+ assert((conf->type == CLIENT_TYPE) || (conf->type == SERVER_TYPE) ||
+ (conf->type == OPER_TYPE));
+
+ ping = get_conf_ping(conf, pingwarn);
+ if (ping > 0)
+ return ping;
+ }
+
+ *pingwarn = 0;
+ return DEFAULT_PINGFREQUENCY;
+}
+
+/* find_class()
+ *
+ * inputs - string name of class
+ * output - corresponding Class pointer
+ * side effects - NONE
+ */
+struct ConfItem *
+find_class(const char *classname)
+{
+ struct ConfItem *conf;
+
+ if ((conf = find_exact_name_conf(CLASS_TYPE, NULL, classname, NULL, NULL)) != NULL)
+ return conf;
+
+ return class_default;
+}
+
+/* check_class()
+ *
+ * inputs - NONE
+ * output - NONE
+ * side effects -
+ */
+void
+check_class(void)
+{
+ dlink_node *ptr = NULL, *next_ptr = NULL;
+
+ DLINK_FOREACH_SAFE(ptr, next_ptr, class_items.head)
+ {
+ struct ClassItem *aclass = map_to_conf(ptr->data);
+
+ if (!aclass->active && !aclass->curr_user_count)
+ {
+ destroy_cidr_class(aclass);
+ delete_conf_item(ptr->data);
+ }
+ }
+}
+
+/* init_class()
+ *
+ * inputs - NONE
+ * output - NONE
+ * side effects -
+ */
+void
+init_class(void)
+{
+ struct ClassItem *aclass;
+
+ class_default = make_conf_item(CLASS_TYPE);
+
+ aclass = map_to_conf(class_default);
+ aclass->active = 1;
+ DupString(class_default->name, "default");
+ aclass->con_freq = DEFAULT_CONNECTFREQUENCY;
+ aclass->ping_freq = DEFAULT_PINGFREQUENCY;
+ aclass->max_total = MAXIMUM_LINKS_DEFAULT;
+ aclass->max_sendq = DEFAULT_SENDQ;
+ aclass->max_recvq = DEFAULT_RECVQ;
+
+ client_check_cb = register_callback("check_client", check_client);
+}
+
+/* get_sendq()
+ *
+ * inputs - pointer to client
+ * output - sendq for this client as found from its class
+ * side effects - NONE
+ */
+unsigned int
+get_sendq(struct Client *client_p)
+{
+ unsigned int sendq = DEFAULT_SENDQ;
+ dlink_node *cnode;
+ struct ConfItem *class_conf;
+ struct ClassItem *aclass;
+ struct AccessItem *aconf;
+
+ assert(!IsMe(client_p));
+
+ if ((cnode = client_p->localClient->confs.head))
+ {
+ struct ConfItem *conf = cnode->data;
+
+ assert((conf->type == CLIENT_TYPE) || (conf->type == SERVER_TYPE) ||
+ (conf->type == OPER_TYPE));
+
+ aconf = map_to_conf(conf);
+
+ if ((class_conf = aconf->class_ptr) == NULL)
+ return DEFAULT_SENDQ; /* TBV: shouldn't be possible at all */
+
+ aclass = map_to_conf(class_conf);
+ sendq = aclass->max_sendq;
+ return sendq;
+ }
+
+ /* XXX return a default?
+ * if here, then there wasn't an attached conf with a sendq
+ * that is very bad -Dianora
+ */
+ return DEFAULT_SENDQ;
+}
+
+unsigned int
+get_recvq(struct Client *client_p)
+{
+ unsigned int recvq = DEFAULT_RECVQ;
+ dlink_node *cnode;
+ struct ConfItem *class_conf;
+ struct ClassItem *aclass;
+ struct AccessItem *aconf;
+
+ assert(!IsMe(client_p));
+
+ if ((cnode = client_p->localClient->confs.head))
+ {
+ struct ConfItem *conf = cnode->data;
+
+ assert((conf->type == CLIENT_TYPE) || (conf->type == SERVER_TYPE) ||
+ (conf->type == OPER_TYPE));
+
+ aconf = map_to_conf(conf);
+
+ if ((class_conf = aconf->class_ptr) == NULL)
+ return DEFAULT_RECVQ; /* TBV: shouldn't be possible at all */
+
+ aclass = map_to_conf(class_conf);
+ recvq = aclass->max_recvq;
+ return recvq;
+ }
+
+ /* XXX return a default?
+ * if here, then there wasn't an attached conf with a recvq
+ * that is very bad -Dianora
+ */
+ return DEFAULT_RECVQ;
+}
+
+/* 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 *conf, const char *class_name)
+{
+ struct AccessItem *aconf = map_to_conf(conf);
+ struct ClassItem *class = NULL;
+
+ if (class_name == NULL)
+ {
+ aconf->class_ptr = class_default;
+
+ if (conf->type == CLIENT_TYPE)
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Warning *** Defaulting to default class for %s@%s",
+ aconf->user, aconf->host);
+ else
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Warning *** Defaulting to default class for %s",
+ conf->name);
+ }
+ else
+ aconf->class_ptr = find_class(class_name);
+
+ if (aconf->class_ptr)
+ class = map_to_conf(aconf->class_ptr);
+
+ if (aconf->class_ptr == NULL || !class->active)
+ {
+ if (conf->type == CLIENT_TYPE)
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Warning *** Defaulting to default class for %s@%s",
+ aconf->user, aconf->host);
+ else
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Warning *** Defaulting to default class for %s",
+ conf->name);
+ aconf->class_ptr = class_default;
+ }
+}
+
+/* conf_add_server()
+ *
+ * inputs - pointer to config item
+ * - pointer to link count already on this conf
+ * output - NONE
+ * side effects - Add a connect block
+ */
+int
+conf_add_server(struct ConfItem *conf, const char *class_name)
+{
+ struct AccessItem *aconf = map_to_conf(conf);
+
+ conf_add_class_to_conf(conf, class_name);
+
+ if (!aconf->host || !conf->name)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL, "Bad connect block");
+ ilog(LOG_TYPE_IRCD, "Bad connect block");
+ return -1;
+ }
+
+ if (EmptyString(aconf->passwd))
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL, "Bad connect block, name %s",
+ conf->name);
+ ilog(LOG_TYPE_IRCD, "Bad connect block, host %s", conf->name);
+ return -1;
+ }
+
+ lookup_confhost(conf);
+
+ return 0;
+}
+
+/* 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[IRCD_BUFSIZE];
+
+ if (conf_parser_ctx.pass != 1)
+ return;
+
+ strip_tabs(newlinebuf, linebuf, sizeof(newlinebuf));
+ sendto_realops_flags(UMODE_ALL, L_ALL, "\"%s\", line %u: %s: %s",
+ conffilebuf, lineno + 1, msg, newlinebuf);
+ ilog(LOG_TYPE_IRCD, "\"%s\", line %u: %s: %s",
+ conffilebuf, lineno + 1, msg, newlinebuf);
+}
+
+/*
+ * valid_tkline()
+ *
+ * inputs - pointer to ascii string to check
+ * - whether the specified time is in seconds or minutes
+ * output - -1 not enough parameters
+ * - 0 if not an integer number, else the number
+ * side effects - none
+ * Originally written by Dianora (Diane, db@db.net)
+ */
+time_t
+valid_tkline(const char *p, int minutes)
+{
+ time_t result = 0;
+
+ for (; *p; ++p)
+ {
+ if (!IsDigit(*p))
+ return 0;
+
+ result *= 10;
+ result += ((*p) & 0xF);
+ }
+
+ /*
+ * In the degenerate case where oper does a /quote kline 0 user@host :reason
+ * i.e. they specifically use 0, I am going to return 1 instead
+ * as a return value of non-zero is used to flag it as a temporary kline
+ */
+ if (result == 0)
+ result = 1;
+
+ /*
+ * If the incoming time is in seconds convert it to minutes for the purpose
+ * of this calculation
+ */
+ if (!minutes)
+ result = result / (time_t)60;
+
+ if (result > MAX_TDKLINE_TIME)
+ result = MAX_TDKLINE_TIME;
+
+ result = result * (time_t)60; /* turn it into seconds */
+
+ return result;
+}
+
+/* valid_wild_card()
+ *
+ * input - pointer to client
+ * - int flag, 0 for no warning oper 1 for warning oper
+ * - count of following varargs to check
+ * output - 0 if not valid, 1 if valid
+ * side effects - NOTICE is given to source_p if warn is 1
+ */
+int
+valid_wild_card(struct Client *source_p, int warn, int count, ...)
+{
+ char *p;
+ char tmpch;
+ int nonwild = 0;
+ va_list args;
+
+ /*
+ * Now we must check the user and host to make sure there
+ * are at least NONWILDCHARS non-wildcard characters in
+ * them, otherwise assume they are attempting to kline
+ * *@* or some variant of that. This code will also catch
+ * people attempting to kline *@*.tld, as long as NONWILDCHARS
+ * is greater than 3. In that case, there are only 3 non-wild
+ * characters (tld), so if NONWILDCHARS is 4, the kline will
+ * be disallowed.
+ * -wnder
+ */
+
+ va_start(args, count);
+
+ while (count--)
+ {
+ p = va_arg(args, char *);
+ if (p == NULL)
+ continue;
+
+ while ((tmpch = *p++))
+ {
+ if (!IsKWildChar(tmpch))
+ {
+ /*
+ * If we find enough non-wild characters, we can
+ * break - no point in searching further.
+ */
+ if (++nonwild >= ConfigFileEntry.min_nonwildcard)
+ return 1;
+ }
+ }
+ }
+
+ if (warn)
+ sendto_one(source_p, ":%s NOTICE %s :Please include at least %d non-wildcard characters with the mask",
+ me.name, source_p->name, ConfigFileEntry.min_nonwildcard);
+ return 0;
+}
+
+/* XXX should this go into a separate file ? -Dianora */
+/* parse_aline
+ *
+ * input - pointer to cmd name being used
+ * - pointer to client using cmd
+ * - parc parameter count
+ * - parv[] list of parameters to parse
+ * - parse_flags bit map of things to test
+ * - pointer to user or string to parse into
+ * - pointer to host or NULL to parse into if non NULL
+ * - pointer to optional tkline time or NULL
+ * - pointer to target_server to parse into if non NULL
+ * - pointer to reason to parse into
+ *
+ * output - 1 if valid, -1 if not valid
+ * side effects - A generalised k/d/x etc. line parser,
+ * "ALINE [time] user@host|string [ON] target :reason"
+ * will parse returning a parsed user, host if
+ * h_p pointer is non NULL, string otherwise.
+ * if tkline_time pointer is non NULL a tk line will be set
+ * to non zero if found.
+ * if tkline_time pointer is NULL and tk line is found,
+ * error is reported.
+ * if target_server is NULL and an "ON" is found error
+ * is reported.
+ * if reason pointer is NULL ignore pointer,
+ * this allows use of parse_a_line in unkline etc.
+ *
+ * - Dianora
+ */
+int
+parse_aline(const char *cmd, struct Client *source_p,
+ int parc, char **parv,
+ int parse_flags, char **up_p, char **h_p, time_t *tkline_time,
+ char **target_server, char **reason)
+{
+ int found_tkline_time=0;
+ static char def_reason[] = "No Reason";
+ static char user[USERLEN*4+1];
+ static char host[HOSTLEN*4+1];
+
+ parv++;
+ parc--;
+
+ found_tkline_time = valid_tkline(*parv, TK_MINUTES);
+
+ if (found_tkline_time != 0)
+ {
+ parv++;
+ parc--;
+
+ if (tkline_time != NULL)
+ *tkline_time = found_tkline_time;
+ else
+ {
+ sendto_one(source_p, ":%s NOTICE %s :temp_line not supported by %s",
+ me.name, source_p->name, cmd);
+ return -1;
+ }
+ }
+
+ if (parc == 0)
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, cmd);
+ return -1;
+ }
+
+ if (h_p == NULL)
+ *up_p = *parv;
+ else
+ {
+ if (find_user_host(source_p, *parv, user, host, parse_flags) == 0)
+ return -1;
+
+ *up_p = user;
+ *h_p = host;
+ }
+
+ parc--;
+ parv++;
+
+ if (parc != 0)
+ {
+ if (irccmp(*parv, "ON") == 0)
+ {
+ parc--;
+ parv++;
+
+ if (target_server == NULL)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :ON server not supported by %s",
+ me.name, source_p->name, cmd);
+ return -1;
+ }
+
+ if (!HasOFlag(source_p, OPER_FLAG_REMOTEBAN))
+ {
+ sendto_one(source_p, form_str(ERR_NOPRIVS),
+ me.name, source_p->name, "remoteban");
+ return -1;
+ }
+
+ if (parc == 0 || EmptyString(*parv))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, cmd);
+ return -1;
+ }
+
+ *target_server = *parv;
+ parc--;
+ parv++;
+ }
+ else
+ {
+ /* Make sure target_server *is* NULL if no ON server found
+ * caller probably NULL'd it first, but no harm to do it again -db
+ */
+ if (target_server != NULL)
+ *target_server = NULL;
+ }
+ }
+
+ if (h_p != NULL)
+ {
+ if (strchr(user, '!') != NULL)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :Invalid character '!' in kline",
+ me.name, source_p->name);
+ return -1;
+ }
+
+ if ((parse_flags & AWILD) && !valid_wild_card(source_p, 1, 2, *up_p, *h_p))
+ return -1;
+ }
+ else
+ if ((parse_flags & AWILD) && !valid_wild_card(source_p, 1, 1, *up_p))
+ return -1;
+
+ if (reason != NULL)
+ {
+ if (parc != 0 && !EmptyString(*parv))
+ {
+ *reason = *parv;
+ if (!valid_comment(source_p, *reason, 1))
+ return -1;
+ }
+ else
+ *reason = def_reason;
+ }
+
+ return 1;
+}
+
+/* find_user_host()
+ *
+ * inputs - pointer to client placing kline
+ * - pointer to user_host_or_nick
+ * - pointer to user buffer
+ * - pointer to 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, char *user_host_or_nick,
+ char *luser, char *lhost, unsigned int flags)
+{
+ struct Client *target_p = NULL;
+ char *hostp = NULL;
+
+ if (lhost == NULL)
+ {
+ strlcpy(luser, user_host_or_nick, USERLEN*4 + 1);
+ return 1;
+ }
+
+ if ((hostp = strchr(user_host_or_nick, '@')) || *user_host_or_nick == '*')
+ {
+ /* Explicit user@host mask given */
+
+ if (hostp != NULL) /* I'm a little user@host */
+ {
+ *(hostp++) = '\0'; /* short and squat */
+ if (*user_host_or_nick)
+ strlcpy(luser, user_host_or_nick, USERLEN*4 + 1); /* here is my user */
+ else
+ strcpy(luser, "*");
+ if (*hostp)
+ strlcpy(lhost, hostp, HOSTLEN + 1); /* here is my host */
+ else
+ strcpy(lhost, "*");
+ }
+ else
+ {
+ luser[0] = '*'; /* no @ found, assume its *@somehost */
+ luser[1] = '\0';
+ strlcpy(lhost, user_host_or_nick, HOSTLEN*4 + 1);
+ }
+
+ return 1;
+ }
+ else
+ {
+ /* Try to find user@host mask from nick */
+ /* Okay to use source_p as the first param, because source_p == client_p */
+ if ((target_p =
+ find_chasing(source_p, source_p, user_host_or_nick, NULL)) == NULL)
+ return 0;
+
+ if (IsExemptKline(target_p))
+ {
+ if (!IsServer(source_p))
+ sendto_one(source_p,
+ ":%s NOTICE %s :%s is E-lined",
+ me.name, source_p->name, target_p->name);
+ return 0;
+ }
+
+ /*
+ * turn the "user" bit into "*user", blow away '~'
+ * if found in original user name (non-idented)
+ */
+ strlcpy(luser, target_p->username, USERLEN*4 + 1);
+
+ if (target_p->username[0] == '~')
+ luser[0] = '*';
+
+ if (target_p->sockhost[0] == '\0' ||
+ (target_p->sockhost[0] == '0' && target_p->sockhost[1] == '\0'))
+ strlcpy(lhost, target_p->host, HOSTLEN*4 + 1);
+ else
+ strlcpy(lhost, target_p->sockhost, HOSTLEN*4 + 1);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* valid_comment()
+ *
+ * inputs - pointer to client
+ * - pointer to comment
+ * output - 0 if no valid comment,
+ * - 1 if valid
+ * side effects - truncates reason where necessary
+ */
+int
+valid_comment(struct Client *source_p, char *comment, int warn)
+{
+ if (strchr(comment, '"'))
+ {
+ if (warn)
+ sendto_one(source_p, ":%s NOTICE %s :Invalid character '\"' in comment",
+ me.name, source_p->name);
+ return 0;
+ }
+
+ if (strlen(comment) > REASONLEN)
+ comment[REASONLEN-1] = '\0';
+
+ return 1;
+}
+
+/* match_conf_password()
+ *
+ * inputs - pointer to given password
+ * - pointer to Conf
+ * output - 1 or 0 if match
+ * side effects - none
+ */
+int
+match_conf_password(const char *password, const struct AccessItem *aconf)
+{
+ const char *encr = NULL;
+
+ if (EmptyString(password) || EmptyString(aconf->passwd))
+ return 0;
+
+ if (aconf->flags & CONF_FLAGS_ENCRYPTED)
+ encr = crypt(password, aconf->passwd);
+ else
+ encr = password;
+
+ return !strcmp(encr, aconf->passwd);
+}
+
+/*
+ * cluster_a_line
+ *
+ * inputs - client sending the cluster
+ * - command name "KLINE" "XLINE" etc.
+ * - capab -- CAP_KLN etc. from s_serv.h
+ * - cluster type -- CLUSTER_KLINE etc. from conf.h
+ * - pattern and args to send along
+ * output - none
+ * side effects - Take source_p send the pattern with args given
+ * along to all servers that match capab and cluster type
+*/
+void
+cluster_a_line(struct Client *source_p, const char *command,
+ int capab, int cluster_type, const char *pattern, ...)
+{
+ va_list args;
+ char buffer[IRCD_BUFSIZE];
+ const dlink_node *ptr = NULL;
+
+ va_start(args, pattern);
+ vsnprintf(buffer, sizeof(buffer), pattern, args);
+ va_end(args);
+
+ DLINK_FOREACH(ptr, cluster_items.head)
+ {
+ const struct ConfItem *conf = ptr->data;
+
+ if (conf->flags & cluster_type)
+ sendto_match_servs(source_p, conf->name, CAP_CLUSTER|capab,
+ "%s %s %s", command, conf->name, buffer);
+ }
+}
+
+/*
+ * split_nuh
+ *
+ * inputs - pointer to original mask (modified in place)
+ * - pointer to pointer where nick should go
+ * - pointer to pointer where user should go
+ * - pointer to pointer where host should go
+ * output - NONE
+ * side effects - mask is modified in place
+ * If nick pointer is NULL, ignore writing to it
+ * this allows us to use this function elsewhere.
+ *
+ * mask nick user host
+ * ---------------------- ------- ------- ------
+ * Dianora!db@db.net Dianora db db.net
+ * Dianora Dianora * *
+ * db.net * * db.net
+ * OR if nick pointer is NULL
+ * Dianora - * Dianora
+ * Dianora! Dianora * *
+ * Dianora!@ Dianora * *
+ * Dianora!db Dianora db *
+ * Dianora!@db.net Dianora * db.net
+ * db@db.net * db db.net
+ * !@ * * *
+ * @ * * *
+ * ! * * *
+ */
+void
+split_nuh(struct split_nuh_item *const iptr)
+{
+ char *p = NULL, *q = NULL;
+
+ if (iptr->nickptr)
+ strlcpy(iptr->nickptr, "*", iptr->nicksize);
+ if (iptr->userptr)
+ strlcpy(iptr->userptr, "*", iptr->usersize);
+ if (iptr->hostptr)
+ strlcpy(iptr->hostptr, "*", iptr->hostsize);
+
+ if ((p = strchr(iptr->nuhmask, '!')))
+ {
+ *p = '\0';
+
+ if (iptr->nickptr && *iptr->nuhmask != '\0')
+ strlcpy(iptr->nickptr, iptr->nuhmask, iptr->nicksize);
+
+ if ((q = strchr(++p, '@'))) {
+ *q++ = '\0';
+
+ if (*p != '\0')
+ strlcpy(iptr->userptr, p, iptr->usersize);
+
+ if (*q != '\0')
+ strlcpy(iptr->hostptr, q, iptr->hostsize);
+ }
+ else
+ {
+ if (*p != '\0')
+ strlcpy(iptr->userptr, p, iptr->usersize);
+ }
+ }
+ else
+ {
+ /* No ! found so lets look for a user@host */
+ if ((p = strchr(iptr->nuhmask, '@')))
+ {
+ /* if found a @ */
+ *p++ = '\0';
+
+ if (*iptr->nuhmask != '\0')
+ strlcpy(iptr->userptr, iptr->nuhmask, iptr->usersize);
+
+ if (*p != '\0')
+ strlcpy(iptr->hostptr, p, iptr->hostsize);
+ }
+ else
+ {
+ /* no @ found */
+ if (!iptr->nickptr || strpbrk(iptr->nuhmask, ".:"))
+ strlcpy(iptr->hostptr, iptr->nuhmask, iptr->hostsize);
+ else
+ strlcpy(iptr->nickptr, iptr->nuhmask, iptr->nicksize);
+ }
+ }
+}
+
+/*
+ * flags_to_ascii
+ *
+ * inputs - flags is a bitmask
+ * - pointer to table of ascii letters corresponding
+ * to each bit
+ * - flag 1 for convert ToLower if bit missing
+ * 0 if ignore.
+ * output - none
+ * side effects - string pointed to by p has bitmap chars written to it
+ */
+static void
+flags_to_ascii(unsigned int flags, const unsigned int bit_table[], char *p,
+ int lowerit)
+{
+ unsigned int mask = 1;
+ int i = 0;
+
+ for (mask = 1; (mask != 0) && (bit_table[i] != 0); mask <<= 1, i++)
+ {
+ if (flags & mask)
+ *p++ = bit_table[i];
+ else if (lowerit)
+ *p++ = ToLower(bit_table[i]);
+ }
+ *p = '\0';
+}
+
+/*
+ * cidr_limit_reached
+ *
+ * inputs - int flag allowing over_rule of limits
+ * - pointer to the ip to be added
+ * - pointer to the class
+ * output - non zero if limit reached
+ * 0 if limit not reached
+ * side effects -
+ */
+static int
+cidr_limit_reached(int over_rule,
+ struct irc_ssaddr *ip, struct ClassItem *aclass)
+{
+ dlink_node *ptr = NULL;
+ struct CidrItem *cidr;
+
+ if (aclass->number_per_cidr <= 0)
+ return 0;
+
+ if (ip->ss.ss_family == AF_INET)
+ {
+ if (aclass->cidr_bitlen_ipv4 <= 0)
+ return 0;
+
+ DLINK_FOREACH(ptr, aclass->list_ipv4.head)
+ {
+ cidr = ptr->data;
+ if (match_ipv4(ip, &cidr->mask, aclass->cidr_bitlen_ipv4))
+ {
+ if (!over_rule && (cidr->number_on_this_cidr >= aclass->number_per_cidr))
+ return -1;
+ cidr->number_on_this_cidr++;
+ return 0;
+ }
+ }
+ cidr = MyMalloc(sizeof(struct CidrItem));
+ cidr->number_on_this_cidr = 1;
+ cidr->mask = *ip;
+ mask_addr(&cidr->mask, aclass->cidr_bitlen_ipv4);
+ dlinkAdd(cidr, &cidr->node, &aclass->list_ipv4);
+ }
+#ifdef IPV6
+ else if (aclass->cidr_bitlen_ipv6 > 0)
+ {
+ DLINK_FOREACH(ptr, aclass->list_ipv6.head)
+ {
+ cidr = ptr->data;
+ if (match_ipv6(ip, &cidr->mask, aclass->cidr_bitlen_ipv6))
+ {
+ if (!over_rule && (cidr->number_on_this_cidr >= aclass->number_per_cidr))
+ return -1;
+ cidr->number_on_this_cidr++;
+ return 0;
+ }
+ }
+ cidr = MyMalloc(sizeof(struct CidrItem));
+ cidr->number_on_this_cidr = 1;
+ cidr->mask = *ip;
+ mask_addr(&cidr->mask, aclass->cidr_bitlen_ipv6);
+ dlinkAdd(cidr, &cidr->node, &aclass->list_ipv6);
+ }
+#endif
+ return 0;
+}
+
+/*
+ * remove_from_cidr_check
+ *
+ * inputs - pointer to the ip to be removed
+ * - pointer to the class
+ * output - NONE
+ * side effects -
+ */
+static void
+remove_from_cidr_check(struct irc_ssaddr *ip, struct ClassItem *aclass)
+{
+ dlink_node *ptr = NULL;
+ dlink_node *next_ptr = NULL;
+ struct CidrItem *cidr;
+
+ if (aclass->number_per_cidr == 0)
+ return;
+
+ if (ip->ss.ss_family == AF_INET)
+ {
+ if (aclass->cidr_bitlen_ipv4 <= 0)
+ return;
+
+ DLINK_FOREACH_SAFE(ptr, next_ptr, aclass->list_ipv4.head)
+ {
+ cidr = ptr->data;
+ if (match_ipv4(ip, &cidr->mask, aclass->cidr_bitlen_ipv4))
+ {
+ cidr->number_on_this_cidr--;
+ if (cidr->number_on_this_cidr == 0)
+ {
+ dlinkDelete(ptr, &aclass->list_ipv4);
+ MyFree(cidr);
+ return;
+ }
+ }
+ }
+ }
+#ifdef IPV6
+ else if (aclass->cidr_bitlen_ipv6 > 0)
+ {
+ DLINK_FOREACH_SAFE(ptr, next_ptr, aclass->list_ipv6.head)
+ {
+ cidr = ptr->data;
+ if (match_ipv6(ip, &cidr->mask, aclass->cidr_bitlen_ipv6))
+ {
+ cidr->number_on_this_cidr--;
+ if (cidr->number_on_this_cidr == 0)
+ {
+ dlinkDelete(ptr, &aclass->list_ipv6);
+ MyFree(cidr);
+ return;
+ }
+ }
+ }
+ }
+#endif
+}
+
+static void
+rebuild_cidr_list(int aftype, struct ConfItem *oldcl, struct ClassItem *newcl,
+ dlink_list *old_list, dlink_list *new_list, int changed)
+{
+ dlink_node *ptr;
+ struct Client *client_p;
+ struct ConfItem *conf;
+ struct AccessItem *aconf;
+
+ if (!changed)
+ {
+ *new_list = *old_list;
+ old_list->head = old_list->tail = NULL;
+ old_list->length = 0;
+ return;
+ }
+
+ DLINK_FOREACH(ptr, local_client_list.head)
+ {
+ client_p = ptr->data;
+ if (client_p->localClient->aftype != aftype)
+ continue;
+ if (dlink_list_length(&client_p->localClient->confs) == 0)
+ continue;
+
+ conf = client_p->localClient->confs.tail->data;
+ if (conf->type == CLIENT_TYPE)
+ {
+ aconf = map_to_conf(conf);
+ if (aconf->class_ptr == oldcl)
+ cidr_limit_reached(1, &client_p->localClient->ip, newcl);
+ }
+ }
+}
+
+/*
+ * rebuild_cidr_class
+ *
+ * inputs - pointer to old conf
+ * - pointer to new_class
+ * output - none
+ * side effects - rebuilds the class link list of cidr blocks
+ */
+void
+rebuild_cidr_class(struct ConfItem *conf, struct ClassItem *new_class)
+{
+ struct ClassItem *old_class = map_to_conf(conf);
+
+ if (old_class->number_per_cidr > 0 && new_class->number_per_cidr > 0)
+ {
+ if (old_class->cidr_bitlen_ipv4 > 0 && new_class->cidr_bitlen_ipv4 > 0)
+ rebuild_cidr_list(AF_INET, conf, new_class,
+ &old_class->list_ipv4, &new_class->list_ipv4,
+ old_class->cidr_bitlen_ipv4 != new_class->cidr_bitlen_ipv4);
+
+#ifdef IPV6
+ if (old_class->cidr_bitlen_ipv6 > 0 && new_class->cidr_bitlen_ipv6 > 0)
+ rebuild_cidr_list(AF_INET6, conf, new_class,
+ &old_class->list_ipv6, &new_class->list_ipv6,
+ old_class->cidr_bitlen_ipv6 != new_class->cidr_bitlen_ipv6);
+#endif
+ }
+
+ destroy_cidr_class(old_class);
+}
+
+/*
+ * destroy_cidr_list
+ *
+ * inputs - pointer to class dlink list of cidr blocks
+ * output - none
+ * side effects - completely destroys the class link list of cidr blocks
+ */
+static void
+destroy_cidr_list(dlink_list *list)
+{
+ dlink_node *ptr = NULL, *next_ptr = NULL;
+
+ DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
+ {
+ dlinkDelete(ptr, list);
+ MyFree(ptr->data);
+ }
+}
+
+/*
+ * destroy_cidr_class
+ *
+ * inputs - pointer to class
+ * output - none
+ * side effects - completely destroys the class link list of cidr blocks
+ */
+static void
+destroy_cidr_class(struct ClassItem *aclass)
+{
+ destroy_cidr_list(&aclass->list_ipv4);
+ destroy_cidr_list(&aclass->list_ipv6);
+}
diff --git a/src/conf_lexer.c b/src/conf_lexer.c
new file mode 100644
index 0000000..e9d42bb
--- /dev/null
+++ b/src/conf_lexer.c
@@ -0,0 +1,4278 @@
+
+#line 3 "conf_lexer.c"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 37
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart(yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+extern yy_size_t yyleng;
+
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = (yy_hold_char); \
+ YY_RESTORE_YY_MORE_OFFSET \
+ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr) )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ yy_size_t yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */
+yy_size_t yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart (FILE *input_file );
+void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer );
+YY_BUFFER_STATE yy_create_buffer (FILE *file,int size );
+void yy_delete_buffer (YY_BUFFER_STATE b );
+void yy_flush_buffer (YY_BUFFER_STATE b );
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer );
+void yypop_buffer_state (void );
+
+static void yyensure_buffer_stack (void );
+static void yy_load_buffer_state (void );
+static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file );
+
+#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size );
+YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len );
+
+void *yyalloc (yy_size_t );
+void *yyrealloc (void *,yy_size_t );
+void yyfree (void * );
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define yywrap() 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int yylineno;
+
+int yylineno = 1;
+
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[] );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ (yytext_ptr) = yy_bp; \
+ (yytext_ptr) -= (yy_more_len); \
+ yyleng = (size_t) (yy_cp - (yytext_ptr)); \
+ (yy_hold_char) = *yy_cp; \
+ *yy_cp = '\0'; \
+ (yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 238
+#define YY_END_OF_BUFFER 239
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[1546] =
+ { 0,
+ 4, 4, 239, 237, 4, 3, 237, 5, 237, 237,
+ 6, 237, 237, 237, 237, 237, 237, 237, 237, 237,
+ 237, 237, 237, 237, 237, 237, 237, 237, 237, 237,
+ 237, 237, 237, 237, 237, 237, 4, 3, 0, 7,
+ 5, 236, 0, 2, 5, 6, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 68, 0, 230, 0, 0, 0, 0, 0, 0,
+ 0, 235, 0, 0, 0, 0, 0, 0, 0, 96,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 12, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 217, 0, 0,
+ 0, 0, 0, 30, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 64, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 79, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 203, 0, 0, 0,
+ 0, 0, 0, 143, 0, 0, 146, 0, 0, 0,
+ 0, 205, 128, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 164, 0, 0, 0, 0, 0, 13,
+ 0, 195, 225, 0, 0, 0, 0, 0, 0, 0,
+ 0, 216, 198, 0, 0, 28, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 41, 0, 0,
+ 200, 0, 0, 0, 0, 0, 0, 0, 63, 219,
+
+ 0, 0, 0, 69, 70, 0, 0, 73, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 90, 0, 0, 0, 94, 0, 0,
+ 0, 0, 0, 103, 0, 0, 189, 0, 111, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 124, 0,
+ 0, 0, 0, 0, 0, 147, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 151, 0,
+ 0, 0, 0, 0, 0, 0, 160, 0, 0, 0,
+ 0, 215, 0, 0, 0, 9, 0, 0, 0, 224,
+ 0, 0, 196, 0, 0, 21, 0, 0, 199, 0,
+
+ 0, 0, 34, 0, 0, 37, 0, 0, 0, 0,
+ 0, 42, 0, 44, 0, 46, 0, 0, 0, 0,
+ 0, 0, 218, 0, 0, 0, 0, 229, 0, 0,
+ 75, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 234, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 115, 0, 118, 0, 0, 0, 0, 0, 0,
+ 0, 137, 0, 0, 0, 0, 0, 0, 201, 0,
+ 148, 134, 0, 0, 0, 0, 0, 0, 135, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 161, 0, 0, 214, 163, 0, 0, 0, 11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 40, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 58, 0, 0,
+ 0, 0, 0, 228, 0, 0, 0, 0, 0, 0,
+ 78, 213, 80, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 233, 0, 0, 221, 0, 188,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 106, 0, 0,
+
+ 0, 0, 0, 0, 114, 0, 0, 119, 120, 0,
+ 0, 0, 0, 0, 223, 0, 138, 0, 0, 144,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 153, 204, 0, 0, 0, 192,
+ 0, 0, 0, 162, 210, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 18, 0, 22, 23,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 45, 0, 0, 0, 0, 0, 53, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 220, 0, 187, 202, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 122, 0, 0, 0, 0, 222,
+ 0, 0, 0, 141, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 155, 154, 0, 191, 157, 0, 0,
+ 0, 0, 0, 0, 0, 14, 211, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 206,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 65, 0, 0, 0, 0, 227, 0,
+ 0, 0, 0, 0, 186, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 232, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 100, 0, 105, 0, 207, 0,
+ 0, 0, 0, 107, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 38, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 209, 0,
+ 0, 226, 0, 0, 77, 0, 0, 0, 0, 0,
+ 82, 83, 0, 0, 0, 86, 231, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 182, 0, 109, 0, 0, 0, 116, 117,
+ 121, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 156, 0,
+ 0, 0, 1, 0, 1, 0, 0, 0, 0, 0,
+
+ 197, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 55, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 166, 0, 0, 84, 0, 0, 85, 0,
+ 0, 0, 56, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 112, 0,
+ 0, 0, 0, 0, 0, 139, 140, 0, 208, 145,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 24, 0, 0, 29, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 54, 0, 59, 0, 0, 0, 0, 0,
+ 0, 0, 184, 175, 0, 81, 0, 0, 190, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 194, 0, 108, 0, 0, 0, 125, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 158, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 31, 0, 0, 0, 36, 39, 0, 0, 0, 47,
+ 48, 0, 0, 0, 61, 0, 0, 0, 0, 0,
+
+ 0, 0, 76, 0, 0, 0, 0, 0, 0, 0,
+ 92, 93, 95, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 110, 113, 0, 0, 0, 0, 0, 212,
+ 149, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 173, 0, 0, 0, 10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 35, 0, 43,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 170, 0, 0, 91, 0, 0,
+ 99, 0, 102, 0, 0, 0, 0, 0, 0, 0,
+ 136, 142, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 159, 0, 0, 174, 176, 0, 0, 0,
+ 16, 0, 0, 0, 0, 0, 0, 49, 51, 0,
+ 0, 0, 62, 0, 0, 0, 0, 0, 0, 0,
+ 0, 87, 0, 0, 0, 0, 0, 0, 104, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 8, 171, 0, 0, 0,
+ 0, 0, 0, 0, 0, 52, 0, 0, 60, 66,
+ 0, 0, 72, 0, 0, 0, 0, 0, 88, 0,
+ 0, 101, 0, 0, 0, 0, 0, 0, 0, 133,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 19, 20, 0, 0, 0, 0, 0, 0, 0,
+ 57, 0, 71, 0, 0, 0, 0, 167, 0, 0,
+ 98, 0, 193, 183, 0, 0, 0, 0, 0, 0,
+ 0, 177, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 123, 0, 0, 0, 130, 132,
+ 131, 180, 179, 178, 181, 0, 0, 0, 25, 0,
+ 0, 0, 0, 165, 0, 0, 0, 0, 168, 169,
+ 0, 97, 0, 0, 0, 0, 0, 152, 0, 0,
+ 0, 0, 0, 0, 0, 0, 185, 0, 0, 0,
+
+ 127, 0, 0, 0, 0, 0, 0, 0, 0, 67,
+ 0, 0, 0, 126, 129, 0, 0, 0, 0, 32,
+ 0, 0, 74, 0, 17, 150, 0, 0, 0, 0,
+ 50, 89, 0, 0, 0, 33, 0, 0, 27, 0,
+ 0, 0, 26, 172, 0
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 1, 4, 5, 1, 1, 1, 1, 1,
+ 1, 6, 1, 1, 1, 7, 8, 9, 10, 9,
+ 11, 12, 9, 13, 9, 9, 9, 1, 1, 14,
+ 1, 15, 1, 1, 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,
+ 1, 1, 1, 1, 42, 1, 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, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int32_t yy_meta[69] =
+ { 0,
+ 1, 1, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int16_t yy_base[1551] =
+ { 0,
+ 0, 0, 2962, 2963, 2959, 0, 66, 0, 64, 66,
+ 66, 98, 43, 146, 75, 58, 85, 76, 117, 109,
+ 51, 154, 155, 197, 239, 53, 177, 57, 125, 283,
+ 323, 190, 127, 168, 128, 143, 2958, 0, 86, 2963,
+ 0, 2963, 166, 2963, 0, 220, 181, 181, 181, 196,
+ 190, 200, 202, 203, 220, 209, 237, 237, 242, 231,
+ 221, 326, 247, 244, 235, 252, 256, 255, 292, 253,
+ 262, 276, 266, 303, 301, 264, 292, 290, 318, 332,
+ 327, 328, 342, 327, 341, 347, 342, 359, 351, 378,
+ 347, 338, 367, 350, 378, 375, 381, 390, 391, 2917,
+
+ 383, 394, 399, 386, 385, 405, 446, 403, 422, 433,
+ 413, 396, 405, 443, 412, 427, 417, 431, 438, 439,
+ 2916, 448, 456, 498, 468, 463, 476, 474, 481, 474,
+ 493, 492, 492, 478, 2963, 495, 499, 489, 506, 500,
+ 2915, 499, 504, 501, 506, 508, 518, 514, 536, 523,
+ 546, 523, 547, 2963, 550, 539, 536, 540, 548, 540,
+ 556, 549, 558, 552, 560, 559, 555, 553, 565, 558,
+ 571, 571, 582, 561, 578, 2914, 583, 592, 144, 588,
+ 584, 595, 591, 606, 605, 601, 595, 601, 2963, 606,
+ 2913, 598, 618, 601, 600, 601, 619, 625, 626, 610,
+
+ 624, 649, 638, 623, 645, 635, 647, 649, 638, 643,
+ 658, 646, 644, 661, 666, 671, 2963, 658, 654, 2912,
+ 660, 674, 658, 2963, 666, 669, 2963, 684, 682, 675,
+ 689, 2963, 686, 686, 694, 701, 690, 710, 704, 713,
+ 715, 699, 711, 712, 716, 721, 716, 711, 711, 720,
+ 720, 729, 727, 2963, 731, 732, 735, 742, 2911, 2963,
+ 757, 2963, 743, 758, 758, 751, 752, 2910, 750, 751,
+ 767, 2963, 2963, 766, 753, 2963, 759, 776, 774, 2909,
+ 765, 769, 757, 778, 768, 768, 783, 2963, 775, 775,
+ 2963, 778, 784, 798, 811, 800, 811, 2908, 2963, 798,
+
+ 805, 801, 801, 2963, 2963, 2907, 818, 2906, 823, 823,
+ 820, 2905, 813, 828, 818, 830, 862, 835, 846, 850,
+ 834, 842, 845, 2963, 852, 2904, 853, 2903, 852, 857,
+ 857, 868, 874, 888, 2902, 863, 2963, 2901, 2963, 886,
+ 874, 887, 888, 890, 886, 898, 898, 918, 2900, 904,
+ 908, 906, 934, 919, 905, 2963, 914, 924, 922, 2930,
+ 937, 911, 911, 928, 2930, 2897, 958, 959, 2963, 956,
+ 942, 955, 956, 958, 953, 964, 2963, 969, 956, 962,
+ 2896, 959, 974, 959, 962, 975, 980, 976, 978, 2963,
+ 976, 984, 2895, 992, 1000, 2963, 1005, 1010, 2963, 1002,
+
+ 1006, 1004, 2963, 1009, 1004, 2963, 1009, 1022, 1007, 1014,
+ 1026, 2963, 1026, 2963, 1031, 2894, 1021, 1018, 1015, 1027,
+ 1024, 1020, 2963, 1043, 1042, 1039, 1043, 1031, 1048, 1031,
+ 2893, 2892, 1051, 2891, 1053, 1049, 1065, 1067, 1071, 1072,
+ 1061, 1075, 1066, 1077, 1081, 1084, 1068, 1063, 1082, 1085,
+ 1077, 1088, 1094, 1094, 1084, 1101, 1100, 1109, 1116, 1110,
+ 1105, 1104, 2890, 1125, 1118, 1104, 1131, 1135, 1122, 2889,
+ 1126, 2963, 1125, 2963, 1134, 1138, 1129, 1143, 1151, 1154,
+ 1153, 2963, 1143, 1146, 1173, 1162, 1174, 2888, 2963, 1179,
+ 2887, 2963, 1183, 1173, 1182, 2886, 1169, 1185, 2963, 1179,
+
+ 1170, 1178, 1178, 1190, 1186, 1187, 1197, 1187, 1196, 1204,
+ 1197, 2914, 1197, 1204, 2963, 2963, 1222, 2884, 1210, 2963,
+ 1221, 1215, 1218, 1225, 1220, 1235, 1230, 1234, 1226, 1226,
+ 1227, 1232, 1244, 1236, 1239, 1234, 2883, 2963, 1254, 2882,
+ 1246, 1251, 1275, 2881, 1245, 2880, 1261, 2879, 1267, 1248,
+ 2878, 1282, 1273, 2963, 1278, 1269, 1290, 1292, 1296, 1294,
+ 2963, 2963, 2963, 1297, 1287, 1301, 1294, 1289, 1300, 1305,
+ 1306, 1301, 1299, 1298, 2963, 1299, 1316, 1307, 1319, 1315,
+ 1332, 1334, 1338, 1329, 1334, 1342, 1333, 1331, 1346, 2877,
+ 1336, 1350, 1342, 1341, 1355, 1344, 1357, 2963, 1341, 1347,
+
+ 1354, 1367, 1351, 1357, 2963, 1358, 1370, 2963, 1378, 1367,
+ 1385, 1367, 1383, 1391, 1375, 1395, 1395, 1392, 1381, 2963,
+ 1392, 1394, 1394, 1391, 1394, 1402, 2876, 1394, 1435, 1404,
+ 2875, 1407, 2874, 1411, 2963, 2963, 1421, 1422, 1409, 2963,
+ 1429, 1437, 1435, 2963, 2963, 1430, 1442, 1432, 1435, 1454,
+ 1457, 1445, 1456, 1453, 1448, 1443, 2963, 1445, 2963, 1460,
+ 2873, 1450, 2872, 2871, 2870, 1471, 1467, 1468, 1466, 2869,
+ 2963, 1462, 1474, 1485, 1490, 1485, 2963, 1481, 1495, 1487,
+ 1484, 1489, 1494, 1507, 1499, 1497, 1512, 1509, 1492, 1512,
+ 1499, 1514, 1515, 1505, 1516, 1528, 1532, 1521, 1536, 1531,
+
+ 1546, 1542, 1547, 1547, 2868, 2963, 1530, 2963, 2963, 1549,
+ 1536, 2867, 1555, 1538, 2866, 2865, 1554, 1547, 1547, 1541,
+ 1555, 1556, 1551, 1556, 1563, 1569, 1559, 1565, 1566, 1578,
+ 1574, 1571, 1573, 1595, 2963, 1582, 1598, 1582, 1594, 2963,
+ 1588, 1599, 1595, 1591, 1603, 1598, 1605, 1604, 1600, 1613,
+ 1617, 1608, 1603, 2864, 2863, 2862, 2861, 2860, 1621, 1622,
+ 2859, 1624, 2858, 2963, 2963, 1627, 2963, 2963, 1631, 2857,
+ 90, 1640, 1624, 1632, 1632, 2963, 2963, 1646, 1652, 1645,
+ 1646, 1642, 1655, 1653, 1672, 1655, 1650, 1663, 1662, 2963,
+ 1659, 1664, 1661, 1679, 1676, 1668, 1669, 1683, 1690, 1682,
+
+ 1696, 1677, 1689, 2963, 1695, 1706, 1697, 1695, 1696, 1711,
+ 1706, 1709, 1709, 1709, 2963, 1708, 1714, 1728, 1710, 1720,
+ 2856, 1728, 1729, 1727, 1717, 1728, 1735, 1732, 1730, 1754,
+ 1736, 1746, 1738, 1758, 2963, 1760, 2963, 1750, 2963, 1744,
+ 1751, 1768, 1754, 2963, 1764, 1774, 1767, 1768, 2855, 1763,
+ 1762, 1772, 2854, 1774, 1787, 1780, 1771, 1790, 1792, 2853,
+ 1797, 1783, 1799, 1785, 1798, 1807, 1804, 1818, 1815, 1818,
+ 1808, 1809, 1811, 1813, 2852, 1805, 1818, 1830, 1832, 1833,
+ 1829, 1826, 190, 2889, 2877, 1822, 1841, 2849, 2848, 2847,
+ 2963, 1831, 1839, 1843, 1840, 1838, 1842, 1837, 1858, 1856,
+
+ 1862, 1871, 2963, 1860, 1869, 1867, 1876, 1876, 1867, 2846,
+ 1861, 1871, 1886, 1869, 1877, 1886, 1886, 1887, 2845, 1891,
+ 1891, 2963, 1884, 1897, 2963, 1901, 1886, 2844, 1888, 1899,
+ 2963, 2963, 1910, 1894, 1895, 2963, 2963, 1905, 1914, 1907,
+ 1905, 1926, 1931, 1927, 2843, 1922, 1925, 1923, 1942, 2842,
+ 2841, 1939, 2840, 1936, 2963, 1937, 1943, 1947, 2963, 2963,
+ 2963, 1947, 1935, 1932, 1953, 1937, 1957, 1950, 1952, 1962,
+ 1965, 1956, 1971, 1975, 1964, 1964, 1967, 1968, 1979, 1974,
+ 1975, 1979, 1981, 1978, 1983, 1984, 1990, 1998, 2963, 1990,
+ 1993, 2877, 2876, 2864, 2863, 1987, 1990, 2008, 2011, 1996,
+
+ 2963, 2006, 2004, 2008, 2016, 2020, 2015, 2025, 2025, 2034,
+ 2020, 2033, 2026, 2031, 2029, 2039, 2036, 2050, 2049, 2044,
+ 2053, 2963, 2053, 2041, 2832, 2039, 2049, 2828, 2827, 2052,
+ 2045, 2048, 2963, 2058, 2056, 2963, 2069, 2073, 2963, 2069,
+ 2086, 2086, 2963, 2077, 2074, 2081, 2091, 2083, 2825, 2084,
+ 2823, 2084, 2084, 2088, 2088, 2089, 2105, 2097, 2963, 2111,
+ 2105, 2094, 2113, 2822, 2107, 2963, 2963, 2123, 2963, 2963,
+ 2118, 2125, 2120, 2821, 2819, 2130, 2818, 2117, 2137, 2138,
+ 2139, 2141, 2138, 2139, 2145, 2132, 2141, 2150, 2150, 2137,
+ 2146, 2150, 2140, 2164, 2817, 2963, 2151, 2158, 2963, 2160,
+
+ 2167, 2161, 2164, 2173, 2162, 2811, 2172, 2176, 2185, 2176,
+ 2188, 2179, 2963, 2808, 2963, 2187, 2191, 2182, 2188, 2201,
+ 2187, 2191, 1636, 2963, 2208, 2963, 2214, 2203, 2963, 2217,
+ 2216, 2202, 2219, 2221, 2211, 2218, 2216, 2221, 2241, 2218,
+ 2226, 2236, 2963, 2242, 2963, 2245, 2240, 2254, 2963, 1390,
+ 2245, 2240, 2247, 2257, 2260, 2264, 2257, 2257, 2259, 2260,
+ 2273, 2257, 2258, 2262, 2266, 2273, 2271, 2272, 2290, 2273,
+ 2963, 2281, 2283, 2286, 2290, 2297, 2299, 2300, 2306, 2292,
+ 2963, 1386, 2294, 2295, 2963, 2963, 2305, 2302, 2308, 2963,
+ 2963, 2320, 2306, 2324, 2963, 2319, 2313, 1239, 861, 2315,
+
+ 2325, 2329, 2963, 2337, 2325, 2330, 2340, 2335, 2348, 2348,
+ 2963, 2963, 2963, 853, 2342, 2355, 2351, 2346, 822, 2348,
+ 2345, 2353, 2963, 2963, 2354, 2358, 2368, 2371, 2372, 2963,
+ 2963, 2377, 2371, 2376, 815, 2377, 2381, 811, 810, 809,
+ 462, 2379, 2383, 455, 2963, 2391, 2389, 2379, 2963, 2383,
+ 2379, 2381, 2387, 2403, 445, 2409, 2408, 2963, 2399, 2963,
+ 2402, 2399, 393, 2403, 2404, 2403, 2403, 2424, 2408, 2418,
+ 2419, 2426, 380, 2428, 2963, 2431, 2419, 2963, 2419, 2430,
+ 2963, 2442, 2963, 2445, 2447, 2430, 2437, 2441, 2452, 2435,
+ 2963, 2963, 2446, 2448, 2448, 2464, 2451, 2460, 2459, 2461,
+
+ 2462, 2466, 2963, 287, 2477, 2963, 2963, 2481, 2482, 273,
+ 2963, 2466, 2474, 2471, 2483, 249, 2476, 2963, 266, 2496,
+ 2488, 2486, 2963, 2487, 2492, 2495, 2506, 2509, 2519, 2507,
+ 2516, 2963, 2520, 2509, 2517, 2512, 2530, 2530, 2963, 2525,
+ 2534, 2515, 200, 2537, 2523, 2536, 2536, 2538, 2545, 2540,
+ 2542, 2545, 2546, 2547, 2551, 2963, 2963, 2552, 310, 2547,
+ 2569, 2556, 2575, 2575, 2570, 2963, 2559, 2576, 2963, 2963,
+ 2570, 2565, 2963, 145, 2575, 2575, 2574, 2575, 124, 2584,
+ 2577, 2963, 2586, 2580, 2595, 2592, 109, 2602, 107, 2963,
+ 2595, 2601, 2599, 2611, 2605, 2607, 2610, 2616, 2614, 2615,
+
+ 2627, 2963, 2963, 2619, 2616, 2631, 2624, 2624, 2640, 2627,
+ 2963, 2633, 2963, 2636, 2636, 2646, 2647, 2963, 2634, 2645,
+ 2963, 2646, 2963, 2963, 2643, 2658, 2658, 2662, 2665, 2666,
+ 2669, 2963, 2651, 2657, 2658, 2659, 2666, 2672, 2669, 2670,
+ 2670, 2675, 2683, 2686, 2696, 2701, 2699, 2696, 2701, 2689,
+ 2690, 2703, 2696, 2713, 2963, 2712, 2710, 2714, 2963, 2963,
+ 2963, 2963, 2963, 2963, 2963, 2716, 2723, 2711, 2963, 2731,
+ 100, 2732, 2725, 2963, 2720, 2738, 2729, 2732, 2963, 2963,
+ 2733, 2963, 2729, 2739, 2748, 2743, 2753, 2963, 2757, 2741,
+ 2757, 2749, 2761, 2757, 2750, 2763, 2963, 2759, 2767, 2772,
+
+ 2963, 2774, 2776, 2777, 95, 2775, 2772, 2778, 2779, 2963,
+ 2775, 2784, 2794, 2963, 2963, 2781, 2796, 2802, 2786, 2963,
+ 2805, 2796, 2963, 2807, 2963, 2963, 93, 2798, 2800, 2796,
+ 2963, 2963, 2796, 2799, 2804, 2963, 2817, 2815, 2963, 2817,
+ 2811, 2828, 2963, 2963, 2963, 105, 2875, 97, 84, 81
+ } ;
+
+static yyconst flex_int16_t yy_def[1551] =
+ { 0,
+ 1545, 1, 1545, 1545, 1545, 1546, 1547, 1548, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1546, 1547, 1545,
+ 1548, 1545, 1545, 1545, 1548, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1549, 1550, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1549, 1549, 1550, 1550, 1545, 1545, 1545, 1545, 1545,
+
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 0, 1545, 1545, 1545, 1545, 1545
+ } ;
+
+static yyconst flex_int16_t yy_nxt[3032] =
+ { 0,
+ 4, 5, 6, 7, 8, 4, 9, 10, 11, 11,
+ 11, 11, 11, 4, 4, 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,
+ 4, 4, 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, 4, 40, 40,
+ 42, 44, 53, 45, 46, 46, 46, 46, 46, 66,
+ 83, 994, 54, 102, 992, 67, 68, 43, 40, 40,
+ 61, 883, 106, 884, 62, 74, 69, 41, 63, 53,
+
+ 70, 64, 75, 885, 65, 38, 66, 83, 71, 54,
+ 102, 72, 67, 68, 43, 47, 48, 61, 49, 106,
+ 73, 62, 74, 69, 50, 63, 51, 70, 64, 75,
+ 80, 65, 76, 52, 1533, 71, 1518, 81, 72, 82,
+ 77, 1491, 47, 48, 107, 49, 78, 73, 1428, 126,
+ 1426, 50, 79, 51, 129, 304, 305, 80, 108, 76,
+ 52, 55, 130, 56, 81, 1419, 82, 77, 57, 58,
+ 84, 107, 59, 78, 88, 60, 126, 85, 89, 79,
+ 86, 129, 87, 127, 90, 108, 1414, 128, 55, 130,
+ 56, 883, 103, 884, 131, 57, 58, 84, 132, 59,
+
+ 104, 88, 60, 885, 85, 89, 105, 86, 133, 87,
+ 127, 90, 91, 92, 128, 134, 93, 123, 124, 103,
+ 94, 131, 135, 125, 136, 132, 95, 104, 46, 46,
+ 46, 46, 46, 105, 137, 133, 138, 139, 142, 91,
+ 92, 1388, 134, 93, 123, 124, 140, 94, 141, 135,
+ 125, 136, 143, 95, 96, 144, 97, 145, 98, 147,
+ 148, 137, 99, 138, 139, 142, 154, 156, 100, 157,
+ 158, 159, 160, 140, 101, 141, 164, 146, 1366, 143,
+ 155, 96, 144, 97, 145, 98, 147, 148, 165, 99,
+ 1364, 166, 167, 154, 156, 100, 157, 158, 159, 160,
+
+ 172, 101, 109, 164, 146, 110, 111, 155, 112, 161,
+ 173, 162, 113, 114, 1358, 165, 115, 116, 166, 167,
+ 168, 1402, 1403, 174, 170, 175, 163, 172, 1354, 109,
+ 171, 169, 110, 111, 176, 112, 161, 173, 162, 113,
+ 114, 149, 150, 115, 116, 117, 151, 168, 118, 119,
+ 174, 170, 175, 163, 152, 120, 121, 171, 169, 153,
+ 177, 176, 122, 178, 179, 180, 181, 182, 149, 150,
+ 183, 184, 117, 151, 185, 118, 119, 192, 195, 186,
+ 190, 152, 120, 121, 187, 191, 153, 177, 193, 122,
+ 178, 179, 180, 181, 182, 188, 196, 183, 184, 189,
+
+ 194, 185, 197, 198, 192, 195, 186, 190, 201, 199,
+ 203, 187, 191, 204, 208, 193, 205, 209, 220, 229,
+ 210, 1330, 188, 196, 200, 230, 189, 194, 211, 197,
+ 198, 227, 206, 207, 1320, 201, 199, 203, 233, 221,
+ 204, 208, 234, 205, 209, 220, 229, 210, 225, 235,
+ 222, 200, 230, 228, 223, 211, 224, 236, 227, 206,
+ 207, 212, 226, 213, 214, 233, 221, 215, 216, 234,
+ 217, 237, 231, 218, 238, 225, 235, 222, 240, 219,
+ 228, 223, 232, 224, 236, 241, 1314, 248, 212, 226,
+ 213, 214, 249, 252, 215, 216, 1305, 217, 237, 231,
+
+ 218, 238, 250, 1302, 253, 240, 219, 254, 251, 232,
+ 255, 256, 241, 242, 248, 257, 243, 258, 259, 249,
+ 252, 260, 262, 244, 245, 263, 264, 266, 261, 250,
+ 246, 253, 267, 268, 254, 251, 247, 255, 256, 269,
+ 242, 270, 257, 243, 258, 259, 271, 272, 260, 262,
+ 244, 245, 263, 264, 266, 261, 273, 246, 274, 267,
+ 268, 275, 276, 247, 277, 278, 269, 279, 270, 280,
+ 281, 282, 283, 271, 272, 284, 285, 286, 287, 288,
+ 289, 291, 292, 273, 293, 274, 294, 295, 275, 276,
+ 296, 277, 278, 290, 279, 299, 280, 281, 282, 283,
+
+ 297, 298, 284, 285, 286, 287, 288, 289, 291, 292,
+ 300, 293, 302, 294, 295, 303, 306, 296, 307, 310,
+ 290, 308, 299, 311, 309, 312, 313, 297, 298, 314,
+ 315, 316, 318, 319, 320, 321, 323, 300, 324, 302,
+ 325, 322, 303, 306, 326, 307, 310, 327, 308, 328,
+ 311, 309, 312, 313, 333, 334, 314, 315, 316, 318,
+ 319, 320, 321, 323, 335, 324, 329, 325, 336, 337,
+ 338, 326, 339, 330, 327, 340, 328, 341, 331, 342,
+ 343, 333, 334, 332, 344, 345, 346, 347, 348, 351,
+ 349, 335, 352, 329, 353, 336, 337, 338, 354, 339,
+
+ 330, 355, 340, 356, 341, 331, 342, 343, 357, 358,
+ 332, 344, 345, 346, 347, 348, 351, 349, 359, 352,
+ 362, 353, 360, 363, 364, 354, 365, 361, 355, 366,
+ 356, 367, 369, 370, 371, 357, 358, 372, 373, 374,
+ 375, 368, 376, 377, 379, 359, 380, 362, 381, 360,
+ 363, 364, 378, 365, 382, 383, 366, 384, 367, 369,
+ 370, 371, 385, 386, 372, 373, 374, 375, 368, 376,
+ 377, 379, 387, 380, 389, 381, 390, 391, 392, 393,
+ 394, 382, 383, 396, 384, 397, 398, 399, 400, 385,
+ 386, 401, 402, 403, 405, 406, 407, 408, 409, 387,
+
+ 410, 389, 411, 390, 391, 392, 393, 394, 412, 413,
+ 396, 414, 397, 398, 399, 400, 415, 416, 401, 402,
+ 403, 405, 406, 407, 408, 409, 417, 410, 419, 411,
+ 421, 423, 424, 425, 426, 412, 413, 428, 414, 430,
+ 418, 420, 431, 415, 416, 432, 434, 435, 436, 437,
+ 1301, 1300, 1299, 417, 447, 419, 1296, 421, 423, 424,
+ 425, 426, 448, 1284, 428, 449, 430, 418, 450, 431,
+ 451, 452, 432, 434, 435, 436, 437, 438, 439, 440,
+ 453, 447, 455, 441, 457, 442, 458, 459, 443, 448,
+ 444, 460, 449, 461, 1279, 450, 445, 451, 452, 446,
+
+ 467, 469, 1268, 462, 438, 439, 440, 453, 470, 455,
+ 441, 457, 442, 458, 459, 443, 471, 444, 460, 472,
+ 461, 463, 473, 445, 474, 464, 446, 467, 469, 465,
+ 462, 475, 476, 477, 480, 470, 481, 482, 487, 488,
+ 489, 490, 491, 471, 496, 497, 472, 483, 463, 473,
+ 478, 474, 464, 484, 493, 494, 498, 485, 475, 476,
+ 477, 480, 486, 481, 482, 487, 488, 489, 490, 491,
+ 495, 496, 497, 501, 502, 503, 504, 478, 505, 506,
+ 484, 493, 494, 498, 485, 507, 508, 509, 510, 486,
+ 512, 513, 515, 516, 517, 511, 518, 495, 519, 520,
+
+ 501, 502, 503, 504, 521, 505, 506, 523, 524, 522,
+ 525, 527, 507, 508, 509, 510, 528, 512, 513, 515,
+ 516, 517, 511, 518, 529, 519, 520, 530, 531, 532,
+ 533, 521, 534, 535, 523, 524, 522, 525, 527, 536,
+ 537, 538, 539, 528, 540, 541, 542, 544, 545, 546,
+ 547, 529, 548, 549, 530, 531, 532, 533, 550, 534,
+ 535, 551, 552, 553, 554, 555, 536, 537, 538, 539,
+ 556, 540, 541, 542, 544, 545, 546, 547, 559, 548,
+ 549, 561, 562, 563, 564, 550, 565, 568, 551, 552,
+ 553, 554, 555, 569, 566, 570, 573, 556, 567, 574,
+
+ 571, 575, 576, 577, 578, 559, 579, 580, 561, 562,
+ 563, 564, 572, 565, 568, 581, 584, 582, 585, 586,
+ 569, 566, 570, 573, 583, 567, 574, 571, 575, 576,
+ 577, 578, 587, 579, 580, 588, 589, 590, 591, 572,
+ 593, 597, 581, 584, 582, 585, 586, 594, 595, 598,
+ 603, 583, 600, 596, 605, 606, 608, 609, 607, 587,
+ 599, 610, 588, 589, 590, 591, 611, 593, 597, 601,
+ 612, 615, 602, 616, 594, 595, 598, 603, 617, 600,
+ 596, 605, 606, 608, 609, 607, 613, 599, 610, 614,
+ 618, 619, 620, 611, 622, 627, 601, 612, 615, 602,
+
+ 616, 628, 624, 630, 631, 617, 625, 632, 633, 626,
+ 634, 635, 636, 613, 637, 638, 614, 618, 619, 620,
+ 639, 622, 627, 640, 641, 642, 643, 645, 628, 624,
+ 630, 631, 646, 625, 632, 633, 626, 634, 635, 636,
+ 647, 637, 638, 649, 650, 651, 652, 639, 653, 655,
+ 640, 641, 642, 643, 645, 656, 657, 658, 659, 646,
+ 660, 661, 662, 663, 664, 665, 654, 647, 666, 668,
+ 649, 650, 651, 652, 670, 653, 655, 671, 677, 679,
+ 1267, 683, 656, 657, 658, 659, 681, 660, 661, 662,
+ 663, 664, 665, 672, 673, 666, 668, 682, 685, 686,
+
+ 687, 670, 674, 688, 671, 677, 679, 675, 683, 689,
+ 690, 691, 692, 681, 693, 694, 695, 696, 697, 698,
+ 672, 673, 699, 700, 682, 685, 686, 687, 701, 674,
+ 688, 702, 703, 704, 675, 705, 689, 690, 691, 692,
+ 706, 693, 694, 695, 696, 697, 698, 707, 708, 699,
+ 700, 709, 710, 711, 712, 701, 713, 714, 702, 703,
+ 704, 715, 705, 716, 717, 719, 720, 706, 721, 722,
+ 723, 724, 725, 726, 707, 708, 727, 728, 709, 710,
+ 711, 712, 729, 713, 714, 730, 731, 732, 715, 733,
+ 716, 717, 719, 720, 734, 721, 722, 723, 724, 725,
+
+ 726, 735, 736, 727, 728, 737, 738, 739, 740, 729,
+ 741, 744, 730, 731, 732, 745, 733, 742, 743, 746,
+ 747, 734, 748, 749, 750, 751, 753, 1256, 735, 736,
+ 759, 1226, 737, 738, 739, 740, 761, 741, 744, 763,
+ 764, 765, 745, 766, 742, 743, 746, 747, 767, 748,
+ 749, 750, 751, 753, 754, 768, 769, 759, 755, 770,
+ 756, 771, 772, 761, 757, 758, 763, 764, 765, 773,
+ 766, 774, 775, 776, 777, 767, 778, 779, 780, 781,
+ 782, 754, 768, 769, 784, 755, 770, 756, 771, 772,
+ 788, 757, 758, 789, 790, 791, 773, 793, 774, 775,
+
+ 776, 777, 794, 778, 779, 780, 781, 782, 796, 797,
+ 798, 784, 795, 799, 800, 801, 802, 788, 803, 804,
+ 789, 790, 791, 805, 793, 806, 807, 808, 809, 794,
+ 810, 811, 812, 813, 814, 796, 797, 798, 815, 795,
+ 799, 800, 801, 802, 816, 803, 804, 817, 818, 819,
+ 805, 820, 806, 807, 808, 809, 821, 810, 811, 812,
+ 813, 814, 822, 823, 824, 815, 825, 827, 828, 829,
+ 831, 816, 832, 835, 817, 818, 819, 836, 820, 837,
+ 838, 839, 840, 821, 841, 842, 843, 844, 845, 822,
+ 823, 824, 846, 825, 827, 828, 829, 831, 847, 832,
+
+ 835, 848, 849, 850, 836, 851, 837, 838, 839, 840,
+ 852, 841, 842, 843, 844, 845, 853, 854, 855, 846,
+ 856, 857, 858, 859, 860, 847, 861, 862, 848, 849,
+ 850, 863, 851, 864, 865, 866, 867, 852, 868, 869,
+ 875, 876, 878, 853, 854, 855, 880, 856, 857, 858,
+ 859, 860, 881, 861, 862, 886, 887, 888, 863, 889,
+ 864, 865, 866, 867, 890, 868, 869, 875, 876, 878,
+ 891, 892, 893, 880, 894, 895, 897, 1204, 901, 881,
+ 902, 903, 886, 887, 888, 904, 889, 898, 896, 905,
+ 906, 890, 899, 907, 908, 909, 910, 891, 892, 893,
+
+ 911, 894, 895, 897, 900, 901, 912, 902, 903, 913,
+ 914, 915, 904, 916, 898, 896, 905, 906, 917, 899,
+ 907, 908, 909, 910, 918, 919, 920, 911, 921, 922,
+ 923, 900, 924, 912, 925, 926, 913, 914, 915, 927,
+ 916, 928, 929, 930, 931, 917, 932, 934, 935, 936,
+ 937, 918, 919, 920, 938, 921, 922, 923, 939, 924,
+ 940, 925, 926, 941, 944, 945, 927, 946, 928, 929,
+ 930, 931, 942, 932, 934, 935, 936, 937, 947, 948,
+ 949, 938, 943, 950, 951, 939, 952, 940, 953, 954,
+ 941, 944, 945, 955, 946, 956, 957, 959, 960, 942,
+
+ 961, 963, 964, 965, 966, 947, 948, 949, 967, 943,
+ 950, 951, 968, 952, 970, 953, 954, 971, 972, 973,
+ 955, 974, 956, 957, 959, 960, 975, 961, 963, 964,
+ 965, 966, 976, 977, 978, 967, 979, 980, 981, 968,
+ 982, 970, 983, 985, 971, 972, 973, 986, 974, 987,
+ 988, 989, 990, 975, 991, 996, 997, 1001, 1002, 976,
+ 977, 978, 1003, 979, 980, 981, 1004, 982, 1005, 983,
+ 985, 1006, 1007, 1008, 986, 1009, 987, 988, 989, 990,
+ 1010, 991, 996, 997, 1001, 1002, 1011, 1012, 1013, 1003,
+ 1014, 1015, 1016, 1004, 1017, 1005, 1019, 1020, 1006, 1007,
+
+ 1008, 1021, 1009, 1022, 1023, 1024, 1025, 1010, 1026, 1028,
+ 1029, 1030, 1031, 1011, 1012, 1013, 1032, 1014, 1015, 1016,
+ 1033, 1017, 1035, 1019, 1020, 1036, 1039, 1037, 1021, 1040,
+ 1022, 1023, 1024, 1025, 1041, 1026, 1028, 1029, 1030, 1031,
+ 1042, 1043, 1044, 1032, 1038, 1045, 1046, 1033, 1047, 1035,
+ 1049, 1050, 1036, 1039, 1037, 1051, 1040, 1052, 1055, 1057,
+ 1058, 1041, 1059, 1060, 1061, 1062, 1063, 1042, 1043, 1044,
+ 1064, 1038, 1045, 1046, 1065, 1047, 1066, 1049, 1050, 1067,
+ 1068, 1069, 1051, 1070, 1052, 1055, 1057, 1058, 1071, 1059,
+ 1060, 1061, 1062, 1063, 1072, 1073, 1074, 1064, 1075, 1076,
+
+ 1077, 1065, 1078, 1066, 1079, 1080, 1067, 1068, 1069, 1081,
+ 1070, 1082, 1083, 1084, 1085, 1071, 1086, 1087, 1088, 1089,
+ 1090, 1072, 1073, 1074, 1091, 1075, 1076, 1077, 1092, 1078,
+ 1093, 1079, 1080, 1094, 1095, 1096, 1081, 1097, 1082, 1083,
+ 1084, 1085, 1098, 1086, 1087, 1088, 1089, 1090, 1099, 1100,
+ 1101, 1091, 1102, 1103, 1104, 1092, 1105, 1093, 1106, 1107,
+ 1094, 1095, 1096, 1108, 1097, 1109, 1110, 1111, 1112, 1098,
+ 1113, 1114, 1115, 1116, 1118, 1099, 1100, 1101, 1119, 1102,
+ 1103, 1104, 1122, 1105, 1123, 1106, 1107, 1124, 1125, 1126,
+ 1108, 1127, 1109, 1110, 1111, 1112, 1128, 1113, 1114, 1115,
+
+ 1116, 1118, 1129, 1130, 1131, 1119, 1132, 1133, 1134, 1122,
+ 1135, 1123, 1136, 1138, 1124, 1125, 1126, 1140, 1127, 1141,
+ 1142, 1143, 1144, 1128, 1145, 1146, 1147, 1148, 1149, 1129,
+ 1130, 1131, 1150, 1132, 1133, 1134, 1152, 1135, 1153, 1136,
+ 1138, 1154, 1155, 1156, 1140, 1159, 1141, 1142, 1143, 1144,
+ 1161, 1145, 1146, 1147, 1148, 1149, 1162, 1163, 1164, 1150,
+ 1165, 1166, 1167, 1152, 1168, 1153, 1169, 1170, 1154, 1155,
+ 1156, 1171, 1159, 1172, 1173, 1174, 1175, 1161, 1176, 1177,
+ 1179, 1180, 1181, 1162, 1163, 1164, 1182, 1165, 1166, 1167,
+ 1183, 1168, 1184, 1169, 1170, 1185, 1186, 1188, 1171, 1189,
+
+ 1172, 1173, 1174, 1175, 1190, 1176, 1177, 1179, 1180, 1181,
+ 1191, 1192, 1193, 1182, 1197, 1198, 1199, 1183, 1200, 1184,
+ 1195, 1202, 1185, 1186, 1188, 1203, 1189, 1205, 1196, 1206,
+ 1207, 1190, 1208, 1209, 1210, 1201, 1211, 1191, 1192, 1193,
+ 1212, 1197, 1198, 1199, 1213, 1200, 1214, 1195, 1202, 1215,
+ 1216, 1219, 1203, 1220, 1205, 1221, 1206, 1207, 1217, 1208,
+ 1209, 1210, 1201, 1211, 1218, 1222, 1223, 1212, 1224, 1225,
+ 1227, 1213, 1228, 1214, 1229, 1230, 1215, 1216, 1219, 1231,
+ 1220, 1232, 1221, 1233, 1234, 1217, 1235, 1236, 1237, 1238,
+ 1239, 1218, 1222, 1223, 1240, 1224, 1225, 1227, 1241, 1228,
+
+ 1242, 1229, 1230, 1243, 1244, 1245, 1231, 1246, 1232, 1247,
+ 1233, 1234, 1248, 1235, 1236, 1237, 1238, 1239, 1249, 1250,
+ 1251, 1240, 1252, 1253, 1254, 1241, 1255, 1242, 1257, 1258,
+ 1243, 1244, 1245, 1259, 1246, 1260, 1247, 1261, 1262, 1248,
+ 1263, 1264, 1265, 1266, 1269, 1249, 1250, 1251, 1270, 1252,
+ 1253, 1254, 1271, 1255, 1272, 1257, 1258, 1273, 1274, 1275,
+ 1259, 1276, 1260, 1277, 1261, 1262, 1278, 1263, 1264, 1265,
+ 1266, 1269, 1280, 1281, 1282, 1270, 1283, 1285, 1286, 1271,
+ 1287, 1272, 1288, 1289, 1273, 1274, 1275, 1290, 1276, 1291,
+ 1277, 1292, 1293, 1278, 1294, 1295, 1297, 1298, 1303, 1280,
+
+ 1281, 1282, 1304, 1283, 1285, 1286, 1306, 1287, 1307, 1288,
+ 1289, 1308, 1309, 1310, 1290, 1311, 1291, 1312, 1292, 1293,
+ 1313, 1294, 1295, 1297, 1298, 1303, 1315, 1316, 1317, 1304,
+ 1318, 1319, 1321, 1306, 1322, 1307, 1323, 1324, 1308, 1309,
+ 1310, 1325, 1311, 1326, 1312, 1327, 1328, 1313, 1329, 1331,
+ 1332, 1333, 1334, 1315, 1316, 1317, 1335, 1318, 1319, 1321,
+ 1336, 1322, 1337, 1323, 1324, 1338, 1339, 1340, 1325, 1341,
+ 1326, 1342, 1327, 1328, 1343, 1329, 1331, 1332, 1333, 1334,
+ 1344, 1345, 1346, 1335, 1347, 1348, 1349, 1336, 1350, 1337,
+ 1351, 1352, 1338, 1339, 1340, 1353, 1341, 1355, 1342, 1356,
+
+ 1357, 1343, 1359, 1360, 1361, 1363, 1362, 1344, 1345, 1346,
+ 1365, 1347, 1348, 1349, 1367, 1350, 1368, 1351, 1352, 1369,
+ 1370, 1371, 1353, 1372, 1355, 1373, 1356, 1357, 1374, 1359,
+ 1360, 1361, 1363, 1362, 1375, 1378, 1376, 1365, 1379, 1380,
+ 1381, 1367, 1377, 1368, 1382, 1383, 1369, 1370, 1371, 1384,
+ 1372, 1385, 1373, 1386, 1387, 1374, 1389, 1390, 1391, 1392,
+ 1393, 1375, 1378, 1376, 1394, 1379, 1380, 1381, 1395, 1377,
+ 1396, 1382, 1383, 1397, 1398, 1399, 1384, 1400, 1385, 1401,
+ 1386, 1387, 1404, 1389, 1390, 1391, 1392, 1393, 1405, 1406,
+ 1407, 1394, 1408, 1409, 1410, 1395, 1411, 1396, 1412, 1413,
+
+ 1397, 1398, 1399, 1415, 1400, 1416, 1401, 1417, 1418, 1404,
+ 1420, 1421, 1422, 1423, 1424, 1405, 1406, 1407, 1425, 1408,
+ 1409, 1410, 1427, 1411, 1429, 1412, 1413, 1430, 1431, 1432,
+ 1415, 1433, 1416, 1434, 1417, 1418, 1435, 1420, 1421, 1422,
+ 1423, 1424, 1436, 1437, 1438, 1425, 1439, 1440, 1441, 1427,
+ 1442, 1429, 1443, 1444, 1430, 1431, 1432, 1445, 1433, 1446,
+ 1434, 1447, 1448, 1435, 1449, 1450, 1451, 1452, 1453, 1436,
+ 1437, 1438, 1454, 1439, 1440, 1441, 1455, 1442, 1456, 1443,
+ 1444, 1457, 1458, 1459, 1445, 1460, 1446, 1461, 1447, 1448,
+ 1462, 1449, 1450, 1451, 1452, 1453, 1463, 1464, 1465, 1454,
+
+ 1466, 1467, 1468, 1455, 1469, 1456, 1470, 1471, 1457, 1458,
+ 1459, 1472, 1460, 1473, 1461, 1474, 1475, 1462, 1476, 1477,
+ 1478, 1479, 1480, 1463, 1464, 1465, 1481, 1466, 1467, 1468,
+ 1482, 1469, 1483, 1470, 1471, 1484, 1485, 1486, 1472, 1487,
+ 1473, 1488, 1474, 1475, 1489, 1476, 1477, 1478, 1479, 1480,
+ 1490, 1492, 1493, 1481, 1494, 1495, 1496, 1482, 1497, 1483,
+ 1498, 1499, 1484, 1485, 1486, 1500, 1487, 1501, 1488, 1502,
+ 1503, 1489, 1504, 1505, 1506, 1507, 1508, 1490, 1492, 1493,
+ 1509, 1494, 1495, 1496, 1510, 1497, 1511, 1498, 1499, 1512,
+ 1513, 1514, 1500, 1515, 1501, 1516, 1502, 1503, 1517, 1504,
+
+ 1505, 1506, 1507, 1508, 1519, 1520, 1521, 1509, 1522, 1523,
+ 1524, 1510, 1525, 1511, 1526, 1527, 1512, 1513, 1514, 1528,
+ 1515, 1529, 1516, 1530, 1531, 1517, 1532, 1534, 1535, 1536,
+ 1537, 1519, 1520, 1521, 1538, 1522, 1523, 1524, 1539, 1525,
+ 1540, 1526, 1527, 1541, 1542, 1543, 1528, 1544, 1529, 1194,
+ 1530, 1531, 1187, 1532, 1534, 1535, 1536, 1537, 1178, 1160,
+ 1158, 1538, 1157, 1151, 1139, 1539, 1137, 1540, 1121, 1120,
+ 1541, 1542, 1543, 1117, 1544, 39, 39, 995, 995, 993,
+ 993, 1056, 1054, 1053, 1048, 1034, 1027, 1018, 1000, 999,
+ 998, 995, 993, 984, 969, 962, 958, 933, 882, 879,
+
+ 877, 874, 873, 872, 871, 870, 834, 833, 830, 826,
+ 792, 787, 786, 785, 783, 762, 760, 752, 718, 684,
+ 680, 678, 676, 669, 667, 648, 644, 629, 623, 621,
+ 604, 592, 560, 558, 557, 543, 526, 514, 500, 499,
+ 492, 479, 468, 466, 456, 454, 433, 429, 427, 422,
+ 404, 395, 388, 350, 317, 301, 265, 239, 202, 37,
+ 37, 1545, 3, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545
+ } ;
+
+static yyconst flex_int16_t yy_chk[3032] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 7, 7,
+ 9, 10, 13, 10, 11, 11, 11, 11, 11, 16,
+ 21, 1550, 13, 26, 1549, 16, 16, 9, 39, 39,
+ 15, 771, 28, 771, 15, 18, 16, 1548, 15, 13,
+
+ 17, 15, 18, 771, 15, 1546, 16, 21, 17, 13,
+ 26, 17, 16, 16, 9, 12, 12, 15, 12, 28,
+ 17, 15, 18, 16, 12, 15, 12, 17, 15, 18,
+ 20, 15, 19, 12, 1527, 17, 1505, 20, 17, 20,
+ 19, 1471, 12, 12, 29, 12, 19, 17, 1389, 33,
+ 1387, 12, 19, 12, 35, 179, 179, 20, 29, 19,
+ 12, 14, 36, 14, 20, 1379, 20, 19, 14, 14,
+ 22, 29, 14, 19, 23, 14, 33, 22, 23, 19,
+ 22, 35, 22, 34, 23, 29, 1374, 34, 14, 36,
+ 14, 883, 27, 883, 43, 14, 14, 22, 47, 14,
+
+ 27, 23, 14, 883, 22, 23, 27, 22, 48, 22,
+ 34, 23, 24, 24, 34, 49, 24, 32, 32, 27,
+ 24, 43, 50, 32, 51, 47, 24, 27, 46, 46,
+ 46, 46, 46, 27, 52, 48, 53, 54, 56, 24,
+ 24, 1343, 49, 24, 32, 32, 55, 24, 55, 50,
+ 32, 51, 57, 24, 25, 58, 25, 59, 25, 60,
+ 61, 52, 25, 53, 54, 56, 63, 64, 25, 65,
+ 66, 67, 68, 55, 25, 55, 70, 59, 1319, 57,
+ 63, 25, 58, 25, 59, 25, 60, 61, 71, 25,
+ 1316, 72, 73, 63, 64, 25, 65, 66, 67, 68,
+
+ 76, 25, 30, 70, 59, 30, 30, 63, 30, 69,
+ 77, 69, 30, 30, 1310, 71, 30, 30, 72, 73,
+ 74, 1359, 1359, 78, 75, 78, 69, 76, 1304, 30,
+ 75, 74, 30, 30, 79, 30, 69, 77, 69, 30,
+ 30, 62, 62, 30, 30, 31, 62, 74, 31, 31,
+ 78, 75, 78, 69, 62, 31, 31, 75, 74, 62,
+ 80, 79, 31, 81, 82, 83, 84, 85, 62, 62,
+ 86, 87, 31, 62, 88, 31, 31, 92, 94, 89,
+ 91, 62, 31, 31, 89, 91, 62, 80, 93, 31,
+ 81, 82, 83, 84, 85, 90, 95, 86, 87, 90,
+
+ 93, 88, 96, 97, 92, 94, 89, 91, 99, 98,
+ 101, 89, 91, 102, 104, 93, 103, 105, 108, 112,
+ 106, 1273, 90, 95, 98, 113, 90, 93, 106, 96,
+ 97, 111, 103, 103, 1263, 99, 98, 101, 115, 109,
+ 102, 104, 116, 103, 105, 108, 112, 106, 110, 117,
+ 109, 98, 113, 111, 109, 106, 109, 118, 111, 103,
+ 103, 107, 110, 107, 107, 115, 109, 107, 107, 116,
+ 107, 119, 114, 107, 120, 110, 117, 109, 122, 107,
+ 111, 109, 114, 109, 118, 123, 1255, 125, 107, 110,
+ 107, 107, 126, 128, 107, 107, 1244, 107, 119, 114,
+
+ 107, 120, 127, 1241, 129, 122, 107, 130, 127, 114,
+ 131, 132, 123, 124, 125, 133, 124, 134, 136, 126,
+ 128, 137, 138, 124, 124, 139, 140, 142, 137, 127,
+ 124, 129, 143, 144, 130, 127, 124, 131, 132, 145,
+ 124, 146, 133, 124, 134, 136, 147, 148, 137, 138,
+ 124, 124, 139, 140, 142, 137, 149, 124, 150, 143,
+ 144, 151, 152, 124, 153, 155, 145, 156, 146, 157,
+ 158, 159, 160, 147, 148, 161, 162, 163, 164, 165,
+ 166, 167, 168, 149, 169, 150, 170, 171, 151, 152,
+ 172, 153, 155, 166, 156, 174, 157, 158, 159, 160,
+
+ 173, 173, 161, 162, 163, 164, 165, 166, 167, 168,
+ 175, 169, 177, 170, 171, 178, 180, 172, 181, 183,
+ 166, 182, 174, 184, 182, 185, 186, 173, 173, 187,
+ 188, 190, 192, 193, 194, 195, 196, 175, 197, 177,
+ 198, 195, 178, 180, 199, 181, 183, 200, 182, 201,
+ 184, 182, 185, 186, 203, 204, 187, 188, 190, 192,
+ 193, 194, 195, 196, 205, 197, 202, 198, 206, 207,
+ 208, 199, 209, 202, 200, 210, 201, 211, 202, 212,
+ 213, 203, 204, 202, 214, 215, 216, 218, 219, 221,
+ 219, 205, 222, 202, 223, 206, 207, 208, 225, 209,
+
+ 202, 226, 210, 228, 211, 202, 212, 213, 229, 230,
+ 202, 214, 215, 216, 218, 219, 221, 219, 231, 222,
+ 234, 223, 233, 235, 236, 225, 237, 233, 226, 238,
+ 228, 239, 240, 241, 242, 229, 230, 243, 244, 245,
+ 246, 239, 247, 248, 249, 231, 250, 234, 251, 233,
+ 235, 236, 248, 237, 252, 253, 238, 255, 239, 240,
+ 241, 242, 256, 257, 243, 244, 245, 246, 239, 247,
+ 248, 249, 258, 250, 261, 251, 263, 264, 265, 266,
+ 267, 252, 253, 269, 255, 270, 271, 274, 275, 256,
+ 257, 277, 278, 279, 281, 282, 283, 284, 285, 258,
+
+ 286, 261, 287, 263, 264, 265, 266, 267, 289, 290,
+ 269, 292, 270, 271, 274, 275, 293, 294, 277, 278,
+ 279, 281, 282, 283, 284, 285, 295, 286, 296, 287,
+ 297, 300, 301, 302, 303, 289, 290, 307, 292, 309,
+ 295, 296, 310, 293, 294, 311, 313, 314, 315, 316,
+ 1240, 1239, 1238, 295, 318, 296, 1235, 297, 300, 301,
+ 302, 303, 319, 1219, 307, 320, 309, 295, 321, 310,
+ 322, 323, 311, 313, 314, 315, 316, 317, 317, 317,
+ 325, 318, 327, 317, 329, 317, 330, 331, 317, 319,
+ 317, 332, 320, 333, 1214, 321, 317, 322, 323, 317,
+
+ 336, 340, 1199, 334, 317, 317, 317, 325, 341, 327,
+ 317, 329, 317, 330, 331, 317, 342, 317, 332, 343,
+ 333, 334, 344, 317, 345, 334, 317, 336, 340, 334,
+ 334, 346, 347, 348, 350, 341, 351, 352, 354, 355,
+ 357, 358, 359, 342, 362, 363, 343, 352, 334, 344,
+ 348, 345, 334, 353, 361, 361, 364, 353, 346, 347,
+ 348, 350, 353, 351, 352, 354, 355, 357, 358, 359,
+ 361, 362, 363, 367, 368, 370, 371, 348, 372, 373,
+ 353, 361, 361, 364, 353, 374, 375, 376, 378, 353,
+ 379, 380, 382, 383, 384, 378, 385, 361, 386, 387,
+
+ 367, 368, 370, 371, 388, 372, 373, 389, 391, 388,
+ 392, 394, 374, 375, 376, 378, 395, 379, 380, 382,
+ 383, 384, 378, 385, 397, 386, 387, 398, 400, 401,
+ 402, 388, 404, 405, 389, 391, 388, 392, 394, 407,
+ 408, 409, 410, 395, 411, 413, 415, 417, 418, 419,
+ 420, 397, 421, 422, 398, 400, 401, 402, 424, 404,
+ 405, 425, 426, 427, 428, 429, 407, 408, 409, 410,
+ 430, 411, 413, 415, 417, 418, 419, 420, 433, 421,
+ 422, 435, 436, 437, 438, 424, 439, 441, 425, 426,
+ 427, 428, 429, 442, 440, 443, 445, 430, 440, 446,
+
+ 444, 447, 448, 449, 450, 433, 451, 452, 435, 436,
+ 437, 438, 444, 439, 441, 453, 455, 454, 456, 457,
+ 442, 440, 443, 445, 454, 440, 446, 444, 447, 448,
+ 449, 450, 458, 451, 452, 459, 460, 461, 462, 444,
+ 464, 466, 453, 455, 454, 456, 457, 465, 465, 467,
+ 469, 454, 468, 465, 471, 473, 475, 476, 473, 458,
+ 467, 477, 459, 460, 461, 462, 478, 464, 466, 468,
+ 479, 481, 468, 483, 465, 465, 467, 469, 484, 468,
+ 465, 471, 473, 475, 476, 473, 480, 467, 477, 480,
+ 485, 486, 487, 478, 490, 494, 468, 479, 481, 468,
+
+ 483, 495, 493, 497, 498, 484, 493, 500, 501, 493,
+ 502, 503, 504, 480, 505, 506, 480, 485, 486, 487,
+ 507, 490, 494, 508, 509, 510, 511, 513, 495, 493,
+ 497, 498, 514, 493, 500, 501, 493, 502, 503, 504,
+ 517, 505, 506, 519, 521, 522, 523, 507, 524, 525,
+ 508, 509, 510, 511, 513, 526, 527, 528, 529, 514,
+ 530, 531, 532, 533, 534, 535, 524, 517, 536, 539,
+ 519, 521, 522, 523, 541, 524, 525, 542, 545, 547,
+ 1198, 550, 526, 527, 528, 529, 549, 530, 531, 532,
+ 533, 534, 535, 543, 543, 536, 539, 549, 552, 553,
+
+ 555, 541, 543, 556, 542, 545, 547, 543, 550, 557,
+ 558, 559, 560, 549, 564, 565, 566, 567, 568, 569,
+ 543, 543, 570, 571, 549, 552, 553, 555, 572, 543,
+ 556, 573, 574, 576, 543, 577, 557, 558, 559, 560,
+ 578, 564, 565, 566, 567, 568, 569, 579, 580, 570,
+ 571, 581, 582, 583, 584, 572, 585, 586, 573, 574,
+ 576, 587, 577, 588, 589, 591, 592, 578, 593, 594,
+ 595, 596, 597, 599, 579, 580, 600, 601, 581, 582,
+ 583, 584, 602, 585, 586, 603, 604, 606, 587, 607,
+ 588, 589, 591, 592, 609, 593, 594, 595, 596, 597,
+
+ 599, 610, 611, 600, 601, 612, 613, 614, 615, 602,
+ 616, 618, 603, 604, 606, 619, 607, 617, 617, 621,
+ 622, 609, 623, 624, 625, 626, 628, 1182, 610, 611,
+ 630, 1150, 612, 613, 614, 615, 632, 616, 618, 634,
+ 637, 638, 619, 639, 617, 617, 621, 622, 641, 623,
+ 624, 625, 626, 628, 629, 642, 643, 630, 629, 646,
+ 629, 647, 648, 632, 629, 629, 634, 637, 638, 649,
+ 639, 650, 651, 652, 653, 641, 654, 655, 656, 658,
+ 660, 629, 642, 643, 662, 629, 646, 629, 647, 648,
+ 666, 629, 629, 667, 668, 669, 649, 672, 650, 651,
+
+ 652, 653, 673, 654, 655, 656, 658, 660, 674, 675,
+ 676, 662, 673, 678, 679, 680, 681, 666, 682, 683,
+ 667, 668, 669, 684, 672, 685, 686, 687, 688, 673,
+ 689, 690, 691, 692, 693, 674, 675, 676, 694, 673,
+ 678, 679, 680, 681, 695, 682, 683, 696, 697, 698,
+ 684, 699, 685, 686, 687, 688, 700, 689, 690, 691,
+ 692, 693, 701, 702, 703, 694, 704, 707, 710, 711,
+ 713, 695, 714, 717, 696, 697, 698, 718, 699, 719,
+ 720, 721, 722, 700, 723, 724, 725, 726, 727, 701,
+ 702, 703, 728, 704, 707, 710, 711, 713, 729, 714,
+
+ 717, 730, 731, 732, 718, 733, 719, 720, 721, 722,
+ 734, 723, 724, 725, 726, 727, 736, 737, 738, 728,
+ 739, 741, 742, 743, 744, 729, 745, 746, 730, 731,
+ 732, 747, 733, 748, 749, 750, 751, 734, 752, 753,
+ 759, 760, 762, 736, 737, 738, 766, 739, 741, 742,
+ 743, 744, 769, 745, 746, 772, 773, 774, 747, 775,
+ 748, 749, 750, 751, 778, 752, 753, 759, 760, 762,
+ 779, 780, 781, 766, 782, 783, 784, 1123, 786, 769,
+ 787, 788, 772, 773, 774, 789, 775, 785, 783, 791,
+ 792, 778, 785, 793, 794, 795, 796, 779, 780, 781,
+
+ 797, 782, 783, 784, 785, 786, 798, 787, 788, 799,
+ 800, 801, 789, 802, 785, 783, 791, 792, 803, 785,
+ 793, 794, 795, 796, 805, 806, 807, 797, 808, 809,
+ 810, 785, 811, 798, 812, 813, 799, 800, 801, 814,
+ 802, 816, 817, 818, 819, 803, 820, 822, 823, 824,
+ 825, 805, 806, 807, 826, 808, 809, 810, 827, 811,
+ 828, 812, 813, 829, 831, 832, 814, 833, 816, 817,
+ 818, 819, 830, 820, 822, 823, 824, 825, 834, 836,
+ 838, 826, 830, 840, 841, 827, 842, 828, 843, 845,
+ 829, 831, 832, 846, 833, 847, 848, 850, 851, 830,
+
+ 852, 854, 855, 856, 857, 834, 836, 838, 858, 830,
+ 840, 841, 859, 842, 861, 843, 845, 862, 863, 864,
+ 846, 865, 847, 848, 850, 851, 866, 852, 854, 855,
+ 856, 857, 867, 868, 869, 858, 870, 871, 872, 859,
+ 873, 861, 874, 876, 862, 863, 864, 877, 865, 878,
+ 879, 880, 881, 866, 882, 886, 887, 892, 893, 867,
+ 868, 869, 894, 870, 871, 872, 895, 873, 896, 874,
+ 876, 897, 898, 899, 877, 900, 878, 879, 880, 881,
+ 901, 882, 886, 887, 892, 893, 902, 904, 905, 894,
+ 906, 907, 908, 895, 909, 896, 911, 912, 897, 898,
+
+ 899, 913, 900, 914, 915, 916, 917, 901, 918, 920,
+ 921, 923, 924, 902, 904, 905, 926, 906, 907, 908,
+ 927, 909, 929, 911, 912, 930, 934, 933, 913, 935,
+ 914, 915, 916, 917, 938, 918, 920, 921, 923, 924,
+ 939, 940, 941, 926, 933, 942, 943, 927, 944, 929,
+ 946, 947, 930, 934, 933, 948, 935, 949, 952, 954,
+ 956, 938, 957, 958, 962, 963, 964, 939, 940, 941,
+ 965, 933, 942, 943, 966, 944, 967, 946, 947, 968,
+ 969, 970, 948, 971, 949, 952, 954, 956, 972, 957,
+ 958, 962, 963, 964, 973, 974, 975, 965, 976, 977,
+
+ 978, 966, 979, 967, 980, 981, 968, 969, 970, 982,
+ 971, 983, 984, 985, 986, 972, 987, 988, 990, 991,
+ 996, 973, 974, 975, 997, 976, 977, 978, 998, 979,
+ 999, 980, 981, 1000, 1002, 1003, 982, 1004, 983, 984,
+ 985, 986, 1005, 987, 988, 990, 991, 996, 1006, 1007,
+ 1008, 997, 1009, 1010, 1011, 998, 1012, 999, 1013, 1014,
+ 1000, 1002, 1003, 1015, 1004, 1016, 1017, 1018, 1019, 1005,
+ 1020, 1021, 1023, 1024, 1026, 1006, 1007, 1008, 1027, 1009,
+ 1010, 1011, 1030, 1012, 1031, 1013, 1014, 1032, 1034, 1035,
+ 1015, 1037, 1016, 1017, 1018, 1019, 1038, 1020, 1021, 1023,
+
+ 1024, 1026, 1040, 1041, 1042, 1027, 1044, 1045, 1046, 1030,
+ 1047, 1031, 1048, 1050, 1032, 1034, 1035, 1052, 1037, 1053,
+ 1054, 1055, 1056, 1038, 1057, 1058, 1060, 1061, 1062, 1040,
+ 1041, 1042, 1063, 1044, 1045, 1046, 1065, 1047, 1068, 1048,
+ 1050, 1071, 1072, 1073, 1052, 1076, 1053, 1054, 1055, 1056,
+ 1078, 1057, 1058, 1060, 1061, 1062, 1079, 1080, 1081, 1063,
+ 1082, 1083, 1084, 1065, 1085, 1068, 1086, 1087, 1071, 1072,
+ 1073, 1088, 1076, 1089, 1090, 1091, 1092, 1078, 1093, 1094,
+ 1097, 1098, 1100, 1079, 1080, 1081, 1101, 1082, 1083, 1084,
+ 1102, 1085, 1103, 1086, 1087, 1104, 1105, 1107, 1088, 1108,
+
+ 1089, 1090, 1091, 1092, 1109, 1093, 1094, 1097, 1098, 1100,
+ 1110, 1111, 1112, 1101, 1117, 1118, 1119, 1102, 1120, 1103,
+ 1116, 1121, 1104, 1105, 1107, 1122, 1108, 1125, 1116, 1127,
+ 1128, 1109, 1130, 1131, 1132, 1120, 1133, 1110, 1111, 1112,
+ 1134, 1117, 1118, 1119, 1135, 1120, 1136, 1116, 1121, 1137,
+ 1138, 1140, 1122, 1141, 1125, 1142, 1127, 1128, 1139, 1130,
+ 1131, 1132, 1120, 1133, 1139, 1144, 1146, 1134, 1147, 1148,
+ 1151, 1135, 1152, 1136, 1153, 1154, 1137, 1138, 1140, 1155,
+ 1141, 1156, 1142, 1157, 1158, 1139, 1159, 1160, 1161, 1162,
+ 1163, 1139, 1144, 1146, 1164, 1147, 1148, 1151, 1165, 1152,
+
+ 1166, 1153, 1154, 1167, 1168, 1169, 1155, 1170, 1156, 1172,
+ 1157, 1158, 1173, 1159, 1160, 1161, 1162, 1163, 1174, 1175,
+ 1176, 1164, 1177, 1178, 1179, 1165, 1180, 1166, 1183, 1184,
+ 1167, 1168, 1169, 1187, 1170, 1188, 1172, 1189, 1192, 1173,
+ 1193, 1194, 1196, 1197, 1200, 1174, 1175, 1176, 1201, 1177,
+ 1178, 1179, 1202, 1180, 1204, 1183, 1184, 1205, 1206, 1207,
+ 1187, 1208, 1188, 1209, 1189, 1192, 1210, 1193, 1194, 1196,
+ 1197, 1200, 1215, 1216, 1217, 1201, 1218, 1220, 1221, 1202,
+ 1222, 1204, 1225, 1226, 1205, 1206, 1207, 1227, 1208, 1228,
+ 1209, 1229, 1232, 1210, 1233, 1234, 1236, 1237, 1242, 1215,
+
+ 1216, 1217, 1243, 1218, 1220, 1221, 1246, 1222, 1247, 1225,
+ 1226, 1248, 1250, 1251, 1227, 1252, 1228, 1253, 1229, 1232,
+ 1254, 1233, 1234, 1236, 1237, 1242, 1256, 1257, 1259, 1243,
+ 1261, 1262, 1264, 1246, 1265, 1247, 1266, 1267, 1248, 1250,
+ 1251, 1268, 1252, 1269, 1253, 1270, 1271, 1254, 1272, 1274,
+ 1276, 1277, 1279, 1256, 1257, 1259, 1280, 1261, 1262, 1264,
+ 1282, 1265, 1284, 1266, 1267, 1285, 1286, 1287, 1268, 1288,
+ 1269, 1289, 1270, 1271, 1290, 1272, 1274, 1276, 1277, 1279,
+ 1293, 1294, 1295, 1280, 1296, 1297, 1298, 1282, 1299, 1284,
+ 1300, 1301, 1285, 1286, 1287, 1302, 1288, 1305, 1289, 1308,
+
+ 1309, 1290, 1312, 1313, 1314, 1315, 1314, 1293, 1294, 1295,
+ 1317, 1296, 1297, 1298, 1320, 1299, 1321, 1300, 1301, 1322,
+ 1324, 1325, 1302, 1326, 1305, 1327, 1308, 1309, 1328, 1312,
+ 1313, 1314, 1315, 1314, 1329, 1331, 1330, 1317, 1333, 1334,
+ 1335, 1320, 1330, 1321, 1336, 1337, 1322, 1324, 1325, 1338,
+ 1326, 1340, 1327, 1341, 1342, 1328, 1344, 1345, 1346, 1347,
+ 1348, 1329, 1331, 1330, 1349, 1333, 1334, 1335, 1350, 1330,
+ 1351, 1336, 1337, 1352, 1353, 1354, 1338, 1355, 1340, 1358,
+ 1341, 1342, 1360, 1344, 1345, 1346, 1347, 1348, 1361, 1362,
+ 1363, 1349, 1364, 1365, 1367, 1350, 1368, 1351, 1371, 1372,
+
+ 1352, 1353, 1354, 1375, 1355, 1376, 1358, 1377, 1378, 1360,
+ 1380, 1381, 1383, 1384, 1385, 1361, 1362, 1363, 1386, 1364,
+ 1365, 1367, 1388, 1368, 1391, 1371, 1372, 1392, 1393, 1394,
+ 1375, 1395, 1376, 1396, 1377, 1378, 1397, 1380, 1381, 1383,
+ 1384, 1385, 1398, 1399, 1400, 1386, 1401, 1404, 1405, 1388,
+ 1406, 1391, 1407, 1408, 1392, 1393, 1394, 1409, 1395, 1410,
+ 1396, 1412, 1414, 1397, 1415, 1416, 1417, 1419, 1420, 1398,
+ 1399, 1400, 1422, 1401, 1404, 1405, 1425, 1406, 1426, 1407,
+ 1408, 1427, 1428, 1429, 1409, 1430, 1410, 1431, 1412, 1414,
+ 1433, 1415, 1416, 1417, 1419, 1420, 1434, 1435, 1436, 1422,
+
+ 1437, 1438, 1439, 1425, 1440, 1426, 1441, 1442, 1427, 1428,
+ 1429, 1443, 1430, 1444, 1431, 1445, 1446, 1433, 1447, 1448,
+ 1449, 1450, 1451, 1434, 1435, 1436, 1452, 1437, 1438, 1439,
+ 1453, 1440, 1454, 1441, 1442, 1456, 1457, 1458, 1443, 1466,
+ 1444, 1467, 1445, 1446, 1468, 1447, 1448, 1449, 1450, 1451,
+ 1470, 1472, 1473, 1452, 1475, 1476, 1477, 1453, 1478, 1454,
+ 1481, 1483, 1456, 1457, 1458, 1484, 1466, 1485, 1467, 1486,
+ 1487, 1468, 1489, 1490, 1491, 1492, 1493, 1470, 1472, 1473,
+ 1494, 1475, 1476, 1477, 1495, 1478, 1496, 1481, 1483, 1498,
+ 1499, 1500, 1484, 1502, 1485, 1503, 1486, 1487, 1504, 1489,
+
+ 1490, 1491, 1492, 1493, 1506, 1507, 1508, 1494, 1509, 1511,
+ 1512, 1495, 1513, 1496, 1516, 1517, 1498, 1499, 1500, 1518,
+ 1502, 1519, 1503, 1521, 1522, 1504, 1524, 1528, 1529, 1530,
+ 1533, 1506, 1507, 1508, 1534, 1509, 1511, 1512, 1535, 1513,
+ 1537, 1516, 1517, 1538, 1540, 1541, 1518, 1542, 1519, 1114,
+ 1521, 1522, 1106, 1524, 1528, 1529, 1530, 1533, 1095, 1077,
+ 1075, 1534, 1074, 1064, 1051, 1535, 1049, 1537, 1029, 1028,
+ 1538, 1540, 1541, 1025, 1542, 1547, 1547, 995, 994, 993,
+ 992, 953, 951, 950, 945, 928, 919, 910, 890, 889,
+ 888, 885, 884, 875, 860, 853, 849, 821, 770, 763,
+
+ 761, 758, 757, 756, 755, 754, 716, 715, 712, 705,
+ 670, 665, 664, 663, 661, 633, 631, 627, 590, 551,
+ 548, 546, 544, 540, 537, 518, 512, 496, 491, 488,
+ 470, 463, 434, 432, 431, 416, 393, 381, 366, 365,
+ 360, 349, 338, 335, 328, 326, 312, 308, 306, 298,
+ 280, 268, 259, 220, 191, 176, 141, 121, 100, 37,
+ 5, 3, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545,
+ 1545
+ } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+extern int yy_flex_debug;
+int yy_flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+static int yy_more_flag = 0;
+static int yy_more_len = 0;
+#define yymore() ((yy_more_flag) = 1)
+#define YY_MORE_ADJ (yy_more_len)
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "conf_lexer.l"
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * conf_lexer.l: Scans the ircd configuration file for tokens.
+ *
+ * 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: conf_lexer.l 1547 2012-09-30 17:50:03Z michael $
+ */
+#line 31 "conf_lexer.l"
+#include "stdinc.h"
+#include "irc_string.h"
+#include "conf.h"
+#include "conf_parser.h" /* autogenerated header file */
+#include "memory.h"
+#include "hostmask.h"
+#include "log.h"
+
+#undef YY_INPUT
+#define YY_FATAL_ERROR(msg) conf_yy_fatal_error(msg)
+#define YY_INPUT(buf,result,max_size) \
+ if (!(result = conf_yy_input(buf, max_size))) \
+ YY_FATAL_ERROR("input in flex scanner failed");
+#define MAX_INCLUDE_DEPTH 10
+
+
+unsigned int lineno = 1;
+char linebuf[IRCD_BUFSIZE];
+char conffilebuf[IRCD_BUFSIZE];
+
+static int include_stack_ptr = 0;
+static YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
+static unsigned int lineno_stack[MAX_INCLUDE_DEPTH];
+static FILE *inc_fbfile_in[MAX_INCLUDE_DEPTH];
+static char conffile_stack[MAX_INCLUDE_DEPTH][IRCD_BUFSIZE];
+static void ccomment(void);
+static void cinclude(void);
+static int ieof(void);
+
+static int
+conf_yy_input(char *lbuf, unsigned int max_size)
+{
+ return !fgets(lbuf, max_size, conf_parser_ctx.conf_file) ? 0 : strlen(lbuf);
+}
+
+static int
+conf_yy_fatal_error(const char *msg)
+{
+ return 0;
+}
+
+#line 1700 "conf_lexer.c"
+
+#define INITIAL 0
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy (void );
+
+int yyget_debug (void );
+
+void yyset_debug (int debug_flag );
+
+YY_EXTRA_TYPE yyget_extra (void );
+
+void yyset_extra (YY_EXTRA_TYPE user_defined );
+
+FILE *yyget_in (void );
+
+void yyset_in (FILE * in_str );
+
+FILE *yyget_out (void );
+
+void yyset_out (FILE * out_str );
+
+yy_size_t yyget_leng (void );
+
+char *yyget_text (void );
+
+int yyget_lineno (void );
+
+void yyset_lineno (int line_number );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap (void );
+#else
+extern int yywrap (void );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ size_t n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (void);
+
+#define YY_DECL int yylex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+#line 80 "conf_lexer.l"
+
+#line 1882 "conf_lexer.c"
+
+ if ( !(yy_init) )
+ {
+ (yy_init) = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! (yy_start) )
+ (yy_start) = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer(yyin,YY_BUF_SIZE );
+ }
+
+ yy_load_buffer_state( );
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ (yy_more_len) = 0;
+ if ( (yy_more_flag) )
+ {
+ (yy_more_len) = (yy_c_buf_p) - (yytext_ptr);
+ (yy_more_flag) = 0;
+ }
+ yy_cp = (yy_c_buf_p);
+
+ /* Support of yytext. */
+ *yy_cp = (yy_hold_char);
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = (yy_start);
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 1546 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_current_state != 1545 );
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = (yy_hold_char);
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 81 "conf_lexer.l"
+{ cinclude(); }
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 82 "conf_lexer.l"
+{ ccomment(); }
+ YY_BREAK
+case 3:
+/* rule 3 can match eol */
+YY_RULE_SETUP
+#line 84 "conf_lexer.l"
+{ strlcpy(linebuf, yytext+1, sizeof(linebuf)); ++lineno; yyless(1); }
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 86 "conf_lexer.l"
+;
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 87 "conf_lexer.l"
+;
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 89 "conf_lexer.l"
+{ yylval.number = atoi(yytext); return NUMBER; }
+ YY_BREAK
+case 7:
+/* rule 7 can match eol */
+YY_RULE_SETUP
+#line 91 "conf_lexer.l"
+{ if (yytext[yyleng-2] == '\\')
+ {
+ yyless(yyleng-1); /* return last quote */
+ yymore(); /* append next string */
+ }
+ else
+ {
+ yylval.string = yytext+1;
+ if(yylval.string[yyleng-2] != '"')
+ ilog(LOG_TYPE_IRCD, "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(LOG_TYPE_IRCD,
+ "Unterminated character string");
+ break;
+ }
+ yylval.string[j] = yylval.string[i];
+ }
+ }
+ yylval.string[j] = '\0';
+ return QSTRING;
+ }
+ }
+ }
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 136 "conf_lexer.l"
+{ return ACCEPT_PASSWORD; }
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 137 "conf_lexer.l"
+{ return ADMIN; }
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 138 "conf_lexer.l"
+{ return ADMIN; }
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 139 "conf_lexer.l"
+{ return AFTYPE; }
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 140 "conf_lexer.l"
+{ return T_ALL; }
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 141 "conf_lexer.l"
+{ return IRCD_AUTH; }
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 142 "conf_lexer.l"
+{ return AUTOCONN; }
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 143 "conf_lexer.l"
+{ return CAN_FLOOD; }
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 144 "conf_lexer.l"
+{ return CALLER_ID_WAIT; }
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 145 "conf_lexer.l"
+{ return OPERS_BYPASS_CALLERID; }
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 146 "conf_lexer.l"
+{ return CHANNEL; }
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 147 "conf_lexer.l"
+{ return CIDR_BITLEN_IPV4; }
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 148 "conf_lexer.l"
+{ return CIDR_BITLEN_IPV6; }
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 149 "conf_lexer.l"
+{ return CLASS; }
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 150 "conf_lexer.l"
+{ return T_CLUSTER; }
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 151 "conf_lexer.l"
+{ return CONNECT; }
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 152 "conf_lexer.l"
+{ return CONNECTFREQ; }
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 153 "conf_lexer.l"
+{ return DEFAULT_FLOODCOUNT; }
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 154 "conf_lexer.l"
+{ return DEFAULT_SPLIT_SERVER_COUNT; }
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 155 "conf_lexer.l"
+{ return DEFAULT_SPLIT_USER_COUNT; }
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 156 "conf_lexer.l"
+{ return DENY; }
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 157 "conf_lexer.l"
+{ return DESCRIPTION; }
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 158 "conf_lexer.l"
+{ return DIE; }
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 159 "conf_lexer.l"
+{ return DISABLE_AUTH; }
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 160 "conf_lexer.l"
+{ return DISABLE_FAKE_CHANNELS; }
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 161 "conf_lexer.l"
+{ return DISABLE_REMOTE_COMMANDS; }
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 162 "conf_lexer.l"
+{ return T_DLINE; }
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 163 "conf_lexer.l"
+{ return DOTS_IN_IDENT; }
+ YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 164 "conf_lexer.l"
+{ return EGDPOOL_PATH; }
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 165 "conf_lexer.l"
+{ return EMAIL; }
+ YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 166 "conf_lexer.l"
+{ return ENCRYPTED; }
+ YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 167 "conf_lexer.l"
+{ return EXCEED_LIMIT; }
+ YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 168 "conf_lexer.l"
+{ return EXEMPT; }
+ YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 169 "conf_lexer.l"
+{ return T_FILE; }
+ YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 170 "conf_lexer.l"
+{ return IRCD_FLAGS; }
+ YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 171 "conf_lexer.l"
+{ return FLATTEN_LINKS; }
+ YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 172 "conf_lexer.l"
+{ return GECOS; }
+ YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 173 "conf_lexer.l"
+{ return GENERAL; }
+ YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 174 "conf_lexer.l"
+{ return GLINE; }
+ YY_BREAK
+case 47:
+YY_RULE_SETUP
+#line 175 "conf_lexer.l"
+{ return GLINE_ENABLE; }
+ YY_BREAK
+case 48:
+YY_RULE_SETUP
+#line 176 "conf_lexer.l"
+{ return GLINE_EXEMPT; }
+ YY_BREAK
+case 49:
+YY_RULE_SETUP
+#line 177 "conf_lexer.l"
+{ return GLINE_DURATION; }
+ YY_BREAK
+case 50:
+YY_RULE_SETUP
+#line 178 "conf_lexer.l"
+{ return GLINE_REQUEST_DURATION; }
+ YY_BREAK
+case 51:
+YY_RULE_SETUP
+#line 179 "conf_lexer.l"
+{ return GLINE_MIN_CIDR; }
+ YY_BREAK
+case 52:
+YY_RULE_SETUP
+#line 180 "conf_lexer.l"
+{ return GLINE_MIN_CIDR6; }
+ YY_BREAK
+case 53:
+YY_RULE_SETUP
+#line 181 "conf_lexer.l"
+{ return T_GLOBOPS; }
+ YY_BREAK
+case 54:
+YY_RULE_SETUP
+#line 182 "conf_lexer.l"
+{ return GLOBAL_KILL; }
+ YY_BREAK
+case 55:
+YY_RULE_SETUP
+#line 183 "conf_lexer.l"
+{ return NEED_IDENT; }
+ YY_BREAK
+case 56:
+YY_RULE_SETUP
+#line 184 "conf_lexer.l"
+{ return NEED_IDENT; }
+ YY_BREAK
+case 57:
+YY_RULE_SETUP
+#line 185 "conf_lexer.l"
+{ return HAVENT_READ_CONF; }
+ YY_BREAK
+case 58:
+YY_RULE_SETUP
+#line 186 "conf_lexer.l"
+{ return HIDDEN; }
+ YY_BREAK
+case 59:
+YY_RULE_SETUP
+#line 187 "conf_lexer.l"
+{ return HIDDEN_NAME; }
+ YY_BREAK
+case 60:
+YY_RULE_SETUP
+#line 188 "conf_lexer.l"
+{ return HIDE_SERVER_IPS; }
+ YY_BREAK
+case 61:
+YY_RULE_SETUP
+#line 189 "conf_lexer.l"
+{ return HIDE_SERVERS; }
+ YY_BREAK
+case 62:
+YY_RULE_SETUP
+#line 190 "conf_lexer.l"
+{ return HIDE_SPOOF_IPS; }
+ YY_BREAK
+case 63:
+YY_RULE_SETUP
+#line 191 "conf_lexer.l"
+{ return HOST; }
+ YY_BREAK
+case 64:
+YY_RULE_SETUP
+#line 192 "conf_lexer.l"
+{ return HUB; }
+ YY_BREAK
+case 65:
+YY_RULE_SETUP
+#line 193 "conf_lexer.l"
+{ return HUB_MASK; }
+ YY_BREAK
+case 66:
+YY_RULE_SETUP
+#line 194 "conf_lexer.l"
+{ return IGNORE_BOGUS_TS; }
+ YY_BREAK
+case 67:
+YY_RULE_SETUP
+#line 195 "conf_lexer.l"
+{ return INVISIBLE_ON_CONNECT; }
+ YY_BREAK
+case 68:
+YY_RULE_SETUP
+#line 196 "conf_lexer.l"
+{ return IP; }
+ YY_BREAK
+case 69:
+YY_RULE_SETUP
+#line 197 "conf_lexer.l"
+{ return T_IPV4; }
+ YY_BREAK
+case 70:
+YY_RULE_SETUP
+#line 198 "conf_lexer.l"
+{ return T_IPV6; }
+ YY_BREAK
+case 71:
+YY_RULE_SETUP
+#line 199 "conf_lexer.l"
+{ return JOIN_FLOOD_COUNT; }
+ YY_BREAK
+case 72:
+YY_RULE_SETUP
+#line 200 "conf_lexer.l"
+{ return JOIN_FLOOD_TIME; }
+ YY_BREAK
+case 73:
+YY_RULE_SETUP
+#line 201 "conf_lexer.l"
+{ return KILL; }
+ YY_BREAK
+case 74:
+YY_RULE_SETUP
+#line 202 "conf_lexer.l"
+{ return KILL_CHASE_TIME_LIMIT; }
+ YY_BREAK
+case 75:
+YY_RULE_SETUP
+#line 203 "conf_lexer.l"
+{ return KLINE; }
+ YY_BREAK
+case 76:
+YY_RULE_SETUP
+#line 204 "conf_lexer.l"
+{ return KLINE_EXEMPT; }
+ YY_BREAK
+case 77:
+YY_RULE_SETUP
+#line 205 "conf_lexer.l"
+{ return LEAF_MASK; }
+ YY_BREAK
+case 78:
+YY_RULE_SETUP
+#line 206 "conf_lexer.l"
+{ return LISTEN; }
+ YY_BREAK
+case 79:
+YY_RULE_SETUP
+#line 207 "conf_lexer.l"
+{ return T_LOG; }
+ YY_BREAK
+case 80:
+YY_RULE_SETUP
+#line 208 "conf_lexer.l"
+{ return TMASKED; }
+ YY_BREAK
+case 81:
+YY_RULE_SETUP
+#line 209 "conf_lexer.l"
+{ return T_MAX_CLIENTS; }
+ YY_BREAK
+case 82:
+YY_RULE_SETUP
+#line 210 "conf_lexer.l"
+{ return MAX_IDENT; }
+ YY_BREAK
+case 83:
+YY_RULE_SETUP
+#line 211 "conf_lexer.l"
+{ return MAX_LOCAL; }
+ YY_BREAK
+case 84:
+YY_RULE_SETUP
+#line 212 "conf_lexer.l"
+{ return MAX_GLOBAL; }
+ YY_BREAK
+case 85:
+YY_RULE_SETUP
+#line 213 "conf_lexer.l"
+{ return MAX_NUMBER; }
+ YY_BREAK
+case 86:
+YY_RULE_SETUP
+#line 214 "conf_lexer.l"
+{ return MAX_WATCH; }
+ YY_BREAK
+case 87:
+YY_RULE_SETUP
+#line 215 "conf_lexer.l"
+{ return MESSAGE_LOCALE; }
+ YY_BREAK
+case 88:
+YY_RULE_SETUP
+#line 216 "conf_lexer.l"
+{ return MIN_NONWILDCARD; }
+ YY_BREAK
+case 89:
+YY_RULE_SETUP
+#line 217 "conf_lexer.l"
+{ return MIN_NONWILDCARD_SIMPLE; }
+ YY_BREAK
+case 90:
+YY_RULE_SETUP
+#line 218 "conf_lexer.l"
+{ return NAME; }
+ YY_BREAK
+case 91:
+YY_RULE_SETUP
+#line 219 "conf_lexer.l"
+{ return NEED_PASSWORD; }
+ YY_BREAK
+case 92:
+YY_RULE_SETUP
+#line 220 "conf_lexer.l"
+{ return NETWORK_DESC; }
+ YY_BREAK
+case 93:
+YY_RULE_SETUP
+#line 221 "conf_lexer.l"
+{ return NETWORK_NAME; }
+ YY_BREAK
+case 94:
+YY_RULE_SETUP
+#line 222 "conf_lexer.l"
+{ return NICK; }
+ YY_BREAK
+case 95:
+YY_RULE_SETUP
+#line 223 "conf_lexer.l"
+{ return NICK_CHANGES; }
+ YY_BREAK
+case 96:
+YY_RULE_SETUP
+#line 224 "conf_lexer.l"
+{ yylval.number = 0; return TBOOL; }
+ YY_BREAK
+case 97:
+YY_RULE_SETUP
+#line 225 "conf_lexer.l"
+{ return NO_CREATE_ON_SPLIT; }
+ YY_BREAK
+case 98:
+YY_RULE_SETUP
+#line 226 "conf_lexer.l"
+{ return NO_JOIN_ON_SPLIT; }
+ YY_BREAK
+case 99:
+YY_RULE_SETUP
+#line 227 "conf_lexer.l"
+{ return NO_OPER_FLOOD; }
+ YY_BREAK
+case 100:
+YY_RULE_SETUP
+#line 228 "conf_lexer.l"
+{ return NO_TILDE; }
+ YY_BREAK
+case 101:
+YY_RULE_SETUP
+#line 229 "conf_lexer.l"
+{ return NUMBER_PER_CIDR; }
+ YY_BREAK
+case 102:
+YY_RULE_SETUP
+#line 230 "conf_lexer.l"
+{ return NUMBER_PER_IP; }
+ YY_BREAK
+case 103:
+YY_RULE_SETUP
+#line 231 "conf_lexer.l"
+{ return OPERATOR; }
+ YY_BREAK
+case 104:
+YY_RULE_SETUP
+#line 232 "conf_lexer.l"
+{ return OPER_PASS_RESV; }
+ YY_BREAK
+case 105:
+YY_RULE_SETUP
+#line 233 "conf_lexer.l"
+{ return OPERATOR; }
+ YY_BREAK
+case 106:
+YY_RULE_SETUP
+#line 234 "conf_lexer.l"
+{ return PASSWORD; }
+ YY_BREAK
+case 107:
+YY_RULE_SETUP
+#line 235 "conf_lexer.l"
+{ return PASSWORD; }
+ YY_BREAK
+case 108:
+YY_RULE_SETUP
+#line 236 "conf_lexer.l"
+{ return PING_COOKIE; }
+ YY_BREAK
+case 109:
+YY_RULE_SETUP
+#line 237 "conf_lexer.l"
+{ return PING_TIME; }
+ YY_BREAK
+case 110:
+YY_RULE_SETUP
+#line 238 "conf_lexer.l"
+{ return PING_WARNING; }
+ YY_BREAK
+case 111:
+YY_RULE_SETUP
+#line 239 "conf_lexer.l"
+{ return PORT; }
+ YY_BREAK
+case 112:
+YY_RULE_SETUP
+#line 240 "conf_lexer.l"
+{ return RESV; }
+ YY_BREAK
+case 113:
+YY_RULE_SETUP
+#line 241 "conf_lexer.l"
+{ return QUIET_ON_BAN; }
+ YY_BREAK
+case 114:
+YY_RULE_SETUP
+#line 242 "conf_lexer.l"
+{ return REASON; }
+ YY_BREAK
+case 115:
+YY_RULE_SETUP
+#line 243 "conf_lexer.l"
+{ return T_RECVQ; }
+ YY_BREAK
+case 116:
+YY_RULE_SETUP
+#line 244 "conf_lexer.l"
+{ return REDIRPORT; }
+ YY_BREAK
+case 117:
+YY_RULE_SETUP
+#line 245 "conf_lexer.l"
+{ return REDIRSERV; }
+ YY_BREAK
+case 118:
+YY_RULE_SETUP
+#line 246 "conf_lexer.l"
+{ return REGEX_T; }
+ YY_BREAK
+case 119:
+YY_RULE_SETUP
+#line 247 "conf_lexer.l"
+{ return REHASH; }
+ YY_BREAK
+case 120:
+YY_RULE_SETUP
+#line 248 "conf_lexer.l"
+{ return REMOTE; }
+ YY_BREAK
+case 121:
+YY_RULE_SETUP
+#line 249 "conf_lexer.l"
+{ return REMOTEBAN; }
+ YY_BREAK
+case 122:
+YY_RULE_SETUP
+#line 250 "conf_lexer.l"
+{ return T_RESTART; }
+ YY_BREAK
+case 123:
+YY_RULE_SETUP
+#line 251 "conf_lexer.l"
+{ return RESTRICT_CHANNELS; }
+ YY_BREAK
+case 124:
+YY_RULE_SETUP
+#line 252 "conf_lexer.l"
+{ return RESV; }
+ YY_BREAK
+case 125:
+YY_RULE_SETUP
+#line 253 "conf_lexer.l"
+{ return RESV_EXEMPT; }
+ YY_BREAK
+case 126:
+YY_RULE_SETUP
+#line 254 "conf_lexer.l"
+{ return RSA_PRIVATE_KEY_FILE; }
+ YY_BREAK
+case 127:
+YY_RULE_SETUP
+#line 255 "conf_lexer.l"
+{ return RSA_PUBLIC_KEY_FILE; }
+ YY_BREAK
+case 128:
+YY_RULE_SETUP
+#line 256 "conf_lexer.l"
+{ return T_SSL; }
+ YY_BREAK
+case 129:
+YY_RULE_SETUP
+#line 257 "conf_lexer.l"
+{ return SSL_CERTIFICATE_FILE; }
+ YY_BREAK
+case 130:
+YY_RULE_SETUP
+#line 258 "conf_lexer.l"
+{ return T_SSL_CLIENT_METHOD; }
+ YY_BREAK
+case 131:
+YY_RULE_SETUP
+#line 259 "conf_lexer.l"
+{ return T_SSL_SERVER_METHOD; }
+ YY_BREAK
+case 132:
+YY_RULE_SETUP
+#line 260 "conf_lexer.l"
+{ return SSL_DH_PARAM_FILE; }
+ YY_BREAK
+case 133:
+YY_RULE_SETUP
+#line 261 "conf_lexer.l"
+{ return T_SSL_CIPHER_LIST; }
+ YY_BREAK
+case 134:
+YY_RULE_SETUP
+#line 262 "conf_lexer.l"
+{ return T_SSLV3; }
+ YY_BREAK
+case 135:
+YY_RULE_SETUP
+#line 263 "conf_lexer.l"
+{ return T_TLSV1; }
+ YY_BREAK
+case 136:
+YY_RULE_SETUP
+#line 264 "conf_lexer.l"
+{ return SEND_PASSWORD; }
+ YY_BREAK
+case 137:
+YY_RULE_SETUP
+#line 265 "conf_lexer.l"
+{ return SENDQ; }
+ YY_BREAK
+case 138:
+YY_RULE_SETUP
+#line 266 "conf_lexer.l"
+{ return T_SERVER; }
+ YY_BREAK
+case 139:
+YY_RULE_SETUP
+#line 267 "conf_lexer.l"
+{ return SERVERHIDE; }
+ YY_BREAK
+case 140:
+YY_RULE_SETUP
+#line 268 "conf_lexer.l"
+{ return SERVERINFO; }
+ YY_BREAK
+case 141:
+YY_RULE_SETUP
+#line 269 "conf_lexer.l"
+{ return T_SERVICE; }
+ YY_BREAK
+case 142:
+YY_RULE_SETUP
+#line 270 "conf_lexer.l"
+{ return T_SERVICES_NAME; }
+ YY_BREAK
+case 143:
+YY_RULE_SETUP
+#line 271 "conf_lexer.l"
+{ return T_SET; }
+ YY_BREAK
+case 144:
+YY_RULE_SETUP
+#line 272 "conf_lexer.l"
+{ return T_SHARED; }
+ YY_BREAK
+case 145:
+YY_RULE_SETUP
+#line 273 "conf_lexer.l"
+{ return SHORT_MOTD; }
+ YY_BREAK
+case 146:
+YY_RULE_SETUP
+#line 274 "conf_lexer.l"
+{ return IRCD_SID; }
+ YY_BREAK
+case 147:
+YY_RULE_SETUP
+#line 275 "conf_lexer.l"
+{ return T_SIZE; }
+ YY_BREAK
+case 148:
+YY_RULE_SETUP
+#line 276 "conf_lexer.l"
+{ return SPOOF; }
+ YY_BREAK
+case 149:
+YY_RULE_SETUP
+#line 277 "conf_lexer.l"
+{ return SPOOF_NOTICE; }
+ YY_BREAK
+case 150:
+YY_RULE_SETUP
+#line 278 "conf_lexer.l"
+{ return TKLINE_EXPIRE_NOTICES; }
+ YY_BREAK
+case 151:
+YY_RULE_SETUP
+#line 279 "conf_lexer.l"
+{ return TYPE; }
+ YY_BREAK
+case 152:
+YY_RULE_SETUP
+#line 280 "conf_lexer.l"
+{ return TRUE_NO_OPER_FLOOD; }
+ YY_BREAK
+case 153:
+YY_RULE_SETUP
+#line 281 "conf_lexer.l"
+{ return T_UMODES; }
+ YY_BREAK
+case 154:
+YY_RULE_SETUP
+#line 282 "conf_lexer.l"
+{ return UNKLINE; }
+ YY_BREAK
+case 155:
+YY_RULE_SETUP
+#line 283 "conf_lexer.l"
+{ return T_UNDLINE; }
+ YY_BREAK
+case 156:
+YY_RULE_SETUP
+#line 284 "conf_lexer.l"
+{ return T_UNLIMITED; }
+ YY_BREAK
+case 157:
+YY_RULE_SETUP
+#line 285 "conf_lexer.l"
+{ return USE_EGD; }
+ YY_BREAK
+case 158:
+YY_RULE_SETUP
+#line 286 "conf_lexer.l"
+{ return USE_LOGGING; }
+ YY_BREAK
+case 159:
+YY_RULE_SETUP
+#line 287 "conf_lexer.l"
+{ return THROTTLE_TIME; }
+ YY_BREAK
+case 160:
+YY_RULE_SETUP
+#line 288 "conf_lexer.l"
+{ return USER; }
+ YY_BREAK
+case 161:
+YY_RULE_SETUP
+#line 289 "conf_lexer.l"
+{ return VHOST; }
+ YY_BREAK
+case 162:
+YY_RULE_SETUP
+#line 290 "conf_lexer.l"
+{ return VHOST6; }
+ YY_BREAK
+case 163:
+YY_RULE_SETUP
+#line 291 "conf_lexer.l"
+{ return XLINE; }
+ YY_BREAK
+case 164:
+YY_RULE_SETUP
+#line 292 "conf_lexer.l"
+{ yylval.number = 1; return TBOOL; }
+ YY_BREAK
+case 165:
+YY_RULE_SETUP
+#line 294 "conf_lexer.l"
+{ return FAILED_OPER_NOTICE; }
+ YY_BREAK
+case 166:
+YY_RULE_SETUP
+#line 295 "conf_lexer.l"
+{ return MAX_ACCEPT; }
+ YY_BREAK
+case 167:
+YY_RULE_SETUP
+#line 296 "conf_lexer.l"
+{ return MAX_NICK_CHANGES; }
+ YY_BREAK
+case 168:
+YY_RULE_SETUP
+#line 297 "conf_lexer.l"
+{ return MAX_CHANS_PER_OPER; }
+ YY_BREAK
+case 169:
+YY_RULE_SETUP
+#line 298 "conf_lexer.l"
+{ return MAX_CHANS_PER_USER; }
+ YY_BREAK
+case 170:
+YY_RULE_SETUP
+#line 299 "conf_lexer.l"
+{ return MAX_NICK_TIME; }
+ YY_BREAK
+case 171:
+YY_RULE_SETUP
+#line 300 "conf_lexer.l"
+{ return ANTI_NICK_FLOOD; }
+ YY_BREAK
+case 172:
+YY_RULE_SETUP
+#line 301 "conf_lexer.l"
+{ return ANTI_SPAM_EXIT_MESSAGE_TIME; }
+ YY_BREAK
+case 173:
+YY_RULE_SETUP
+#line 302 "conf_lexer.l"
+{ return TS_MAX_DELTA; }
+ YY_BREAK
+case 174:
+YY_RULE_SETUP
+#line 303 "conf_lexer.l"
+{ return TS_WARN_DELTA; }
+ YY_BREAK
+case 175:
+YY_RULE_SETUP
+#line 304 "conf_lexer.l"
+{ return LINKS_DELAY; }
+ YY_BREAK
+case 176:
+YY_RULE_SETUP
+#line 305 "conf_lexer.l"
+{ return WARN_NO_NLINE; }
+ YY_BREAK
+case 177:
+YY_RULE_SETUP
+#line 307 "conf_lexer.l"
+{ return STATS_E_DISABLED; }
+ YY_BREAK
+case 178:
+YY_RULE_SETUP
+#line 308 "conf_lexer.l"
+{ return STATS_O_OPER_ONLY; }
+ YY_BREAK
+case 179:
+YY_RULE_SETUP
+#line 309 "conf_lexer.l"
+{ return STATS_K_OPER_ONLY; }
+ YY_BREAK
+case 180:
+YY_RULE_SETUP
+#line 310 "conf_lexer.l"
+{ return STATS_I_OPER_ONLY; }
+ YY_BREAK
+case 181:
+YY_RULE_SETUP
+#line 311 "conf_lexer.l"
+{ return STATS_P_OPER_ONLY; }
+ YY_BREAK
+case 182:
+YY_RULE_SETUP
+#line 312 "conf_lexer.l"
+{ return PACE_WAIT; }
+ YY_BREAK
+case 183:
+YY_RULE_SETUP
+#line 313 "conf_lexer.l"
+{ return PACE_WAIT_SIMPLE; }
+ YY_BREAK
+case 184:
+YY_RULE_SETUP
+#line 314 "conf_lexer.l"
+{ return KNOCK_DELAY; }
+ YY_BREAK
+case 185:
+YY_RULE_SETUP
+#line 315 "conf_lexer.l"
+{ return KNOCK_DELAY_CHANNEL; }
+ YY_BREAK
+case 186:
+YY_RULE_SETUP
+#line 316 "conf_lexer.l"
+{ return MAX_BANS; }
+ YY_BREAK
+case 187:
+YY_RULE_SETUP
+#line 317 "conf_lexer.l"
+{ return MODULES; }
+ YY_BREAK
+case 188:
+YY_RULE_SETUP
+#line 318 "conf_lexer.l"
+{ return MODULE; }
+ YY_BREAK
+case 189:
+YY_RULE_SETUP
+#line 319 "conf_lexer.l"
+{ return PATH; }
+ YY_BREAK
+case 190:
+YY_RULE_SETUP
+#line 320 "conf_lexer.l"
+{ return MAX_TARGETS; }
+ YY_BREAK
+case 191:
+YY_RULE_SETUP
+#line 322 "conf_lexer.l"
+{ return T_UNXLINE; }
+ YY_BREAK
+case 192:
+YY_RULE_SETUP
+#line 323 "conf_lexer.l"
+{ return T_UNRESV; }
+ YY_BREAK
+case 193:
+YY_RULE_SETUP
+#line 325 "conf_lexer.l"
+{ return OPER_ONLY_UMODES; }
+ YY_BREAK
+case 194:
+YY_RULE_SETUP
+#line 326 "conf_lexer.l"
+{ return OPER_UMODES; }
+ YY_BREAK
+case 195:
+YY_RULE_SETUP
+#line 327 "conf_lexer.l"
+{ return T_BOTS; }
+ YY_BREAK
+case 196:
+YY_RULE_SETUP
+#line 328 "conf_lexer.l"
+{ return T_CCONN; }
+ YY_BREAK
+case 197:
+YY_RULE_SETUP
+#line 329 "conf_lexer.l"
+{ return T_CCONN_FULL; }
+ YY_BREAK
+case 198:
+YY_RULE_SETUP
+#line 330 "conf_lexer.l"
+{ return T_DEAF; }
+ YY_BREAK
+case 199:
+YY_RULE_SETUP
+#line 331 "conf_lexer.l"
+{ return T_DEBUG; }
+ YY_BREAK
+case 200:
+YY_RULE_SETUP
+#line 332 "conf_lexer.l"
+{ return T_FULL; }
+ YY_BREAK
+case 201:
+YY_RULE_SETUP
+#line 333 "conf_lexer.l"
+{ return T_SKILL; }
+ YY_BREAK
+case 202:
+YY_RULE_SETUP
+#line 334 "conf_lexer.l"
+{ return T_NCHANGE; }
+ YY_BREAK
+case 203:
+YY_RULE_SETUP
+#line 335 "conf_lexer.l"
+{ return T_REJ; }
+ YY_BREAK
+case 204:
+YY_RULE_SETUP
+#line 336 "conf_lexer.l"
+{ return T_UNAUTH; }
+ YY_BREAK
+case 205:
+YY_RULE_SETUP
+#line 337 "conf_lexer.l"
+{ return T_SPY; }
+ YY_BREAK
+case 206:
+YY_RULE_SETUP
+#line 338 "conf_lexer.l"
+{ return T_EXTERNAL; }
+ YY_BREAK
+case 207:
+YY_RULE_SETUP
+#line 339 "conf_lexer.l"
+{ return T_OPERWALL; }
+ YY_BREAK
+case 208:
+YY_RULE_SETUP
+#line 340 "conf_lexer.l"
+{ return T_SERVNOTICE; }
+ YY_BREAK
+case 209:
+YY_RULE_SETUP
+#line 341 "conf_lexer.l"
+{ return T_INVISIBLE; }
+ YY_BREAK
+case 210:
+YY_RULE_SETUP
+#line 342 "conf_lexer.l"
+{ return T_WALLOP; }
+ YY_BREAK
+case 211:
+YY_RULE_SETUP
+#line 343 "conf_lexer.l"
+{ return T_CALLERID; }
+ YY_BREAK
+case 212:
+YY_RULE_SETUP
+#line 344 "conf_lexer.l"
+{ return T_SOFTCALLERID; }
+ YY_BREAK
+case 213:
+YY_RULE_SETUP
+#line 345 "conf_lexer.l"
+{ return T_LOCOPS; }
+ YY_BREAK
+case 214:
+YY_RULE_SETUP
+#line 347 "conf_lexer.l"
+{ return WEEKS; }
+ YY_BREAK
+case 215:
+YY_RULE_SETUP
+#line 348 "conf_lexer.l"
+{ return WEEKS; }
+ YY_BREAK
+case 216:
+YY_RULE_SETUP
+#line 349 "conf_lexer.l"
+{ return DAYS; }
+ YY_BREAK
+case 217:
+YY_RULE_SETUP
+#line 350 "conf_lexer.l"
+{ return DAYS; }
+ YY_BREAK
+case 218:
+YY_RULE_SETUP
+#line 351 "conf_lexer.l"
+{ return HOURS; }
+ YY_BREAK
+case 219:
+YY_RULE_SETUP
+#line 352 "conf_lexer.l"
+{ return HOURS; }
+ YY_BREAK
+case 220:
+YY_RULE_SETUP
+#line 353 "conf_lexer.l"
+{ return MINUTES; }
+ YY_BREAK
+case 221:
+YY_RULE_SETUP
+#line 354 "conf_lexer.l"
+{ return MINUTES; }
+ YY_BREAK
+case 222:
+YY_RULE_SETUP
+#line 355 "conf_lexer.l"
+{ return SECONDS; }
+ YY_BREAK
+case 223:
+YY_RULE_SETUP
+#line 356 "conf_lexer.l"
+{ return SECONDS; }
+ YY_BREAK
+case 224:
+YY_RULE_SETUP
+#line 358 "conf_lexer.l"
+{ return BYTES; }
+ YY_BREAK
+case 225:
+YY_RULE_SETUP
+#line 359 "conf_lexer.l"
+{ return BYTES; }
+ YY_BREAK
+case 226:
+YY_RULE_SETUP
+#line 360 "conf_lexer.l"
+{ return KBYTES; }
+ YY_BREAK
+case 227:
+YY_RULE_SETUP
+#line 361 "conf_lexer.l"
+{ return KBYTES; }
+ YY_BREAK
+case 228:
+YY_RULE_SETUP
+#line 362 "conf_lexer.l"
+{ return KBYTES; }
+ YY_BREAK
+case 229:
+YY_RULE_SETUP
+#line 363 "conf_lexer.l"
+{ return KBYTES; }
+ YY_BREAK
+case 230:
+YY_RULE_SETUP
+#line 364 "conf_lexer.l"
+{ return KBYTES; }
+ YY_BREAK
+case 231:
+YY_RULE_SETUP
+#line 365 "conf_lexer.l"
+{ return MBYTES; }
+ YY_BREAK
+case 232:
+YY_RULE_SETUP
+#line 366 "conf_lexer.l"
+{ return MBYTES; }
+ YY_BREAK
+case 233:
+YY_RULE_SETUP
+#line 367 "conf_lexer.l"
+{ return MBYTES; }
+ YY_BREAK
+case 234:
+YY_RULE_SETUP
+#line 368 "conf_lexer.l"
+{ return MBYTES; }
+ YY_BREAK
+case 235:
+YY_RULE_SETUP
+#line 369 "conf_lexer.l"
+{ return MBYTES; }
+ YY_BREAK
+case 236:
+YY_RULE_SETUP
+#line 370 "conf_lexer.l"
+{ return TWODOTS; }
+ YY_BREAK
+case 237:
+YY_RULE_SETUP
+#line 372 "conf_lexer.l"
+{ return yytext[0]; }
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+#line 373 "conf_lexer.l"
+{ if (ieof()) yyterminate(); }
+ YY_BREAK
+case 238:
+YY_RULE_SETUP
+#line 375 "conf_lexer.l"
+ECHO;
+ YY_BREAK
+#line 3206 "conf_lexer.c"
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = (yy_hold_char);
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++(yy_c_buf_p);
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ (yy_did_buffer_switch_on_eof) = 0;
+
+ if ( yywrap( ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) =
+ (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ (yy_c_buf_p) =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = (yytext_ptr);
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+ else
+ {
+ yy_size_t num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+ int yy_c_buf_p_offset =
+ (int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ yy_size_t new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ (yy_n_chars), num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ if ( (yy_n_chars) == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart(yyin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+ (yy_n_chars) += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+ (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (void)
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = (yy_start);
+
+ for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 1546 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
+{
+ register int yy_is_jam;
+ register char *yy_cp = (yy_c_buf_p);
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 1546 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 1545);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (void)
+#else
+ static int input (void)
+#endif
+
+{
+ int c;
+
+ *(yy_c_buf_p) = (yy_hold_char);
+
+ if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ /* This was really a NUL. */
+ *(yy_c_buf_p) = '\0';
+
+ else
+ { /* need more input */
+ yy_size_t offset = (yy_c_buf_p) - (yytext_ptr);
+ ++(yy_c_buf_p);
+
+ switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart(yyin );
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap( ) )
+ return EOF;
+
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) = (yytext_ptr) + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
+ *(yy_c_buf_p) = '\0'; /* preserve yytext */
+ (yy_hold_char) = *++(yy_c_buf_p);
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ *
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void yyrestart (FILE * input_file )
+{
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer(yyin,YY_BUF_SIZE );
+ }
+
+ yy_init_buffer(YY_CURRENT_BUFFER,input_file );
+ yy_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ *
+ */
+ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
+{
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * yypop_buffer_state();
+ * yypush_buffer_state(new_buffer);
+ */
+ yyensure_buffer_stack ();
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ yy_load_buffer_state( );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void yy_load_buffer_state (void)
+{
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ (yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ *
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size )
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer(b,file );
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ *
+ */
+ void yy_delete_buffer (YY_BUFFER_STATE b )
+{
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yyfree((void *) b->yy_ch_buf );
+
+ yyfree((void *) b );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file )
+
+{
+ int oerrno = errno;
+
+ yy_flush_buffer(b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then yy_init_buffer was _probably_
+ * called from yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ *
+ */
+ void yy_flush_buffer (YY_BUFFER_STATE b )
+{
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ yy_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ *
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+ if (new_buffer == NULL)
+ return;
+
+ yyensure_buffer_stack();
+
+ /* This block is copied from yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ (yy_buffer_stack_top)++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from yy_switch_to_buffer. */
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ *
+ */
+void yypop_buffer_state (void)
+{
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if ((yy_buffer_stack_top) > 0)
+ --(yy_buffer_stack_top);
+
+ if (YY_CURRENT_BUFFER) {
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (void)
+{
+ yy_size_t num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ (yy_buffer_stack_max) = num_to_alloc;
+ (yy_buffer_stack_top) = 0;
+ return;
+ }
+
+ if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = (yy_buffer_stack_max) + grow_size;
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
+ ((yy_buffer_stack),
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+ (yy_buffer_stack_max) = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer(b );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ *
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
+{
+
+ return yy_scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len )
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) yyalloc(n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer(buf,n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = (yy_hold_char); \
+ (yy_c_buf_p) = yytext + yyless_macro_arg; \
+ (yy_hold_char) = *(yy_c_buf_p); \
+ *(yy_c_buf_p) = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ *
+ */
+int yyget_lineno (void)
+{
+
+ return yylineno;
+}
+
+/** Get the input stream.
+ *
+ */
+FILE *yyget_in (void)
+{
+ return yyin;
+}
+
+/** Get the output stream.
+ *
+ */
+FILE *yyget_out (void)
+{
+ return yyout;
+}
+
+/** Get the length of the current token.
+ *
+ */
+yy_size_t yyget_leng (void)
+{
+ return yyleng;
+}
+
+/** Get the current token.
+ *
+ */
+
+char *yyget_text (void)
+{
+ return yytext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ *
+ */
+void yyset_lineno (int line_number )
+{
+
+ yylineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ *
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE * in_str )
+{
+ yyin = in_str ;
+}
+
+void yyset_out (FILE * out_str )
+{
+ yyout = out_str ;
+}
+
+int yyget_debug (void)
+{
+ return yy_flex_debug;
+}
+
+void yyset_debug (int bdebug )
+{
+ yy_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from yylex_destroy(), so don't allocate here.
+ */
+
+ (yy_buffer_stack) = 0;
+ (yy_buffer_stack_top) = 0;
+ (yy_buffer_stack_max) = 0;
+ (yy_c_buf_p) = (char *) 0;
+ (yy_init) = 0;
+ (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = (FILE *) 0;
+ yyout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * yylex_init()
+ */
+ return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy (void)
+{
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ yy_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ yypop_buffer_state();
+ }
+
+ /* Destroy the stack itself. */
+ yyfree((yy_buffer_stack) );
+ (yy_buffer_stack) = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * yylex() is called, initialization will occur. */
+ yy_init_globals( );
+
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *yyalloc (yy_size_t size )
+{
+ return (void *) malloc( size );
+}
+
+void *yyrealloc (void * ptr, yy_size_t size )
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void yyfree (void * ptr )
+{
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 375 "conf_lexer.l"
+
+
+
+/* C-comment ignoring routine -kre*/
+static void
+ccomment(void)
+{
+ int c = 0;
+
+ /* log(L_NOTICE, "got comment"); */
+ while (1)
+ {
+ while ((c = input()) != '*' && c != EOF)
+ if (c == '\n')
+ ++lineno;
+
+ if (c == '*')
+ {
+ while ((c = input()) == '*')
+ /* Nothing */ ;
+ if (c == '/')
+ break;
+ else if (c == '\n')
+ ++lineno;
+ }
+
+ if (c == EOF)
+ {
+ YY_FATAL_ERROR("EOF in comment");
+ /* XXX hack alert this disables
+ * the stupid unused function warning
+ * gcc generates
+ */
+ if (1 == 0)
+ yy_fatal_error("EOF in comment");
+ break;
+ }
+ }
+}
+
+/* C-style .includes. This function will properly swap input conf buffers,
+ * and lineno -kre */
+static void
+cinclude(void)
+{
+ char *p = NULL;
+
+ if ((p = strchr(yytext, '<')) == NULL)
+ *strchr(p = strchr(yytext, '"') + 1, '"') = '\0';
+ else
+ *strchr(++p, '>') = '\0';
+
+ /* log(L_NOTICE, "got include %s!", c); */
+
+ /* do stacking and co. */
+ if (include_stack_ptr >= MAX_INCLUDE_DEPTH)
+ ilog(LOG_TYPE_IRCD, "Includes nested too deep in %s", p);
+ else
+ {
+ FILE *tmp_fbfile_in = NULL;
+ char filenamebuf[IRCD_BUFSIZE];
+
+ if (*p == '/') /* if it is an absolute path */
+ snprintf(filenamebuf, sizeof(filenamebuf), "%s", p);
+ else
+ snprintf(filenamebuf, sizeof(filenamebuf), "%s/%s", ETCPATH, p);
+
+ tmp_fbfile_in = fopen(filenamebuf, "r");
+
+ if (tmp_fbfile_in == NULL)
+ {
+ ilog(LOG_TYPE_IRCD, "Unable to read configuration file '%s': %s",
+ filenamebuf, strerror(errno));
+ return;
+ }
+
+ lineno_stack[include_stack_ptr] = lineno;
+ lineno = 1;
+ inc_fbfile_in[include_stack_ptr] = conf_parser_ctx.conf_file;
+ strlcpy(conffile_stack[include_stack_ptr], conffilebuf, IRCD_BUFSIZE);
+ include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER;
+ conf_parser_ctx.conf_file = tmp_fbfile_in;
+ snprintf(conffilebuf, sizeof(conffilebuf), "%s", filenamebuf);
+ yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE));
+ }
+}
+
+/* This is function that will be called on EOF in conf file. It will
+ * apropriately close conf if it not main conf and swap input buffers -kre
+ * */
+static int
+ieof(void)
+{
+ /* log(L_NOTICE, "return from include stack!"); */
+ if (include_stack_ptr)
+ fclose(conf_parser_ctx.conf_file);
+ if (--include_stack_ptr < 0)
+ {
+ /* log(L_NOTICE, "terminating lexer"); */
+ /* 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 */
+ /* log(L_NOTICE, "deleting include_stack_ptr=%d", include_stack_ptr); */
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ lineno = lineno_stack[include_stack_ptr];
+ conf_parser_ctx.conf_file = inc_fbfile_in[include_stack_ptr];
+ strlcpy(conffilebuf, conffile_stack[include_stack_ptr], sizeof(conffilebuf));
+ yy_switch_to_buffer(include_stack[include_stack_ptr]);
+
+ return 0;
+}
+
diff --git a/src/conf_lexer.l b/src/conf_lexer.l
new file mode 100644
index 0000000..d089a57
--- /dev/null
+++ b/src/conf_lexer.l
@@ -0,0 +1,489 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * conf_lexer.l: Scans the ircd configuration file for tokens.
+ *
+ * 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$
+ */
+
+%option case-insensitive
+%option noyywrap
+%option nounput
+%option never-interactive
+
+%{
+#include "stdinc.h"
+#include "irc_string.h"
+#include "conf.h"
+#include "conf_parser.h" /* autogenerated header file */
+#include "memory.h"
+#include "hostmask.h"
+#include "log.h"
+
+#undef YY_INPUT
+#define YY_FATAL_ERROR(msg) conf_yy_fatal_error(msg)
+#define YY_INPUT(buf,result,max_size) \
+ if (!(result = conf_yy_input(buf, max_size))) \
+ YY_FATAL_ERROR("input in flex scanner failed");
+#define MAX_INCLUDE_DEPTH 10
+
+
+unsigned int lineno = 1;
+char linebuf[IRCD_BUFSIZE];
+char conffilebuf[IRCD_BUFSIZE];
+
+static int include_stack_ptr = 0;
+static YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
+static unsigned int lineno_stack[MAX_INCLUDE_DEPTH];
+static FILE *inc_fbfile_in[MAX_INCLUDE_DEPTH];
+static char conffile_stack[MAX_INCLUDE_DEPTH][IRCD_BUFSIZE];
+static void ccomment(void);
+static void cinclude(void);
+static int ieof(void);
+
+static int
+conf_yy_input(char *lbuf, unsigned int max_size)
+{
+ return !fgets(lbuf, max_size, conf_parser_ctx.conf_file) ? 0 : strlen(lbuf);
+}
+
+static int
+conf_yy_fatal_error(const char *msg)
+{
+ return 0;
+}
+
+%}
+
+WS [[:blank:]]*
+DIGIT [[:digit:]]+
+COMMENT ("//"|"#").*
+qstring \"[^\"\n]*[\"\n]
+include \.include{WS}(\<.*\>|\".*\")
+
+%%
+{include} { cinclude(); }
+"/*" { ccomment(); }
+
+\n.* { strlcpy(linebuf, yytext+1, sizeof(linebuf)); ++lineno; yyless(1); }
+
+{WS} ;
+{COMMENT} ;
+
+{DIGIT} { yylval.number = atoi(yytext); return NUMBER; }
+
+{qstring} { if (yytext[yyleng-2] == '\\')
+ {
+ yyless(yyleng-1); /* return last quote */
+ yymore(); /* append next string */
+ }
+ else
+ {
+ yylval.string = yytext+1;
+ if(yylval.string[yyleng-2] != '"')
+ ilog(LOG_TYPE_IRCD, "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(LOG_TYPE_IRCD,
+ "Unterminated character string");
+ break;
+ }
+ yylval.string[j] = yylval.string[i];
+ }
+ }
+ yylval.string[j] = '\0';
+ return QSTRING;
+ }
+ }
+ }
+
+accept_password { return ACCEPT_PASSWORD; }
+admin { return ADMIN; }
+administrator { return ADMIN; }
+aftype { return AFTYPE; }
+all { return T_ALL; }
+auth { return IRCD_AUTH; }
+autoconn { return AUTOCONN; }
+can_flood { return CAN_FLOOD; }
+caller_id_wait { return CALLER_ID_WAIT; }
+opers_bypass_callerid { return OPERS_BYPASS_CALLERID; }
+channel { return CHANNEL; }
+cidr_bitlen_ipv4 { return CIDR_BITLEN_IPV4; }
+cidr_bitlen_ipv6 { return CIDR_BITLEN_IPV6; }
+class { return CLASS; }
+cluster { return T_CLUSTER; }
+connect { return CONNECT; }
+connectfreq { return CONNECTFREQ; }
+default_floodcount { return DEFAULT_FLOODCOUNT; }
+default_split_server_count { return DEFAULT_SPLIT_SERVER_COUNT; }
+default_split_user_count { return DEFAULT_SPLIT_USER_COUNT; }
+deny { return DENY; }
+description { return DESCRIPTION; }
+die { return DIE; }
+disable_auth { return DISABLE_AUTH; }
+disable_fake_channels { return DISABLE_FAKE_CHANNELS; }
+disable_remote_commands { return DISABLE_REMOTE_COMMANDS; }
+dline { return T_DLINE; }
+dots_in_ident { return DOTS_IN_IDENT; }
+egdpool_path { return EGDPOOL_PATH; }
+email { return EMAIL; }
+encrypted { return ENCRYPTED; }
+exceed_limit { return EXCEED_LIMIT; }
+exempt { return EXEMPT; }
+file { return T_FILE; }
+flags { return IRCD_FLAGS; }
+flatten_links { return FLATTEN_LINKS; }
+gecos { return GECOS; }
+general { return GENERAL; }
+gline { return GLINE; }
+gline_enable { return GLINE_ENABLE; }
+gline_exempt { return GLINE_EXEMPT; }
+gline_duration { return GLINE_DURATION; }
+gline_request_duration { return GLINE_REQUEST_DURATION; }
+gline_min_cidr { return GLINE_MIN_CIDR; }
+gline_min_cidr6 { return GLINE_MIN_CIDR6; }
+globops { return T_GLOBOPS; }
+global_kill { return GLOBAL_KILL; }
+have_ident { return NEED_IDENT; }
+need_ident { return NEED_IDENT; }
+havent_read_conf { return HAVENT_READ_CONF; }
+hidden { return HIDDEN; }
+hidden_name { return HIDDEN_NAME; }
+hide_server_ips { return HIDE_SERVER_IPS; }
+hide_servers { return HIDE_SERVERS; }
+hide_spoof_ips { return HIDE_SPOOF_IPS; }
+host { return HOST; }
+hub { return HUB; }
+hub_mask { return HUB_MASK; }
+ignore_bogus_ts { return IGNORE_BOGUS_TS; }
+invisible_on_connect { return INVISIBLE_ON_CONNECT; }
+ip { return IP; }
+ipv4 { return T_IPV4; }
+ipv6 { return T_IPV6; }
+join_flood_count { return JOIN_FLOOD_COUNT; }
+join_flood_time { return JOIN_FLOOD_TIME; }
+kill { return KILL; }
+kill_chase_time_limit { return KILL_CHASE_TIME_LIMIT; }
+kline { return KLINE; }
+kline_exempt { return KLINE_EXEMPT; }
+leaf_mask { return LEAF_MASK; }
+listen { return LISTEN; }
+log { return T_LOG; }
+masked { return TMASKED; }
+max_clients { return T_MAX_CLIENTS; }
+max_ident { return MAX_IDENT; }
+max_local { return MAX_LOCAL; }
+max_global { return MAX_GLOBAL; }
+max_number { return MAX_NUMBER; }
+max_watch { return MAX_WATCH; }
+message_locale { return MESSAGE_LOCALE; }
+min_nonwildcard { return MIN_NONWILDCARD; }
+min_nonwildcard_simple { return MIN_NONWILDCARD_SIMPLE; }
+name { return NAME; }
+need_password { return NEED_PASSWORD; }
+network_desc { return NETWORK_DESC; }
+network_name { return NETWORK_NAME; }
+nick { return NICK; }
+nick_changes { return NICK_CHANGES; }
+no { yylval.number = 0; return TBOOL; }
+no_create_on_split { return NO_CREATE_ON_SPLIT; }
+no_join_on_split { return NO_JOIN_ON_SPLIT; }
+no_oper_flood { return NO_OPER_FLOOD; }
+no_tilde { return NO_TILDE; }
+number_per_cidr { return NUMBER_PER_CIDR; }
+number_per_ip { return NUMBER_PER_IP; }
+oper { return OPERATOR; }
+oper_pass_resv { return OPER_PASS_RESV; }
+operator { return OPERATOR; }
+passwd { return PASSWORD; }
+password { return PASSWORD; }
+ping_cookie { return PING_COOKIE; }
+ping_time { return PING_TIME; }
+ping_warning { return PING_WARNING; }
+port { return PORT; }
+quarantine { return RESV; }
+quiet_on_ban { return QUIET_ON_BAN; }
+reason { return REASON; }
+recvq { return T_RECVQ; }
+redirport { return REDIRPORT; }
+redirserv { return REDIRSERV; }
+regex { return REGEX_T; }
+rehash { return REHASH; }
+remote { return REMOTE; }
+remoteban { return REMOTEBAN; }
+restart { return T_RESTART; }
+restrict_channels { return RESTRICT_CHANNELS; }
+resv { return RESV; }
+resv_exempt { return RESV_EXEMPT; }
+rsa_private_key_file { return RSA_PRIVATE_KEY_FILE; }
+rsa_public_key_file { return RSA_PUBLIC_KEY_FILE; }
+ssl { return T_SSL; }
+ssl_certificate_file { return SSL_CERTIFICATE_FILE; }
+ssl_client_method { return T_SSL_CLIENT_METHOD; }
+ssl_server_method { return T_SSL_SERVER_METHOD; }
+ssl_dh_param_file { return SSL_DH_PARAM_FILE; }
+ssl_cipher_list { return T_SSL_CIPHER_LIST; }
+sslv3 { return T_SSLV3; }
+tlsv1 { return T_TLSV1; }
+send_password { return SEND_PASSWORD; }
+sendq { return SENDQ; }
+server { return T_SERVER; }
+serverhide { return SERVERHIDE; }
+serverinfo { return SERVERINFO; }
+service { return T_SERVICE; }
+services_name { return T_SERVICES_NAME; }
+set { return T_SET; }
+shared { return T_SHARED; }
+short_motd { return SHORT_MOTD; }
+sid { return IRCD_SID; }
+size { return T_SIZE; }
+spoof { return SPOOF; }
+spoof_notice { return SPOOF_NOTICE; }
+tkline_expire_notices { return TKLINE_EXPIRE_NOTICES; }
+type { return TYPE; }
+true_no_oper_flood { return TRUE_NO_OPER_FLOOD; }
+umodes { return T_UMODES; }
+unkline { return UNKLINE; }
+undline { return T_UNDLINE; }
+unlimited { return T_UNLIMITED; }
+use_egd { return USE_EGD; }
+use_logging { return USE_LOGGING; }
+throttle_time { return THROTTLE_TIME; }
+user { return USER; }
+vhost { return VHOST; }
+vhost6 { return VHOST6; }
+xline { return XLINE; }
+yes { yylval.number = 1; return TBOOL; }
+
+failed_oper_notice { return FAILED_OPER_NOTICE; }
+max_accept { return MAX_ACCEPT; }
+max_nick_changes { return MAX_NICK_CHANGES; }
+max_chans_per_oper { return MAX_CHANS_PER_OPER; }
+max_chans_per_user { return MAX_CHANS_PER_USER; }
+max_nick_time { return MAX_NICK_TIME; }
+anti_nick_flood { return ANTI_NICK_FLOOD; }
+anti_spam_exit_message_time { return ANTI_SPAM_EXIT_MESSAGE_TIME; }
+ts_max_delta { return TS_MAX_DELTA; }
+ts_warn_delta { return TS_WARN_DELTA; }
+links_delay { return LINKS_DELAY; }
+warn_no_nline { return WARN_NO_NLINE; }
+
+stats_e_disabled { return STATS_E_DISABLED; }
+stats_o_oper_only { return STATS_O_OPER_ONLY; }
+stats_k_oper_only { return STATS_K_OPER_ONLY; }
+stats_i_oper_only { return STATS_I_OPER_ONLY; }
+stats_P_oper_only { return STATS_P_OPER_ONLY; }
+pace_wait { return PACE_WAIT; }
+pace_wait_simple { return PACE_WAIT_SIMPLE; }
+knock_delay { return KNOCK_DELAY; }
+knock_delay_channel { return KNOCK_DELAY_CHANNEL; }
+max_bans { return MAX_BANS; }
+modules { return MODULES; }
+module { return MODULE; }
+path { return PATH; }
+max_targets { return MAX_TARGETS; }
+
+unxline { return T_UNXLINE; }
+unresv { return T_UNRESV; }
+
+oper_only_umodes { return OPER_ONLY_UMODES; }
+oper_umodes { return OPER_UMODES; }
+bots { return T_BOTS; }
+cconn { return T_CCONN; }
+cconn_full { return T_CCONN_FULL; }
+deaf { return T_DEAF; }
+debug { return T_DEBUG; }
+full { return T_FULL; }
+skill { return T_SKILL; }
+nchange { return T_NCHANGE; }
+rej { return T_REJ; }
+unauth { return T_UNAUTH; }
+spy { return T_SPY; }
+external { return T_EXTERNAL; }
+operwall { return T_OPERWALL; }
+servnotice { return T_SERVNOTICE; }
+invisible { return T_INVISIBLE; }
+wallop { return T_WALLOP; }
+callerid { return T_CALLERID; }
+softcallerid { return T_SOFTCALLERID; }
+locops { return T_LOCOPS; }
+
+weeks { return WEEKS; }
+week { return WEEKS; }
+days { return DAYS; }
+day { return DAYS; }
+hours { return HOURS; }
+hour { return HOURS; }
+minutes { return MINUTES; }
+minute { return MINUTES; }
+seconds { return SECONDS; }
+second { return SECONDS; }
+
+bytes { return BYTES; }
+byte { return BYTES; }
+kilobytes { return KBYTES; }
+kilobyte { return KBYTES; }
+kbytes { return KBYTES; }
+kbyte { return KBYTES; }
+kb { return KBYTES; }
+megabytes { return MBYTES; }
+megabyte { return MBYTES; }
+mbytes { return MBYTES; }
+mbyte { return MBYTES; }
+mb { return MBYTES; }
+\.\. { return TWODOTS; }
+
+. { return yytext[0]; }
+<<EOF>> { if (ieof()) yyterminate(); }
+
+%%
+
+/* C-comment ignoring routine -kre*/
+static void
+ccomment(void)
+{
+ int c = 0;
+
+ /* log(L_NOTICE, "got comment"); */
+ while (1)
+ {
+ while ((c = input()) != '*' && c != EOF)
+ if (c == '\n')
+ ++lineno;
+
+ if (c == '*')
+ {
+ while ((c = input()) == '*')
+ /* Nothing */ ;
+ if (c == '/')
+ break;
+ else if (c == '\n')
+ ++lineno;
+ }
+
+ if (c == EOF)
+ {
+ YY_FATAL_ERROR("EOF in comment");
+ /* XXX hack alert this disables
+ * the stupid unused function warning
+ * gcc generates
+ */
+ if (1 == 0)
+ yy_fatal_error("EOF in comment");
+ break;
+ }
+ }
+}
+
+/* C-style .includes. This function will properly swap input conf buffers,
+ * and lineno -kre */
+static void
+cinclude(void)
+{
+ char *p = NULL;
+
+ if ((p = strchr(yytext, '<')) == NULL)
+ *strchr(p = strchr(yytext, '"') + 1, '"') = '\0';
+ else
+ *strchr(++p, '>') = '\0';
+
+ /* log(L_NOTICE, "got include %s!", c); */
+
+ /* do stacking and co. */
+ if (include_stack_ptr >= MAX_INCLUDE_DEPTH)
+ ilog(LOG_TYPE_IRCD, "Includes nested too deep in %s", p);
+ else
+ {
+ FILE *tmp_fbfile_in = NULL;
+ char filenamebuf[IRCD_BUFSIZE];
+
+ if (*p == '/') /* if it is an absolute path */
+ snprintf(filenamebuf, sizeof(filenamebuf), "%s", p);
+ else
+ snprintf(filenamebuf, sizeof(filenamebuf), "%s/%s", ETCPATH, p);
+
+ tmp_fbfile_in = fopen(filenamebuf, "r");
+
+ if (tmp_fbfile_in == NULL)
+ {
+ ilog(LOG_TYPE_IRCD, "Unable to read configuration file '%s': %s",
+ filenamebuf, strerror(errno));
+ return;
+ }
+
+ lineno_stack[include_stack_ptr] = lineno;
+ lineno = 1;
+ inc_fbfile_in[include_stack_ptr] = conf_parser_ctx.conf_file;
+ strlcpy(conffile_stack[include_stack_ptr], conffilebuf, IRCD_BUFSIZE);
+ include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER;
+ conf_parser_ctx.conf_file = tmp_fbfile_in;
+ snprintf(conffilebuf, sizeof(conffilebuf), "%s", filenamebuf);
+ yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+ }
+}
+
+/* This is function that will be called on EOF in conf file. It will
+ * apropriately close conf if it not main conf and swap input buffers -kre
+ * */
+static int
+ieof(void)
+{
+ /* log(L_NOTICE, "return from include stack!"); */
+ if (include_stack_ptr)
+ fclose(conf_parser_ctx.conf_file);
+ if (--include_stack_ptr < 0)
+ {
+ /* log(L_NOTICE, "terminating lexer"); */
+ /* 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 */
+ /* log(L_NOTICE, "deleting include_stack_ptr=%d", include_stack_ptr); */
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ lineno = lineno_stack[include_stack_ptr];
+ conf_parser_ctx.conf_file = inc_fbfile_in[include_stack_ptr];
+ strlcpy(conffilebuf, conffile_stack[include_stack_ptr], sizeof(conffilebuf));
+ yy_switch_to_buffer(include_stack[include_stack_ptr]);
+
+ return 0;
+}
diff --git a/src/conf_parser.c b/src/conf_parser.c
new file mode 100644
index 0000000..294935c
--- /dev/null
+++ b/src/conf_parser.c
@@ -0,0 +1,7071 @@
+/* A Bison parser, made by GNU Bison 2.6.2. */
+
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.6.2"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+
+
+
+/* Copy the first part of user declarations. */
+/* Line 336 of yacc.c */
+#line 25 "conf_parser.y"
+
+
+#define YY_NO_UNPUT
+#include <sys/types.h>
+#include <string.h>
+
+#include "config.h"
+#include "stdinc.h"
+#include "ircd.h"
+#include "list.h"
+#include "conf.h"
+#include "event.h"
+#include "log.h"
+#include "client.h" /* for UMODE_ALL only */
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "memory.h"
+#include "modules.h"
+#include "s_serv.h"
+#include "hostmask.h"
+#include "send.h"
+#include "listener.h"
+#include "resv.h"
+#include "numeric.h"
+#include "s_user.h"
+
+#ifdef HAVE_LIBCRYPTO
+#include <openssl/rsa.h>
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+#include <openssl/dh.h>
+#endif
+
+int yylex(void);
+
+static char *class_name = NULL;
+static struct ConfItem *yy_conf = NULL;
+static struct AccessItem *yy_aconf = NULL;
+static struct MatchItem *yy_match_item = NULL;
+static struct ClassItem *yy_class = NULL;
+static char *yy_class_name = NULL;
+
+static dlink_list col_conf_list = { NULL, NULL, 0 };
+static unsigned int listener_flags = 0;
+static unsigned int regex_ban = 0;
+static char userbuf[IRCD_BUFSIZE];
+static char hostbuf[IRCD_BUFSIZE];
+static char reasonbuf[REASONLEN + 1];
+static char gecos_name[REALLEN * 4];
+static char lfile[IRCD_BUFSIZE];
+static unsigned int ltype = 0;
+static unsigned int lsize = 0;
+static char *resv_reason = NULL;
+static char *listener_address = NULL;
+
+struct CollectItem
+{
+ dlink_node node;
+ char *name;
+ char *user;
+ char *host;
+ char *passwd;
+ int port;
+ int flags;
+#ifdef HAVE_LIBCRYPTO
+ char *rsa_public_key_file;
+ RSA *rsa_public_key;
+#endif
+};
+
+static void
+free_collect_item(struct CollectItem *item)
+{
+ MyFree(item->name);
+ MyFree(item->user);
+ MyFree(item->host);
+ MyFree(item->passwd);
+#ifdef HAVE_LIBCRYPTO
+ MyFree(item->rsa_public_key_file);
+#endif
+ MyFree(item);
+}
+
+
+/* Line 336 of yacc.c */
+#line 153 "conf_parser.c"
+
+# ifndef YY_NULL
+# if defined __cplusplus && 201103L <= __cplusplus
+# define YY_NULL nullptr
+# else
+# define YY_NULL 0
+# endif
+# endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* In a future release of Bison, this section will be replaced
+ by #include "y.tab.h". */
+#ifndef YY_Y_TAB_H
+# define YY_Y_TAB_H
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ ACCEPT_PASSWORD = 258,
+ ADMIN = 259,
+ AFTYPE = 260,
+ ANTI_NICK_FLOOD = 261,
+ ANTI_SPAM_EXIT_MESSAGE_TIME = 262,
+ AUTOCONN = 263,
+ BYTES = 264,
+ KBYTES = 265,
+ MBYTES = 266,
+ CALLER_ID_WAIT = 267,
+ CAN_FLOOD = 268,
+ CHANNEL = 269,
+ CIDR_BITLEN_IPV4 = 270,
+ CIDR_BITLEN_IPV6 = 271,
+ CLASS = 272,
+ CONNECT = 273,
+ CONNECTFREQ = 274,
+ DEFAULT_FLOODCOUNT = 275,
+ DEFAULT_SPLIT_SERVER_COUNT = 276,
+ DEFAULT_SPLIT_USER_COUNT = 277,
+ DENY = 278,
+ DESCRIPTION = 279,
+ DIE = 280,
+ DISABLE_AUTH = 281,
+ DISABLE_FAKE_CHANNELS = 282,
+ DISABLE_REMOTE_COMMANDS = 283,
+ DOTS_IN_IDENT = 284,
+ EGDPOOL_PATH = 285,
+ EMAIL = 286,
+ ENCRYPTED = 287,
+ EXCEED_LIMIT = 288,
+ EXEMPT = 289,
+ FAILED_OPER_NOTICE = 290,
+ IRCD_FLAGS = 291,
+ FLATTEN_LINKS = 292,
+ GECOS = 293,
+ GENERAL = 294,
+ GLINE = 295,
+ GLINE_DURATION = 296,
+ GLINE_ENABLE = 297,
+ GLINE_EXEMPT = 298,
+ GLINE_REQUEST_DURATION = 299,
+ GLINE_MIN_CIDR = 300,
+ GLINE_MIN_CIDR6 = 301,
+ GLOBAL_KILL = 302,
+ IRCD_AUTH = 303,
+ NEED_IDENT = 304,
+ HAVENT_READ_CONF = 305,
+ HIDDEN = 306,
+ HIDDEN_NAME = 307,
+ HIDE_SERVER_IPS = 308,
+ HIDE_SERVERS = 309,
+ HIDE_SPOOF_IPS = 310,
+ HOST = 311,
+ HUB = 312,
+ HUB_MASK = 313,
+ IGNORE_BOGUS_TS = 314,
+ INVISIBLE_ON_CONNECT = 315,
+ IP = 316,
+ KILL = 317,
+ KILL_CHASE_TIME_LIMIT = 318,
+ KLINE = 319,
+ KLINE_EXEMPT = 320,
+ KNOCK_DELAY = 321,
+ KNOCK_DELAY_CHANNEL = 322,
+ LEAF_MASK = 323,
+ LINKS_DELAY = 324,
+ LISTEN = 325,
+ T_LOG = 326,
+ MAX_ACCEPT = 327,
+ MAX_BANS = 328,
+ MAX_CHANS_PER_OPER = 329,
+ MAX_CHANS_PER_USER = 330,
+ MAX_GLOBAL = 331,
+ MAX_IDENT = 332,
+ MAX_LOCAL = 333,
+ MAX_NICK_CHANGES = 334,
+ MAX_NICK_TIME = 335,
+ MAX_NUMBER = 336,
+ MAX_TARGETS = 337,
+ MAX_WATCH = 338,
+ MESSAGE_LOCALE = 339,
+ MIN_NONWILDCARD = 340,
+ MIN_NONWILDCARD_SIMPLE = 341,
+ MODULE = 342,
+ MODULES = 343,
+ NAME = 344,
+ NEED_PASSWORD = 345,
+ NETWORK_DESC = 346,
+ NETWORK_NAME = 347,
+ NICK = 348,
+ NICK_CHANGES = 349,
+ NO_CREATE_ON_SPLIT = 350,
+ NO_JOIN_ON_SPLIT = 351,
+ NO_OPER_FLOOD = 352,
+ NO_TILDE = 353,
+ NUMBER = 354,
+ NUMBER_PER_CIDR = 355,
+ NUMBER_PER_IP = 356,
+ OPERATOR = 357,
+ OPERS_BYPASS_CALLERID = 358,
+ OPER_ONLY_UMODES = 359,
+ OPER_PASS_RESV = 360,
+ OPER_SPY_T = 361,
+ OPER_UMODES = 362,
+ JOIN_FLOOD_COUNT = 363,
+ JOIN_FLOOD_TIME = 364,
+ PACE_WAIT = 365,
+ PACE_WAIT_SIMPLE = 366,
+ PASSWORD = 367,
+ PATH = 368,
+ PING_COOKIE = 369,
+ PING_TIME = 370,
+ PING_WARNING = 371,
+ PORT = 372,
+ QSTRING = 373,
+ QUIET_ON_BAN = 374,
+ REASON = 375,
+ REDIRPORT = 376,
+ REDIRSERV = 377,
+ REGEX_T = 378,
+ REHASH = 379,
+ REMOTE = 380,
+ REMOTEBAN = 381,
+ RESTRICT_CHANNELS = 382,
+ RSA_PRIVATE_KEY_FILE = 383,
+ RSA_PUBLIC_KEY_FILE = 384,
+ SSL_CERTIFICATE_FILE = 385,
+ SSL_DH_PARAM_FILE = 386,
+ T_SSL_CLIENT_METHOD = 387,
+ T_SSL_SERVER_METHOD = 388,
+ T_SSLV3 = 389,
+ T_TLSV1 = 390,
+ RESV = 391,
+ RESV_EXEMPT = 392,
+ SECONDS = 393,
+ MINUTES = 394,
+ HOURS = 395,
+ DAYS = 396,
+ WEEKS = 397,
+ SENDQ = 398,
+ SEND_PASSWORD = 399,
+ SERVERHIDE = 400,
+ SERVERINFO = 401,
+ IRCD_SID = 402,
+ TKLINE_EXPIRE_NOTICES = 403,
+ T_SHARED = 404,
+ T_CLUSTER = 405,
+ TYPE = 406,
+ SHORT_MOTD = 407,
+ SPOOF = 408,
+ SPOOF_NOTICE = 409,
+ STATS_E_DISABLED = 410,
+ STATS_I_OPER_ONLY = 411,
+ STATS_K_OPER_ONLY = 412,
+ STATS_O_OPER_ONLY = 413,
+ STATS_P_OPER_ONLY = 414,
+ TBOOL = 415,
+ TMASKED = 416,
+ TS_MAX_DELTA = 417,
+ TS_WARN_DELTA = 418,
+ TWODOTS = 419,
+ T_ALL = 420,
+ T_BOTS = 421,
+ T_SOFTCALLERID = 422,
+ T_CALLERID = 423,
+ T_CCONN = 424,
+ T_CCONN_FULL = 425,
+ T_SSL_CIPHER_LIST = 426,
+ T_DEAF = 427,
+ T_DEBUG = 428,
+ T_DLINE = 429,
+ T_EXTERNAL = 430,
+ T_FULL = 431,
+ T_INVISIBLE = 432,
+ T_IPV4 = 433,
+ T_IPV6 = 434,
+ T_LOCOPS = 435,
+ T_MAX_CLIENTS = 436,
+ T_NCHANGE = 437,
+ T_OPERWALL = 438,
+ T_RECVQ = 439,
+ T_REJ = 440,
+ T_SERVER = 441,
+ T_SERVNOTICE = 442,
+ T_SET = 443,
+ T_SKILL = 444,
+ T_SPY = 445,
+ T_SSL = 446,
+ T_UMODES = 447,
+ T_UNAUTH = 448,
+ T_UNDLINE = 449,
+ T_UNLIMITED = 450,
+ T_UNRESV = 451,
+ T_UNXLINE = 452,
+ T_GLOBOPS = 453,
+ T_WALLOP = 454,
+ T_RESTART = 455,
+ T_SERVICE = 456,
+ T_SERVICES_NAME = 457,
+ THROTTLE_TIME = 458,
+ TRUE_NO_OPER_FLOOD = 459,
+ UNKLINE = 460,
+ USER = 461,
+ USE_EGD = 462,
+ USE_LOGGING = 463,
+ VHOST = 464,
+ VHOST6 = 465,
+ XLINE = 466,
+ WARN_NO_NLINE = 467,
+ T_SIZE = 468,
+ T_FILE = 469
+ };
+#endif
+/* Tokens. */
+#define ACCEPT_PASSWORD 258
+#define ADMIN 259
+#define AFTYPE 260
+#define ANTI_NICK_FLOOD 261
+#define ANTI_SPAM_EXIT_MESSAGE_TIME 262
+#define AUTOCONN 263
+#define BYTES 264
+#define KBYTES 265
+#define MBYTES 266
+#define CALLER_ID_WAIT 267
+#define CAN_FLOOD 268
+#define CHANNEL 269
+#define CIDR_BITLEN_IPV4 270
+#define CIDR_BITLEN_IPV6 271
+#define CLASS 272
+#define CONNECT 273
+#define CONNECTFREQ 274
+#define DEFAULT_FLOODCOUNT 275
+#define DEFAULT_SPLIT_SERVER_COUNT 276
+#define DEFAULT_SPLIT_USER_COUNT 277
+#define DENY 278
+#define DESCRIPTION 279
+#define DIE 280
+#define DISABLE_AUTH 281
+#define DISABLE_FAKE_CHANNELS 282
+#define DISABLE_REMOTE_COMMANDS 283
+#define DOTS_IN_IDENT 284
+#define EGDPOOL_PATH 285
+#define EMAIL 286
+#define ENCRYPTED 287
+#define EXCEED_LIMIT 288
+#define EXEMPT 289
+#define FAILED_OPER_NOTICE 290
+#define IRCD_FLAGS 291
+#define FLATTEN_LINKS 292
+#define GECOS 293
+#define GENERAL 294
+#define GLINE 295
+#define GLINE_DURATION 296
+#define GLINE_ENABLE 297
+#define GLINE_EXEMPT 298
+#define GLINE_REQUEST_DURATION 299
+#define GLINE_MIN_CIDR 300
+#define GLINE_MIN_CIDR6 301
+#define GLOBAL_KILL 302
+#define IRCD_AUTH 303
+#define NEED_IDENT 304
+#define HAVENT_READ_CONF 305
+#define HIDDEN 306
+#define HIDDEN_NAME 307
+#define HIDE_SERVER_IPS 308
+#define HIDE_SERVERS 309
+#define HIDE_SPOOF_IPS 310
+#define HOST 311
+#define HUB 312
+#define HUB_MASK 313
+#define IGNORE_BOGUS_TS 314
+#define INVISIBLE_ON_CONNECT 315
+#define IP 316
+#define KILL 317
+#define KILL_CHASE_TIME_LIMIT 318
+#define KLINE 319
+#define KLINE_EXEMPT 320
+#define KNOCK_DELAY 321
+#define KNOCK_DELAY_CHANNEL 322
+#define LEAF_MASK 323
+#define LINKS_DELAY 324
+#define LISTEN 325
+#define T_LOG 326
+#define MAX_ACCEPT 327
+#define MAX_BANS 328
+#define MAX_CHANS_PER_OPER 329
+#define MAX_CHANS_PER_USER 330
+#define MAX_GLOBAL 331
+#define MAX_IDENT 332
+#define MAX_LOCAL 333
+#define MAX_NICK_CHANGES 334
+#define MAX_NICK_TIME 335
+#define MAX_NUMBER 336
+#define MAX_TARGETS 337
+#define MAX_WATCH 338
+#define MESSAGE_LOCALE 339
+#define MIN_NONWILDCARD 340
+#define MIN_NONWILDCARD_SIMPLE 341
+#define MODULE 342
+#define MODULES 343
+#define NAME 344
+#define NEED_PASSWORD 345
+#define NETWORK_DESC 346
+#define NETWORK_NAME 347
+#define NICK 348
+#define NICK_CHANGES 349
+#define NO_CREATE_ON_SPLIT 350
+#define NO_JOIN_ON_SPLIT 351
+#define NO_OPER_FLOOD 352
+#define NO_TILDE 353
+#define NUMBER 354
+#define NUMBER_PER_CIDR 355
+#define NUMBER_PER_IP 356
+#define OPERATOR 357
+#define OPERS_BYPASS_CALLERID 358
+#define OPER_ONLY_UMODES 359
+#define OPER_PASS_RESV 360
+#define OPER_SPY_T 361
+#define OPER_UMODES 362
+#define JOIN_FLOOD_COUNT 363
+#define JOIN_FLOOD_TIME 364
+#define PACE_WAIT 365
+#define PACE_WAIT_SIMPLE 366
+#define PASSWORD 367
+#define PATH 368
+#define PING_COOKIE 369
+#define PING_TIME 370
+#define PING_WARNING 371
+#define PORT 372
+#define QSTRING 373
+#define QUIET_ON_BAN 374
+#define REASON 375
+#define REDIRPORT 376
+#define REDIRSERV 377
+#define REGEX_T 378
+#define REHASH 379
+#define REMOTE 380
+#define REMOTEBAN 381
+#define RESTRICT_CHANNELS 382
+#define RSA_PRIVATE_KEY_FILE 383
+#define RSA_PUBLIC_KEY_FILE 384
+#define SSL_CERTIFICATE_FILE 385
+#define SSL_DH_PARAM_FILE 386
+#define T_SSL_CLIENT_METHOD 387
+#define T_SSL_SERVER_METHOD 388
+#define T_SSLV3 389
+#define T_TLSV1 390
+#define RESV 391
+#define RESV_EXEMPT 392
+#define SECONDS 393
+#define MINUTES 394
+#define HOURS 395
+#define DAYS 396
+#define WEEKS 397
+#define SENDQ 398
+#define SEND_PASSWORD 399
+#define SERVERHIDE 400
+#define SERVERINFO 401
+#define IRCD_SID 402
+#define TKLINE_EXPIRE_NOTICES 403
+#define T_SHARED 404
+#define T_CLUSTER 405
+#define TYPE 406
+#define SHORT_MOTD 407
+#define SPOOF 408
+#define SPOOF_NOTICE 409
+#define STATS_E_DISABLED 410
+#define STATS_I_OPER_ONLY 411
+#define STATS_K_OPER_ONLY 412
+#define STATS_O_OPER_ONLY 413
+#define STATS_P_OPER_ONLY 414
+#define TBOOL 415
+#define TMASKED 416
+#define TS_MAX_DELTA 417
+#define TS_WARN_DELTA 418
+#define TWODOTS 419
+#define T_ALL 420
+#define T_BOTS 421
+#define T_SOFTCALLERID 422
+#define T_CALLERID 423
+#define T_CCONN 424
+#define T_CCONN_FULL 425
+#define T_SSL_CIPHER_LIST 426
+#define T_DEAF 427
+#define T_DEBUG 428
+#define T_DLINE 429
+#define T_EXTERNAL 430
+#define T_FULL 431
+#define T_INVISIBLE 432
+#define T_IPV4 433
+#define T_IPV6 434
+#define T_LOCOPS 435
+#define T_MAX_CLIENTS 436
+#define T_NCHANGE 437
+#define T_OPERWALL 438
+#define T_RECVQ 439
+#define T_REJ 440
+#define T_SERVER 441
+#define T_SERVNOTICE 442
+#define T_SET 443
+#define T_SKILL 444
+#define T_SPY 445
+#define T_SSL 446
+#define T_UMODES 447
+#define T_UNAUTH 448
+#define T_UNDLINE 449
+#define T_UNLIMITED 450
+#define T_UNRESV 451
+#define T_UNXLINE 452
+#define T_GLOBOPS 453
+#define T_WALLOP 454
+#define T_RESTART 455
+#define T_SERVICE 456
+#define T_SERVICES_NAME 457
+#define THROTTLE_TIME 458
+#define TRUE_NO_OPER_FLOOD 459
+#define UNKLINE 460
+#define USER 461
+#define USE_EGD 462
+#define USE_LOGGING 463
+#define VHOST 464
+#define VHOST6 465
+#define XLINE 466
+#define WARN_NO_NLINE 467
+#define T_SIZE 468
+#define T_FILE 469
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+/* Line 350 of yacc.c */
+#line 110 "conf_parser.y"
+
+ int number;
+ char *string;
+
+
+/* Line 350 of yacc.c */
+#line 630 "conf_parser.c"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+extern YYSTYPE yylval;
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !YY_Y_TAB_H */
+
+/* Copy the second part of user declarations. */
+
+/* Line 353 of yacc.c */
+#line 658 "conf_parser.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+ int yyi;
+#endif
+{
+ return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+# else
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 2
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 1206
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 220
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 283
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 627
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 1228
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 469
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 219, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 215,
+ 2, 218, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 217, 2, 216, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
+ 115, 116, 117, 118, 119, 120, 121, 122, 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
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint16 yyprhs[] =
+{
+ 0, 0, 3, 4, 7, 9, 11, 13, 15, 17,
+ 19, 21, 23, 25, 27, 29, 31, 33, 35, 37,
+ 39, 41, 43, 45, 47, 50, 53, 54, 56, 59,
+ 63, 67, 71, 75, 79, 80, 82, 85, 89, 93,
+ 97, 103, 106, 108, 110, 112, 115, 120, 125, 131,
+ 134, 136, 138, 140, 142, 144, 146, 148, 150, 152,
+ 154, 156, 158, 160, 162, 164, 166, 169, 174, 179,
+ 183, 185, 187, 189, 193, 195, 197, 199, 204, 209,
+ 214, 219, 224, 229, 234, 239, 244, 249, 254, 259,
+ 264, 270, 273, 275, 277, 279, 281, 284, 289, 294,
+ 299, 305, 308, 310, 312, 314, 317, 322, 323, 330,
+ 333, 335, 337, 339, 341, 344, 349, 354, 359, 360,
+ 366, 370, 372, 374, 376, 378, 380, 382, 384, 386,
+ 387, 394, 397, 399, 401, 403, 405, 407, 409, 411,
+ 413, 415, 418, 423, 428, 433, 438, 443, 448, 449,
+ 455, 459, 461, 463, 465, 467, 469, 471, 473, 475,
+ 477, 479, 481, 483, 485, 487, 489, 491, 493, 495,
+ 497, 499, 501, 502, 508, 512, 514, 516, 518, 520,
+ 522, 524, 526, 528, 530, 532, 534, 536, 538, 540,
+ 542, 544, 546, 548, 550, 552, 553, 560, 563, 565,
+ 567, 569, 571, 573, 575, 577, 579, 581, 583, 585,
+ 587, 589, 591, 593, 596, 601, 606, 611, 616, 621,
+ 626, 631, 636, 641, 646, 651, 656, 661, 666, 667,
+ 674, 675, 681, 685, 687, 689, 691, 693, 696, 698,
+ 700, 702, 704, 706, 709, 710, 716, 720, 722, 724,
+ 728, 733, 738, 739, 746, 749, 751, 753, 755, 757,
+ 759, 761, 763, 765, 767, 770, 775, 780, 785, 790,
+ 791, 797, 801, 803, 805, 807, 809, 811, 813, 815,
+ 817, 819, 821, 826, 831, 836, 837, 844, 847, 849,
+ 851, 853, 855, 858, 863, 868, 873, 879, 882, 884,
+ 886, 888, 893, 894, 901, 904, 906, 908, 910, 912,
+ 915, 920, 925, 926, 932, 936, 938, 940, 942, 944,
+ 946, 948, 950, 952, 954, 956, 958, 959, 966, 969,
+ 971, 973, 975, 978, 983, 984, 990, 994, 996, 998,
+ 1000, 1002, 1004, 1006, 1008, 1010, 1012, 1014, 1016, 1017,
+ 1024, 1027, 1029, 1031, 1033, 1035, 1037, 1039, 1041, 1043,
+ 1045, 1047, 1049, 1051, 1053, 1055, 1058, 1063, 1068, 1073,
+ 1078, 1083, 1088, 1093, 1098, 1099, 1105, 1109, 1111, 1113,
+ 1115, 1120, 1125, 1130, 1135, 1140, 1141, 1148, 1149, 1155,
+ 1159, 1161, 1163, 1166, 1168, 1170, 1172, 1174, 1176, 1181,
+ 1186, 1187, 1194, 1197, 1199, 1201, 1203, 1205, 1210, 1215,
+ 1221, 1224, 1226, 1228, 1230, 1235, 1236, 1243, 1244, 1250,
+ 1254, 1256, 1258, 1261, 1263, 1265, 1267, 1269, 1271, 1276,
+ 1281, 1287, 1290, 1292, 1294, 1296, 1298, 1300, 1302, 1304,
+ 1306, 1308, 1310, 1312, 1314, 1316, 1318, 1320, 1322, 1324,
+ 1326, 1328, 1330, 1332, 1334, 1336, 1338, 1340, 1342, 1344,
+ 1346, 1348, 1350, 1352, 1354, 1356, 1358, 1360, 1362, 1364,
+ 1366, 1368, 1370, 1372, 1374, 1376, 1378, 1380, 1382, 1384,
+ 1386, 1388, 1390, 1392, 1397, 1402, 1407, 1412, 1417, 1422,
+ 1427, 1432, 1437, 1442, 1447, 1452, 1457, 1462, 1467, 1472,
+ 1477, 1482, 1487, 1492, 1497, 1502, 1507, 1512, 1517, 1522,
+ 1527, 1532, 1537, 1542, 1547, 1552, 1557, 1562, 1567, 1572,
+ 1577, 1582, 1587, 1592, 1597, 1602, 1607, 1612, 1617, 1622,
+ 1623, 1629, 1633, 1635, 1637, 1639, 1641, 1643, 1645, 1647,
+ 1649, 1651, 1653, 1655, 1657, 1659, 1661, 1663, 1665, 1667,
+ 1669, 1671, 1673, 1675, 1676, 1682, 1686, 1688, 1690, 1692,
+ 1694, 1696, 1698, 1700, 1702, 1704, 1706, 1708, 1710, 1712,
+ 1714, 1716, 1718, 1720, 1722, 1724, 1726, 1728, 1733, 1738,
+ 1743, 1749, 1752, 1754, 1756, 1758, 1760, 1762, 1764, 1766,
+ 1768, 1770, 1772, 1774, 1776, 1778, 1780, 1782, 1784, 1789,
+ 1794, 1799, 1804, 1809, 1814, 1819, 1824, 1829, 1834, 1839,
+ 1844, 1849, 1854, 1860, 1863, 1865, 1867, 1869, 1871, 1873,
+ 1875, 1877, 1879, 1884, 1889, 1894, 1899, 1904
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int16 yyrhs[] =
+{
+ 221, 0, -1, -1, 221, 222, -1, 254, -1, 260,
+ -1, 274, -1, 477, -1, 292, -1, 310, -1, 324,
+ -1, 232, -1, 494, -1, 339, -1, 346, -1, 350,
+ -1, 360, -1, 369, -1, 389, -1, 399, -1, 405,
+ -1, 419, -1, 409, -1, 227, -1, 1, 215, -1,
+ 1, 216, -1, -1, 224, -1, 99, 223, -1, 99,
+ 138, 223, -1, 99, 139, 223, -1, 99, 140, 223,
+ -1, 99, 141, 223, -1, 99, 142, 223, -1, -1,
+ 226, -1, 99, 225, -1, 99, 9, 225, -1, 99,
+ 10, 225, -1, 99, 11, 225, -1, 88, 217, 228,
+ 216, 215, -1, 228, 229, -1, 229, -1, 230, -1,
+ 231, -1, 1, 215, -1, 87, 218, 118, 215, -1,
+ 113, 218, 118, 215, -1, 146, 217, 233, 216, 215,
+ -1, 233, 234, -1, 234, -1, 245, -1, 250, -1,
+ 253, -1, 247, -1, 248, -1, 249, -1, 252, -1,
+ 243, -1, 242, -1, 251, -1, 246, -1, 241, -1,
+ 235, -1, 236, -1, 244, -1, 1, 215, -1, 132,
+ 218, 237, 215, -1, 133, 218, 239, 215, -1, 237,
+ 219, 238, -1, 238, -1, 134, -1, 135, -1, 239,
+ 219, 240, -1, 240, -1, 134, -1, 135, -1, 130,
+ 218, 118, 215, -1, 128, 218, 118, 215, -1, 131,
+ 218, 118, 215, -1, 171, 218, 118, 215, -1, 89,
+ 218, 118, 215, -1, 147, 218, 118, 215, -1, 24,
+ 218, 118, 215, -1, 92, 218, 118, 215, -1, 91,
+ 218, 118, 215, -1, 209, 218, 118, 215, -1, 210,
+ 218, 118, 215, -1, 181, 218, 99, 215, -1, 57,
+ 218, 160, 215, -1, 4, 217, 255, 216, 215, -1,
+ 255, 256, -1, 256, -1, 257, -1, 259, -1, 258,
+ -1, 1, 215, -1, 89, 218, 118, 215, -1, 31,
+ 218, 118, 215, -1, 24, 218, 118, 215, -1, 71,
+ 217, 261, 216, 215, -1, 261, 262, -1, 262, -1,
+ 263, -1, 264, -1, 1, 215, -1, 208, 218, 160,
+ 215, -1, -1, 265, 214, 217, 266, 216, 215, -1,
+ 266, 267, -1, 267, -1, 268, -1, 270, -1, 269,
+ -1, 1, 215, -1, 89, 218, 118, 215, -1, 213,
+ 218, 226, 215, -1, 213, 218, 195, 215, -1, -1,
+ 151, 271, 218, 272, 215, -1, 272, 219, 273, -1,
+ 273, -1, 206, -1, 102, -1, 40, -1, 174, -1,
+ 64, -1, 62, -1, 173, -1, -1, 102, 275, 217,
+ 276, 216, 215, -1, 276, 277, -1, 277, -1, 278,
+ -1, 279, -1, 280, -1, 284, -1, 283, -1, 281,
+ -1, 282, -1, 288, -1, 1, 215, -1, 89, 218,
+ 118, 215, -1, 206, 218, 118, 215, -1, 112, 218,
+ 118, 215, -1, 32, 218, 160, 215, -1, 129, 218,
+ 118, 215, -1, 17, 218, 118, 215, -1, -1, 192,
+ 285, 218, 286, 215, -1, 286, 219, 287, -1, 287,
+ -1, 166, -1, 169, -1, 170, -1, 172, -1, 173,
+ -1, 176, -1, 51, -1, 189, -1, 182, -1, 185,
+ -1, 193, -1, 190, -1, 175, -1, 183, -1, 187,
+ -1, 177, -1, 199, -1, 167, -1, 168, -1, 180,
+ -1, -1, 36, 289, 218, 290, 215, -1, 290, 219,
+ 291, -1, 291, -1, 47, -1, 125, -1, 64, -1,
+ 205, -1, 174, -1, 194, -1, 211, -1, 40, -1,
+ 25, -1, 200, -1, 124, -1, 4, -1, 94, -1,
+ 183, -1, 198, -1, 106, -1, 126, -1, 188, -1,
+ 87, -1, -1, 17, 293, 217, 294, 216, 215, -1,
+ 294, 295, -1, 295, -1, 296, -1, 307, -1, 308,
+ -1, 297, -1, 298, -1, 309, -1, 299, -1, 300,
+ -1, 301, -1, 302, -1, 303, -1, 304, -1, 305,
+ -1, 306, -1, 1, 215, -1, 89, 218, 118, 215,
+ -1, 115, 218, 224, 215, -1, 116, 218, 224, 215,
+ -1, 101, 218, 99, 215, -1, 19, 218, 224, 215,
+ -1, 81, 218, 99, 215, -1, 76, 218, 99, 215,
+ -1, 78, 218, 99, 215, -1, 77, 218, 99, 215,
+ -1, 143, 218, 226, 215, -1, 184, 218, 226, 215,
+ -1, 15, 218, 99, 215, -1, 16, 218, 99, 215,
+ -1, 100, 218, 99, 215, -1, -1, 70, 311, 217,
+ 316, 216, 215, -1, -1, 36, 313, 218, 314, 215,
+ -1, 314, 219, 315, -1, 315, -1, 191, -1, 51,
+ -1, 186, -1, 316, 317, -1, 317, -1, 318, -1,
+ 312, -1, 322, -1, 323, -1, 1, 215, -1, -1,
+ 117, 218, 320, 319, 215, -1, 320, 219, 321, -1,
+ 321, -1, 99, -1, 99, 164, 99, -1, 61, 218,
+ 118, 215, -1, 56, 218, 118, 215, -1, -1, 48,
+ 325, 217, 326, 216, 215, -1, 326, 327, -1, 327,
+ -1, 328, -1, 329, -1, 330, -1, 332, -1, 336,
+ -1, 337, -1, 338, -1, 331, -1, 1, 215, -1,
+ 206, 218, 118, 215, -1, 112, 218, 118, 215, -1,
+ 17, 218, 118, 215, -1, 32, 218, 160, 215, -1,
+ -1, 36, 333, 218, 334, 215, -1, 334, 219, 335,
+ -1, 335, -1, 154, -1, 33, -1, 65, -1, 49,
+ -1, 13, -1, 98, -1, 43, -1, 137, -1, 90,
+ -1, 153, 218, 118, 215, -1, 122, 218, 118, 215,
+ -1, 121, 218, 99, 215, -1, -1, 136, 340, 217,
+ 341, 216, 215, -1, 341, 342, -1, 342, -1, 343,
+ -1, 344, -1, 345, -1, 1, 215, -1, 120, 218,
+ 118, 215, -1, 14, 218, 118, 215, -1, 93, 218,
+ 118, 215, -1, 201, 217, 347, 216, 215, -1, 347,
+ 348, -1, 348, -1, 349, -1, 1, -1, 89, 218,
+ 118, 215, -1, -1, 149, 351, 217, 352, 216, 215,
+ -1, 352, 353, -1, 353, -1, 354, -1, 355, -1,
+ 356, -1, 1, 215, -1, 89, 218, 118, 215, -1,
+ 206, 218, 118, 215, -1, -1, 151, 357, 218, 358,
+ 215, -1, 358, 219, 359, -1, 359, -1, 64, -1,
+ 205, -1, 174, -1, 194, -1, 211, -1, 197, -1,
+ 136, -1, 196, -1, 180, -1, 165, -1, -1, 150,
+ 361, 217, 362, 216, 215, -1, 362, 363, -1, 363,
+ -1, 364, -1, 365, -1, 1, 215, -1, 89, 218,
+ 118, 215, -1, -1, 151, 366, 218, 367, 215, -1,
+ 367, 219, 368, -1, 368, -1, 64, -1, 205, -1,
+ 174, -1, 194, -1, 211, -1, 197, -1, 136, -1,
+ 196, -1, 180, -1, 165, -1, -1, 18, 370, 217,
+ 371, 216, 215, -1, 371, 372, -1, 372, -1, 373,
+ -1, 374, -1, 375, -1, 376, -1, 377, -1, 379,
+ -1, 378, -1, 388, -1, 380, -1, 385, -1, 386,
+ -1, 387, -1, 384, -1, 1, 215, -1, 89, 218,
+ 118, 215, -1, 56, 218, 118, 215, -1, 209, 218,
+ 118, 215, -1, 144, 218, 118, 215, -1, 3, 218,
+ 118, 215, -1, 117, 218, 99, 215, -1, 5, 218,
+ 178, 215, -1, 5, 218, 179, 215, -1, -1, 36,
+ 381, 218, 382, 215, -1, 382, 219, 383, -1, 383,
+ -1, 8, -1, 191, -1, 32, 218, 160, 215, -1,
+ 58, 218, 118, 215, -1, 68, 218, 118, 215, -1,
+ 17, 218, 118, 215, -1, 171, 218, 118, 215, -1,
+ -1, 62, 390, 217, 395, 216, 215, -1, -1, 151,
+ 392, 218, 393, 215, -1, 393, 219, 394, -1, 394,
+ -1, 123, -1, 395, 396, -1, 396, -1, 397, -1,
+ 398, -1, 391, -1, 1, -1, 206, 218, 118, 215,
+ -1, 120, 218, 118, 215, -1, -1, 23, 400, 217,
+ 401, 216, 215, -1, 401, 402, -1, 402, -1, 403,
+ -1, 404, -1, 1, -1, 61, 218, 118, 215, -1,
+ 120, 218, 118, 215, -1, 34, 217, 406, 216, 215,
+ -1, 406, 407, -1, 407, -1, 408, -1, 1, -1,
+ 61, 218, 118, 215, -1, -1, 38, 410, 217, 415,
+ 216, 215, -1, -1, 151, 412, 218, 413, 215, -1,
+ 413, 219, 414, -1, 414, -1, 123, -1, 415, 416,
+ -1, 416, -1, 417, -1, 418, -1, 411, -1, 1,
+ -1, 89, 218, 118, 215, -1, 120, 218, 118, 215,
+ -1, 39, 217, 420, 216, 215, -1, 420, 421, -1,
+ 421, -1, 430, -1, 431, -1, 433, -1, 434, -1,
+ 435, -1, 436, -1, 437, -1, 438, -1, 439, -1,
+ 440, -1, 429, -1, 442, -1, 443, -1, 458, -1,
+ 445, -1, 447, -1, 449, -1, 448, -1, 452, -1,
+ 446, -1, 453, -1, 454, -1, 455, -1, 456, -1,
+ 457, -1, 470, -1, 459, -1, 460, -1, 461, -1,
+ 466, -1, 450, -1, 451, -1, 476, -1, 474, -1,
+ 475, -1, 432, -1, 465, -1, 441, -1, 463, -1,
+ 464, -1, 428, -1, 423, -1, 424, -1, 425, -1,
+ 426, -1, 427, -1, 444, -1, 422, -1, 462, -1,
+ 1, -1, 83, 218, 99, 215, -1, 42, 218, 160,
+ 215, -1, 41, 218, 224, 215, -1, 44, 218, 224,
+ 215, -1, 45, 218, 99, 215, -1, 46, 218, 99,
+ 215, -1, 148, 218, 160, 215, -1, 63, 218, 224,
+ 215, -1, 55, 218, 160, 215, -1, 59, 218, 160,
+ 215, -1, 28, 218, 160, 215, -1, 35, 218, 160,
+ 215, -1, 6, 218, 160, 215, -1, 80, 218, 224,
+ 215, -1, 79, 218, 99, 215, -1, 72, 218, 99,
+ 215, -1, 7, 218, 224, 215, -1, 163, 218, 224,
+ 215, -1, 162, 218, 224, 215, -1, 50, 218, 99,
+ 215, -1, 60, 218, 160, 215, -1, 212, 218, 160,
+ 215, -1, 155, 218, 160, 215, -1, 158, 218, 160,
+ 215, -1, 159, 218, 160, 215, -1, 157, 218, 160,
+ 215, -1, 157, 218, 161, 215, -1, 156, 218, 160,
+ 215, -1, 156, 218, 161, 215, -1, 110, 218, 224,
+ 215, -1, 12, 218, 224, 215, -1, 103, 218, 160,
+ 215, -1, 111, 218, 224, 215, -1, 152, 218, 160,
+ 215, -1, 97, 218, 160, 215, -1, 204, 218, 160,
+ 215, -1, 105, 218, 160, 215, -1, 84, 218, 118,
+ 215, -1, 29, 218, 99, 215, -1, 82, 218, 99,
+ 215, -1, 207, 218, 160, 215, -1, 30, 218, 118,
+ 215, -1, 202, 218, 118, 215, -1, 114, 218, 160,
+ 215, -1, 26, 218, 160, 215, -1, 203, 218, 224,
+ 215, -1, -1, 107, 467, 218, 468, 215, -1, 468,
+ 219, 469, -1, 469, -1, 166, -1, 169, -1, 170,
+ -1, 172, -1, 173, -1, 176, -1, 51, -1, 189,
+ -1, 182, -1, 185, -1, 193, -1, 190, -1, 175,
+ -1, 183, -1, 187, -1, 177, -1, 199, -1, 167,
+ -1, 168, -1, 180, -1, -1, 104, 471, 218, 472,
+ 215, -1, 472, 219, 473, -1, 473, -1, 166, -1,
+ 169, -1, 170, -1, 172, -1, 173, -1, 176, -1,
+ 189, -1, 51, -1, 182, -1, 185, -1, 193, -1,
+ 190, -1, 175, -1, 183, -1, 187, -1, 177, -1,
+ 199, -1, 167, -1, 168, -1, 180, -1, 85, 218,
+ 99, 215, -1, 86, 218, 99, 215, -1, 20, 218,
+ 99, 215, -1, 14, 217, 478, 216, 215, -1, 478,
+ 479, -1, 479, -1, 487, -1, 482, -1, 483, -1,
+ 484, -1, 485, -1, 486, -1, 488, -1, 489, -1,
+ 490, -1, 481, -1, 491, -1, 492, -1, 493, -1,
+ 480, -1, 1, -1, 27, 218, 160, 215, -1, 127,
+ 218, 160, 215, -1, 66, 218, 224, 215, -1, 67,
+ 218, 224, 215, -1, 75, 218, 99, 215, -1, 74,
+ 218, 99, 215, -1, 119, 218, 160, 215, -1, 73,
+ 218, 99, 215, -1, 22, 218, 99, 215, -1, 21,
+ 218, 99, 215, -1, 95, 218, 160, 215, -1, 96,
+ 218, 160, 215, -1, 108, 218, 99, 215, -1, 109,
+ 218, 224, 215, -1, 145, 217, 495, 216, 215, -1,
+ 495, 496, -1, 496, -1, 497, -1, 498, -1, 500,
+ -1, 501, -1, 499, -1, 502, -1, 1, -1, 37,
+ 218, 160, 215, -1, 54, 218, 160, 215, -1, 52,
+ 218, 118, 215, -1, 69, 218, 224, 215, -1, 51,
+ 218, 160, 215, -1, 53, 218, 160, 215, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 330, 330, 331, 334, 335, 336, 337, 338, 339,
+ 340, 341, 342, 343, 344, 345, 346, 347, 348, 349,
+ 350, 351, 352, 353, 354, 355, 359, 359, 360, 364,
+ 368, 372, 376, 380, 386, 386, 387, 388, 389, 390,
+ 397, 400, 400, 401, 401, 401, 403, 409, 416, 418,
+ 418, 419, 419, 420, 420, 421, 421, 422, 422, 423,
+ 423, 424, 424, 425, 425, 426, 427, 430, 431, 433,
+ 433, 434, 440, 448, 448, 449, 455, 463, 502, 561,
+ 589, 597, 612, 627, 636, 650, 659, 687, 717, 740,
+ 749, 751, 751, 752, 752, 753, 753, 755, 764, 773,
+ 785, 786, 786, 788, 788, 789, 791, 798, 798, 808,
+ 809, 811, 811, 812, 812, 814, 819, 822, 828, 827,
+ 833, 833, 834, 838, 842, 846, 850, 854, 858, 869,
+ 868, 966, 966, 967, 967, 967, 968, 968, 968, 969,
+ 969, 969, 971, 980, 1017, 1029, 1040, 1082, 1092, 1091,
+ 1097, 1097, 1098, 1102, 1106, 1110, 1114, 1118, 1122, 1126,
+ 1130, 1134, 1138, 1142, 1146, 1150, 1154, 1158, 1162, 1166,
+ 1170, 1174, 1181, 1180, 1186, 1186, 1187, 1191, 1195, 1199,
+ 1203, 1207, 1211, 1215, 1219, 1223, 1227, 1231, 1235, 1239,
+ 1243, 1247, 1251, 1255, 1259, 1270, 1269, 1319, 1319, 1320,
+ 1321, 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329,
+ 1330, 1331, 1331, 1332, 1334, 1343, 1349, 1355, 1361, 1367,
+ 1373, 1379, 1385, 1391, 1397, 1404, 1410, 1416, 1426, 1425,
+ 1442, 1441, 1446, 1446, 1447, 1451, 1455, 1463, 1463, 1464,
+ 1464, 1464, 1464, 1464, 1466, 1466, 1468, 1468, 1470, 1484,
+ 1504, 1513, 1526, 1525, 1594, 1594, 1595, 1595, 1595, 1595,
+ 1596, 1596, 1596, 1597, 1597, 1599, 1634, 1647, 1656, 1668,
+ 1667, 1671, 1671, 1672, 1676, 1680, 1684, 1688, 1692, 1696,
+ 1700, 1704, 1710, 1729, 1739, 1753, 1752, 1768, 1768, 1769,
+ 1769, 1769, 1769, 1771, 1780, 1795, 1808, 1810, 1810, 1811,
+ 1811, 1813, 1829, 1828, 1844, 1844, 1845, 1845, 1845, 1845,
+ 1847, 1856, 1879, 1878, 1884, 1884, 1885, 1889, 1893, 1897,
+ 1901, 1905, 1909, 1913, 1917, 1921, 1931, 1930, 1947, 1947,
+ 1948, 1948, 1948, 1950, 1957, 1956, 1962, 1962, 1963, 1967,
+ 1971, 1975, 1979, 1983, 1987, 1991, 1995, 1999, 2009, 2008,
+ 2059, 2059, 2060, 2060, 2060, 2061, 2061, 2062, 2062, 2062,
+ 2063, 2063, 2063, 2064, 2064, 2065, 2067, 2076, 2085, 2111,
+ 2129, 2147, 2153, 2157, 2166, 2165, 2169, 2169, 2170, 2174,
+ 2180, 2191, 2202, 2213, 2222, 2241, 2240, 2306, 2305, 2309,
+ 2309, 2310, 2316, 2316, 2317, 2317, 2317, 2317, 2319, 2338,
+ 2348, 2347, 2372, 2372, 2373, 2373, 2373, 2375, 2381, 2390,
+ 2392, 2392, 2393, 2393, 2395, 2414, 2413, 2461, 2460, 2464,
+ 2464, 2465, 2471, 2471, 2472, 2472, 2472, 2472, 2474, 2480,
+ 2489, 2492, 2492, 2493, 2493, 2494, 2494, 2495, 2495, 2496,
+ 2496, 2497, 2497, 2498, 2499, 2500, 2500, 2501, 2501, 2502,
+ 2502, 2503, 2503, 2504, 2504, 2505, 2505, 2506, 2507, 2507,
+ 2508, 2508, 2509, 2509, 2510, 2510, 2511, 2511, 2512, 2513,
+ 2513, 2514, 2515, 2516, 2516, 2517, 2517, 2518, 2519, 2520,
+ 2521, 2521, 2522, 2525, 2530, 2536, 2542, 2548, 2553, 2558,
+ 2563, 2568, 2573, 2578, 2583, 2588, 2593, 2598, 2603, 2608,
+ 2613, 2618, 2624, 2635, 2640, 2645, 2650, 2655, 2660, 2663,
+ 2668, 2671, 2676, 2681, 2686, 2691, 2696, 2701, 2706, 2711,
+ 2716, 2727, 2732, 2737, 2742, 2751, 2760, 2765, 2770, 2776,
+ 2775, 2780, 2780, 2781, 2784, 2787, 2790, 2793, 2796, 2799,
+ 2802, 2805, 2808, 2811, 2814, 2817, 2820, 2823, 2826, 2829,
+ 2832, 2835, 2838, 2844, 2843, 2848, 2848, 2849, 2852, 2855,
+ 2858, 2861, 2864, 2867, 2870, 2873, 2876, 2879, 2882, 2885,
+ 2888, 2891, 2894, 2897, 2900, 2903, 2906, 2911, 2916, 2921,
+ 2930, 2933, 2933, 2934, 2935, 2935, 2936, 2936, 2937, 2937,
+ 2938, 2939, 2939, 2940, 2941, 2941, 2942, 2942, 2944, 2949,
+ 2954, 2959, 2964, 2969, 2974, 2979, 2984, 2989, 2994, 2999,
+ 3004, 3009, 3017, 3020, 3020, 3021, 3021, 3022, 3023, 3023,
+ 3024, 3025, 3027, 3033, 3039, 3048, 3062, 3068
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || 0
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "ACCEPT_PASSWORD", "ADMIN", "AFTYPE",
+ "ANTI_NICK_FLOOD", "ANTI_SPAM_EXIT_MESSAGE_TIME", "AUTOCONN", "BYTES",
+ "KBYTES", "MBYTES", "CALLER_ID_WAIT", "CAN_FLOOD", "CHANNEL",
+ "CIDR_BITLEN_IPV4", "CIDR_BITLEN_IPV6", "CLASS", "CONNECT",
+ "CONNECTFREQ", "DEFAULT_FLOODCOUNT", "DEFAULT_SPLIT_SERVER_COUNT",
+ "DEFAULT_SPLIT_USER_COUNT", "DENY", "DESCRIPTION", "DIE", "DISABLE_AUTH",
+ "DISABLE_FAKE_CHANNELS", "DISABLE_REMOTE_COMMANDS", "DOTS_IN_IDENT",
+ "EGDPOOL_PATH", "EMAIL", "ENCRYPTED", "EXCEED_LIMIT", "EXEMPT",
+ "FAILED_OPER_NOTICE", "IRCD_FLAGS", "FLATTEN_LINKS", "GECOS", "GENERAL",
+ "GLINE", "GLINE_DURATION", "GLINE_ENABLE", "GLINE_EXEMPT",
+ "GLINE_REQUEST_DURATION", "GLINE_MIN_CIDR", "GLINE_MIN_CIDR6",
+ "GLOBAL_KILL", "IRCD_AUTH", "NEED_IDENT", "HAVENT_READ_CONF", "HIDDEN",
+ "HIDDEN_NAME", "HIDE_SERVER_IPS", "HIDE_SERVERS", "HIDE_SPOOF_IPS",
+ "HOST", "HUB", "HUB_MASK", "IGNORE_BOGUS_TS", "INVISIBLE_ON_CONNECT",
+ "IP", "KILL", "KILL_CHASE_TIME_LIMIT", "KLINE", "KLINE_EXEMPT",
+ "KNOCK_DELAY", "KNOCK_DELAY_CHANNEL", "LEAF_MASK", "LINKS_DELAY",
+ "LISTEN", "T_LOG", "MAX_ACCEPT", "MAX_BANS", "MAX_CHANS_PER_OPER",
+ "MAX_CHANS_PER_USER", "MAX_GLOBAL", "MAX_IDENT", "MAX_LOCAL",
+ "MAX_NICK_CHANGES", "MAX_NICK_TIME", "MAX_NUMBER", "MAX_TARGETS",
+ "MAX_WATCH", "MESSAGE_LOCALE", "MIN_NONWILDCARD",
+ "MIN_NONWILDCARD_SIMPLE", "MODULE", "MODULES", "NAME", "NEED_PASSWORD",
+ "NETWORK_DESC", "NETWORK_NAME", "NICK", "NICK_CHANGES",
+ "NO_CREATE_ON_SPLIT", "NO_JOIN_ON_SPLIT", "NO_OPER_FLOOD", "NO_TILDE",
+ "NUMBER", "NUMBER_PER_CIDR", "NUMBER_PER_IP", "OPERATOR",
+ "OPERS_BYPASS_CALLERID", "OPER_ONLY_UMODES", "OPER_PASS_RESV",
+ "OPER_SPY_T", "OPER_UMODES", "JOIN_FLOOD_COUNT", "JOIN_FLOOD_TIME",
+ "PACE_WAIT", "PACE_WAIT_SIMPLE", "PASSWORD", "PATH", "PING_COOKIE",
+ "PING_TIME", "PING_WARNING", "PORT", "QSTRING", "QUIET_ON_BAN", "REASON",
+ "REDIRPORT", "REDIRSERV", "REGEX_T", "REHASH", "REMOTE", "REMOTEBAN",
+ "RESTRICT_CHANNELS", "RSA_PRIVATE_KEY_FILE", "RSA_PUBLIC_KEY_FILE",
+ "SSL_CERTIFICATE_FILE", "SSL_DH_PARAM_FILE", "T_SSL_CLIENT_METHOD",
+ "T_SSL_SERVER_METHOD", "T_SSLV3", "T_TLSV1", "RESV", "RESV_EXEMPT",
+ "SECONDS", "MINUTES", "HOURS", "DAYS", "WEEKS", "SENDQ", "SEND_PASSWORD",
+ "SERVERHIDE", "SERVERINFO", "IRCD_SID", "TKLINE_EXPIRE_NOTICES",
+ "T_SHARED", "T_CLUSTER", "TYPE", "SHORT_MOTD", "SPOOF", "SPOOF_NOTICE",
+ "STATS_E_DISABLED", "STATS_I_OPER_ONLY", "STATS_K_OPER_ONLY",
+ "STATS_O_OPER_ONLY", "STATS_P_OPER_ONLY", "TBOOL", "TMASKED",
+ "TS_MAX_DELTA", "TS_WARN_DELTA", "TWODOTS", "T_ALL", "T_BOTS",
+ "T_SOFTCALLERID", "T_CALLERID", "T_CCONN", "T_CCONN_FULL",
+ "T_SSL_CIPHER_LIST", "T_DEAF", "T_DEBUG", "T_DLINE", "T_EXTERNAL",
+ "T_FULL", "T_INVISIBLE", "T_IPV4", "T_IPV6", "T_LOCOPS", "T_MAX_CLIENTS",
+ "T_NCHANGE", "T_OPERWALL", "T_RECVQ", "T_REJ", "T_SERVER",
+ "T_SERVNOTICE", "T_SET", "T_SKILL", "T_SPY", "T_SSL", "T_UMODES",
+ "T_UNAUTH", "T_UNDLINE", "T_UNLIMITED", "T_UNRESV", "T_UNXLINE",
+ "T_GLOBOPS", "T_WALLOP", "T_RESTART", "T_SERVICE", "T_SERVICES_NAME",
+ "THROTTLE_TIME", "TRUE_NO_OPER_FLOOD", "UNKLINE", "USER", "USE_EGD",
+ "USE_LOGGING", "VHOST", "VHOST6", "XLINE", "WARN_NO_NLINE", "T_SIZE",
+ "T_FILE", "';'", "'}'", "'{'", "'='", "','", "$accept", "conf",
+ "conf_item", "timespec_", "timespec", "sizespec_", "sizespec",
+ "modules_entry", "modules_items", "modules_item", "modules_module",
+ "modules_path", "serverinfo_entry", "serverinfo_items",
+ "serverinfo_item", "serverinfo_ssl_client_method",
+ "serverinfo_ssl_server_method", "client_method_types",
+ "client_method_type_item", "server_method_types",
+ "server_method_type_item", "serverinfo_ssl_certificate_file",
+ "serverinfo_rsa_private_key_file", "serverinfo_ssl_dh_param_file",
+ "serverinfo_ssl_cipher_list", "serverinfo_name", "serverinfo_sid",
+ "serverinfo_description", "serverinfo_network_name",
+ "serverinfo_network_desc", "serverinfo_vhost", "serverinfo_vhost6",
+ "serverinfo_max_clients", "serverinfo_hub", "admin_entry", "admin_items",
+ "admin_item", "admin_name", "admin_email", "admin_description",
+ "logging_entry", "logging_items", "logging_item", "logging_use_logging",
+ "logging_file_entry", "$@1", "logging_file_items", "logging_file_item",
+ "logging_file_name", "logging_file_size", "logging_file_type", "$@2",
+ "logging_file_type_items", "logging_file_type_item", "oper_entry", "$@3",
+ "oper_items", "oper_item", "oper_name", "oper_user", "oper_password",
+ "oper_encrypted", "oper_rsa_public_key_file", "oper_class",
+ "oper_umodes", "$@4", "oper_umodes_items", "oper_umodes_item",
+ "oper_flags", "$@5", "oper_flags_items", "oper_flags_item",
+ "class_entry", "$@6", "class_items", "class_item", "class_name",
+ "class_ping_time", "class_ping_warning", "class_number_per_ip",
+ "class_connectfreq", "class_max_number", "class_max_global",
+ "class_max_local", "class_max_ident", "class_sendq", "class_recvq",
+ "class_cidr_bitlen_ipv4", "class_cidr_bitlen_ipv6",
+ "class_number_per_cidr", "listen_entry", "$@7", "listen_flags", "$@8",
+ "listen_flags_items", "listen_flags_item", "listen_items", "listen_item",
+ "listen_port", "$@9", "port_items", "port_item", "listen_address",
+ "listen_host", "auth_entry", "$@10", "auth_items", "auth_item",
+ "auth_user", "auth_passwd", "auth_class", "auth_encrypted", "auth_flags",
+ "$@11", "auth_flags_items", "auth_flags_item", "auth_spoof",
+ "auth_redir_serv", "auth_redir_port", "resv_entry", "$@12", "resv_items",
+ "resv_item", "resv_creason", "resv_channel", "resv_nick",
+ "service_entry", "service_items", "service_item", "service_name",
+ "shared_entry", "$@13", "shared_items", "shared_item", "shared_name",
+ "shared_user", "shared_type", "$@14", "shared_types", "shared_type_item",
+ "cluster_entry", "$@15", "cluster_items", "cluster_item", "cluster_name",
+ "cluster_type", "$@16", "cluster_types", "cluster_type_item",
+ "connect_entry", "$@17", "connect_items", "connect_item", "connect_name",
+ "connect_host", "connect_vhost", "connect_send_password",
+ "connect_accept_password", "connect_port", "connect_aftype",
+ "connect_flags", "$@18", "connect_flags_items", "connect_flags_item",
+ "connect_encrypted", "connect_hub_mask", "connect_leaf_mask",
+ "connect_class", "connect_ssl_cipher_list", "kill_entry", "$@19",
+ "kill_type", "$@20", "kill_type_items", "kill_type_item", "kill_items",
+ "kill_item", "kill_user", "kill_reason", "deny_entry", "$@21",
+ "deny_items", "deny_item", "deny_ip", "deny_reason", "exempt_entry",
+ "exempt_items", "exempt_item", "exempt_ip", "gecos_entry", "$@22",
+ "gecos_flags", "$@23", "gecos_flags_items", "gecos_flags_item",
+ "gecos_items", "gecos_item", "gecos_name", "gecos_reason",
+ "general_entry", "general_items", "general_item", "general_max_watch",
+ "general_gline_enable", "general_gline_duration",
+ "general_gline_request_duration", "general_gline_min_cidr",
+ "general_gline_min_cidr6", "general_tkline_expire_notices",
+ "general_kill_chase_time_limit", "general_hide_spoof_ips",
+ "general_ignore_bogus_ts", "general_disable_remote_commands",
+ "general_failed_oper_notice", "general_anti_nick_flood",
+ "general_max_nick_time", "general_max_nick_changes",
+ "general_max_accept", "general_anti_spam_exit_message_time",
+ "general_ts_warn_delta", "general_ts_max_delta",
+ "general_havent_read_conf", "general_invisible_on_connect",
+ "general_warn_no_nline", "general_stats_e_disabled",
+ "general_stats_o_oper_only", "general_stats_P_oper_only",
+ "general_stats_k_oper_only", "general_stats_i_oper_only",
+ "general_pace_wait", "general_caller_id_wait",
+ "general_opers_bypass_callerid", "general_pace_wait_simple",
+ "general_short_motd", "general_no_oper_flood",
+ "general_true_no_oper_flood", "general_oper_pass_resv",
+ "general_message_locale", "general_dots_in_ident", "general_max_targets",
+ "general_use_egd", "general_egdpool_path", "general_services_name",
+ "general_ping_cookie", "general_disable_auth", "general_throttle_time",
+ "general_oper_umodes", "$@24", "umode_oitems", "umode_oitem",
+ "general_oper_only_umodes", "$@25", "umode_items", "umode_item",
+ "general_min_nonwildcard", "general_min_nonwildcard_simple",
+ "general_default_floodcount", "channel_entry", "channel_items",
+ "channel_item", "channel_disable_fake_channels",
+ "channel_restrict_channels", "channel_knock_delay",
+ "channel_knock_delay_channel", "channel_max_chans_per_user",
+ "channel_max_chans_per_oper", "channel_quiet_on_ban", "channel_max_bans",
+ "channel_default_split_user_count", "channel_default_split_server_count",
+ "channel_no_create_on_split", "channel_no_join_on_split",
+ "channel_jflood_count", "channel_jflood_time", "serverhide_entry",
+ "serverhide_items", "serverhide_item", "serverhide_flatten_links",
+ "serverhide_hide_servers", "serverhide_hidden_name",
+ "serverhide_links_delay", "serverhide_hidden",
+ "serverhide_hide_server_ips", YY_NULL
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296, 297, 298, 299, 300, 301, 302, 303, 304,
+ 305, 306, 307, 308, 309, 310, 311, 312, 313, 314,
+ 315, 316, 317, 318, 319, 320, 321, 322, 323, 324,
+ 325, 326, 327, 328, 329, 330, 331, 332, 333, 334,
+ 335, 336, 337, 338, 339, 340, 341, 342, 343, 344,
+ 345, 346, 347, 348, 349, 350, 351, 352, 353, 354,
+ 355, 356, 357, 358, 359, 360, 361, 362, 363, 364,
+ 365, 366, 367, 368, 369, 370, 371, 372, 373, 374,
+ 375, 376, 377, 378, 379, 380, 381, 382, 383, 384,
+ 385, 386, 387, 388, 389, 390, 391, 392, 393, 394,
+ 395, 396, 397, 398, 399, 400, 401, 402, 403, 404,
+ 405, 406, 407, 408, 409, 410, 411, 412, 413, 414,
+ 415, 416, 417, 418, 419, 420, 421, 422, 423, 424,
+ 425, 426, 427, 428, 429, 430, 431, 432, 433, 434,
+ 435, 436, 437, 438, 439, 440, 441, 442, 443, 444,
+ 445, 446, 447, 448, 449, 450, 451, 452, 453, 454,
+ 455, 456, 457, 458, 459, 460, 461, 462, 463, 464,
+ 465, 466, 467, 468, 469, 59, 125, 123, 61, 44
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint16 yyr1[] =
+{
+ 0, 220, 221, 221, 222, 222, 222, 222, 222, 222,
+ 222, 222, 222, 222, 222, 222, 222, 222, 222, 222,
+ 222, 222, 222, 222, 222, 222, 223, 223, 224, 224,
+ 224, 224, 224, 224, 225, 225, 226, 226, 226, 226,
+ 227, 228, 228, 229, 229, 229, 230, 231, 232, 233,
+ 233, 234, 234, 234, 234, 234, 234, 234, 234, 234,
+ 234, 234, 234, 234, 234, 234, 234, 235, 236, 237,
+ 237, 238, 238, 239, 239, 240, 240, 241, 242, 243,
+ 244, 245, 246, 247, 248, 249, 250, 251, 252, 253,
+ 254, 255, 255, 256, 256, 256, 256, 257, 258, 259,
+ 260, 261, 261, 262, 262, 262, 263, 265, 264, 266,
+ 266, 267, 267, 267, 267, 268, 269, 269, 271, 270,
+ 272, 272, 273, 273, 273, 273, 273, 273, 273, 275,
+ 274, 276, 276, 277, 277, 277, 277, 277, 277, 277,
+ 277, 277, 278, 279, 280, 281, 282, 283, 285, 284,
+ 286, 286, 287, 287, 287, 287, 287, 287, 287, 287,
+ 287, 287, 287, 287, 287, 287, 287, 287, 287, 287,
+ 287, 287, 289, 288, 290, 290, 291, 291, 291, 291,
+ 291, 291, 291, 291, 291, 291, 291, 291, 291, 291,
+ 291, 291, 291, 291, 291, 293, 292, 294, 294, 295,
+ 295, 295, 295, 295, 295, 295, 295, 295, 295, 295,
+ 295, 295, 295, 295, 296, 297, 298, 299, 300, 301,
+ 302, 303, 304, 305, 306, 307, 308, 309, 311, 310,
+ 313, 312, 314, 314, 315, 315, 315, 316, 316, 317,
+ 317, 317, 317, 317, 319, 318, 320, 320, 321, 321,
+ 322, 323, 325, 324, 326, 326, 327, 327, 327, 327,
+ 327, 327, 327, 327, 327, 328, 329, 330, 331, 333,
+ 332, 334, 334, 335, 335, 335, 335, 335, 335, 335,
+ 335, 335, 336, 337, 338, 340, 339, 341, 341, 342,
+ 342, 342, 342, 343, 344, 345, 346, 347, 347, 348,
+ 348, 349, 351, 350, 352, 352, 353, 353, 353, 353,
+ 354, 355, 357, 356, 358, 358, 359, 359, 359, 359,
+ 359, 359, 359, 359, 359, 359, 361, 360, 362, 362,
+ 363, 363, 363, 364, 366, 365, 367, 367, 368, 368,
+ 368, 368, 368, 368, 368, 368, 368, 368, 370, 369,
+ 371, 371, 372, 372, 372, 372, 372, 372, 372, 372,
+ 372, 372, 372, 372, 372, 372, 373, 374, 375, 376,
+ 377, 378, 379, 379, 381, 380, 382, 382, 383, 383,
+ 384, 385, 386, 387, 388, 390, 389, 392, 391, 393,
+ 393, 394, 395, 395, 396, 396, 396, 396, 397, 398,
+ 400, 399, 401, 401, 402, 402, 402, 403, 404, 405,
+ 406, 406, 407, 407, 408, 410, 409, 412, 411, 413,
+ 413, 414, 415, 415, 416, 416, 416, 416, 417, 418,
+ 419, 420, 420, 421, 421, 421, 421, 421, 421, 421,
+ 421, 421, 421, 421, 421, 421, 421, 421, 421, 421,
+ 421, 421, 421, 421, 421, 421, 421, 421, 421, 421,
+ 421, 421, 421, 421, 421, 421, 421, 421, 421, 421,
+ 421, 421, 421, 421, 421, 421, 421, 421, 421, 421,
+ 421, 421, 421, 422, 423, 424, 425, 426, 427, 428,
+ 429, 430, 431, 432, 433, 434, 435, 436, 437, 438,
+ 439, 440, 441, 442, 443, 444, 445, 446, 447, 447,
+ 448, 448, 449, 450, 451, 452, 453, 454, 455, 456,
+ 457, 458, 459, 460, 461, 462, 463, 464, 465, 467,
+ 466, 468, 468, 469, 469, 469, 469, 469, 469, 469,
+ 469, 469, 469, 469, 469, 469, 469, 469, 469, 469,
+ 469, 469, 469, 471, 470, 472, 472, 473, 473, 473,
+ 473, 473, 473, 473, 473, 473, 473, 473, 473, 473,
+ 473, 473, 473, 473, 473, 473, 473, 474, 475, 476,
+ 477, 478, 478, 479, 479, 479, 479, 479, 479, 479,
+ 479, 479, 479, 479, 479, 479, 479, 479, 480, 481,
+ 482, 483, 484, 485, 486, 487, 488, 489, 490, 491,
+ 492, 493, 494, 495, 495, 496, 496, 496, 496, 496,
+ 496, 496, 497, 498, 499, 500, 501, 502
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 0, 2, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 2, 2, 0, 1, 2, 3,
+ 3, 3, 3, 3, 0, 1, 2, 3, 3, 3,
+ 5, 2, 1, 1, 1, 2, 4, 4, 5, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 2, 4, 4, 3,
+ 1, 1, 1, 3, 1, 1, 1, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 2, 1, 1, 1, 1, 2, 4, 4, 4,
+ 5, 2, 1, 1, 1, 2, 4, 0, 6, 2,
+ 1, 1, 1, 1, 2, 4, 4, 4, 0, 5,
+ 3, 1, 1, 1, 1, 1, 1, 1, 1, 0,
+ 6, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 4, 4, 4, 4, 4, 4, 0, 5,
+ 3, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 0, 5, 3, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 0, 6, 2, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 2, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 0, 6,
+ 0, 5, 3, 1, 1, 1, 1, 2, 1, 1,
+ 1, 1, 1, 2, 0, 5, 3, 1, 1, 3,
+ 4, 4, 0, 6, 2, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 2, 4, 4, 4, 4, 0,
+ 5, 3, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 4, 4, 4, 0, 6, 2, 1, 1,
+ 1, 1, 2, 4, 4, 4, 5, 2, 1, 1,
+ 1, 4, 0, 6, 2, 1, 1, 1, 1, 2,
+ 4, 4, 0, 5, 3, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 0, 6, 2, 1,
+ 1, 1, 2, 4, 0, 5, 3, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 0, 6,
+ 2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 2, 4, 4, 4, 4,
+ 4, 4, 4, 4, 0, 5, 3, 1, 1, 1,
+ 4, 4, 4, 4, 4, 0, 6, 0, 5, 3,
+ 1, 1, 2, 1, 1, 1, 1, 1, 4, 4,
+ 0, 6, 2, 1, 1, 1, 1, 4, 4, 5,
+ 2, 1, 1, 1, 4, 0, 6, 0, 5, 3,
+ 1, 1, 2, 1, 1, 1, 1, 1, 4, 4,
+ 5, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 0,
+ 5, 3, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 0, 5, 3, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 4, 4, 4,
+ 5, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 5, 2, 1, 1, 1, 1, 1, 1,
+ 1, 1, 4, 4, 4, 4, 4, 4
+};
+
+/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint16 yydefact[] =
+{
+ 2, 0, 1, 0, 0, 0, 195, 348, 400, 0,
+ 415, 0, 252, 385, 228, 0, 0, 129, 285, 0,
+ 0, 302, 326, 0, 3, 23, 11, 4, 5, 6,
+ 8, 9, 10, 13, 14, 15, 16, 17, 18, 19,
+ 20, 22, 21, 7, 12, 24, 25, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 92, 93, 95, 94, 597, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 582, 596, 592, 584, 585, 586, 587, 588,
+ 583, 589, 590, 591, 593, 594, 595, 0, 0, 0,
+ 413, 0, 0, 411, 412, 0, 482, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 553, 0, 529, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 432, 480, 474,
+ 475, 476, 477, 478, 473, 443, 433, 434, 468, 435,
+ 436, 437, 438, 439, 440, 441, 442, 470, 444, 445,
+ 479, 447, 452, 448, 450, 449, 463, 464, 451, 453,
+ 454, 455, 456, 457, 446, 459, 460, 461, 481, 471,
+ 472, 469, 462, 458, 466, 467, 465, 0, 0, 0,
+ 0, 0, 0, 102, 103, 104, 0, 0, 0, 0,
+ 0, 42, 43, 44, 0, 0, 621, 0, 0, 0,
+ 0, 0, 0, 0, 614, 615, 616, 619, 617, 618,
+ 620, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 50, 63,
+ 64, 62, 59, 58, 65, 51, 61, 54, 55, 56,
+ 52, 60, 57, 53, 0, 0, 300, 0, 0, 298,
+ 299, 96, 0, 0, 0, 0, 91, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 581, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 198,
+ 199, 202, 203, 205, 206, 207, 208, 209, 210, 211,
+ 212, 200, 201, 204, 0, 0, 0, 0, 0, 374,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 351,
+ 352, 353, 354, 355, 356, 358, 357, 360, 364, 361,
+ 362, 363, 359, 406, 0, 0, 0, 403, 404, 405,
+ 0, 0, 410, 427, 0, 0, 417, 426, 0, 423,
+ 424, 425, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 431, 0, 0, 0, 269, 0, 0, 0,
+ 0, 0, 0, 255, 256, 257, 258, 263, 259, 260,
+ 261, 262, 397, 0, 387, 0, 396, 0, 393, 394,
+ 395, 0, 230, 0, 0, 0, 240, 0, 238, 239,
+ 241, 242, 105, 0, 0, 101, 0, 45, 0, 0,
+ 0, 41, 0, 0, 0, 172, 0, 0, 0, 148,
+ 0, 0, 132, 133, 134, 135, 138, 139, 137, 136,
+ 140, 0, 0, 0, 0, 0, 288, 289, 290, 291,
+ 0, 0, 0, 0, 0, 0, 0, 613, 66, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 49, 0, 0, 312, 0,
+ 0, 305, 306, 307, 308, 0, 0, 334, 0, 329,
+ 330, 331, 0, 0, 297, 0, 0, 0, 90, 0,
+ 0, 0, 26, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 580, 213, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 197, 365, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 350, 0, 0,
+ 0, 402, 0, 409, 0, 0, 0, 0, 422, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 430, 264, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 254, 0, 0, 0, 0, 392, 243, 0, 0,
+ 0, 0, 0, 237, 0, 100, 0, 0, 0, 40,
+ 141, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 131, 292, 0, 0, 0, 0, 287, 0, 0, 0,
+ 0, 0, 0, 612, 0, 0, 0, 0, 0, 0,
+ 0, 0, 71, 72, 0, 70, 75, 76, 0, 74,
+ 0, 0, 0, 0, 0, 48, 309, 0, 0, 0,
+ 0, 304, 332, 0, 0, 0, 328, 0, 296, 99,
+ 98, 97, 607, 606, 598, 26, 26, 26, 26, 26,
+ 28, 27, 600, 601, 605, 603, 602, 608, 609, 610,
+ 611, 604, 599, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 34, 0, 0, 196, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 349, 0, 0, 401, 414, 0, 0,
+ 0, 416, 495, 499, 513, 579, 527, 493, 521, 524,
+ 494, 485, 484, 486, 487, 488, 502, 491, 492, 503,
+ 490, 498, 497, 496, 522, 483, 520, 577, 578, 517,
+ 514, 564, 557, 574, 575, 558, 559, 560, 561, 569,
+ 562, 572, 576, 565, 570, 566, 571, 563, 568, 567,
+ 573, 0, 556, 519, 539, 533, 550, 551, 534, 535,
+ 536, 537, 545, 538, 548, 552, 541, 546, 542, 547,
+ 540, 544, 543, 549, 0, 532, 512, 515, 526, 489,
+ 516, 505, 510, 511, 508, 509, 506, 507, 501, 500,
+ 525, 528, 518, 523, 504, 0, 0, 0, 0, 0,
+ 0, 0, 0, 253, 0, 0, 0, 386, 0, 0,
+ 0, 248, 244, 247, 229, 106, 0, 0, 118, 0,
+ 0, 110, 111, 113, 112, 46, 47, 0, 0, 0,
+ 0, 0, 0, 0, 0, 130, 0, 0, 0, 286,
+ 622, 626, 624, 627, 623, 625, 83, 89, 81, 85,
+ 84, 78, 77, 79, 67, 0, 68, 0, 82, 80,
+ 88, 86, 87, 0, 0, 0, 303, 0, 0, 327,
+ 301, 29, 30, 31, 32, 33, 225, 226, 218, 220,
+ 222, 221, 219, 214, 227, 217, 215, 216, 34, 34,
+ 34, 36, 35, 223, 224, 370, 372, 373, 383, 380,
+ 378, 379, 0, 377, 367, 381, 382, 366, 371, 369,
+ 384, 368, 407, 408, 428, 429, 421, 0, 420, 554,
+ 0, 530, 0, 267, 268, 277, 274, 279, 276, 275,
+ 281, 278, 280, 273, 0, 272, 266, 284, 283, 282,
+ 265, 399, 391, 0, 390, 398, 235, 236, 234, 0,
+ 233, 251, 250, 0, 0, 0, 114, 0, 0, 0,
+ 0, 109, 147, 145, 187, 184, 183, 176, 178, 194,
+ 188, 191, 186, 177, 192, 180, 189, 193, 181, 190,
+ 185, 179, 182, 0, 175, 142, 144, 146, 158, 152,
+ 169, 170, 153, 154, 155, 156, 164, 157, 167, 171,
+ 160, 165, 161, 166, 159, 163, 162, 168, 0, 151,
+ 143, 294, 295, 293, 69, 73, 310, 316, 322, 325,
+ 318, 324, 319, 323, 321, 317, 320, 0, 315, 311,
+ 333, 338, 344, 347, 340, 346, 341, 345, 343, 339,
+ 342, 0, 337, 37, 38, 39, 375, 0, 418, 0,
+ 555, 531, 270, 0, 388, 0, 231, 0, 249, 246,
+ 245, 0, 0, 0, 0, 108, 173, 0, 149, 0,
+ 313, 0, 335, 0, 376, 419, 271, 389, 232, 115,
+ 124, 127, 126, 123, 128, 125, 122, 0, 121, 117,
+ 116, 174, 150, 314, 336, 119, 0, 120
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 1, 24, 780, 781, 1021, 1022, 25, 230, 231,
+ 232, 233, 26, 267, 268, 269, 270, 744, 745, 748,
+ 749, 271, 272, 273, 274, 275, 276, 277, 278, 279,
+ 280, 281, 282, 283, 27, 71, 72, 73, 74, 75,
+ 28, 222, 223, 224, 225, 226, 950, 951, 952, 953,
+ 954, 1088, 1217, 1218, 29, 60, 501, 502, 503, 504,
+ 505, 506, 507, 508, 509, 717, 1138, 1139, 510, 713,
+ 1113, 1114, 30, 49, 328, 329, 330, 331, 332, 333,
+ 334, 335, 336, 337, 338, 339, 340, 341, 342, 343,
+ 31, 57, 476, 698, 1079, 1080, 477, 478, 479, 1085,
+ 942, 943, 480, 481, 32, 55, 452, 453, 454, 455,
+ 456, 457, 458, 684, 1064, 1065, 459, 460, 461, 33,
+ 61, 515, 516, 517, 518, 519, 34, 288, 289, 290,
+ 35, 64, 550, 551, 552, 553, 554, 758, 1157, 1158,
+ 36, 65, 558, 559, 560, 561, 764, 1171, 1172, 37,
+ 50, 358, 359, 360, 361, 362, 363, 364, 365, 366,
+ 367, 607, 1032, 1033, 368, 369, 370, 371, 372, 38,
+ 56, 466, 693, 1073, 1074, 467, 468, 469, 470, 39,
+ 51, 376, 377, 378, 379, 40, 112, 113, 114, 41,
+ 53, 387, 626, 1047, 1048, 388, 389, 390, 391, 42,
+ 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, 423, 904, 905,
+ 213, 421, 881, 882, 214, 215, 216, 43, 91, 92,
+ 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
+ 103, 104, 105, 106, 44, 243, 244, 245, 246, 247,
+ 248, 249, 250
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -744
+static const yytype_int16 yypact[] =
+{
+ -744, 610, -744, -209, -187, -179, -744, -744, -744, -176,
+ -744, -171, -744, -744, -744, -166, -164, -744, -744, -139,
+ -136, -744, -744, -131, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, 61, 807, -126,
+ -104, -84, 16, -79, 382, -77, -63, -60, 7, 21,
+ -49, -40, 638, 381, -26, 52, 25, -152, 62, 85,
+ 86, 18, -744, -744, -744, -744, -744, 88, 89, 93,
+ 94, 96, 101, 108, 112, 118, 119, 125, 127, 132,
+ 133, 162, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, 531, 499, 266,
+ -744, 135, 28, -744, -744, 11, -744, 142, 143, 145,
+ 147, 148, 150, 153, 163, 166, 167, 169, 173, 174,
+ 175, 177, 178, 180, 182, 183, 185, 191, 197, 200,
+ 201, 202, 204, 211, 212, 215, -744, 216, -744, 217,
+ 218, 221, 222, 225, 226, 229, 234, 235, 237, 238,
+ 239, 242, 253, 256, 257, 262, 38, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, 337, 24, 259,
+ 73, 263, 4, -744, -744, -744, 126, 131, 264, 270,
+ 59, -744, -744, -744, 389, 209, -744, 276, 279, 280,
+ 281, 285, 287, 3, -744, -744, -744, -744, -744, -744,
+ -744, 149, 288, 289, 290, 292, 299, 301, 302, 303,
+ 304, 305, 307, 308, 315, 324, 330, 75, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, 208, 30, -744, 331, 15, -744,
+ -744, -744, 107, 254, 359, 165, -744, 385, 396, 367,
+ 454, 454, 455, 457, 461, 399, 401, 464, 454, 404,
+ 405, 351, -744, 358, 356, 360, 361, 362, 364, 365,
+ 369, 374, 375, 379, 383, 386, 388, 395, 232, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, 384, 397, 400, 403, 408, -744,
+ 411, 412, 420, 423, 424, 427, 433, 434, 260, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, 435, 437, 8, -744, -744, -744,
+ 458, 407, -744, -744, 441, 442, -744, -744, 36, -744,
+ -744, -744, 417, 454, 454, 501, 443, 459, 524, 543,
+ 502, 454, 503, 454, 565, 567, 568, 508, 509, 513,
+ 454, 577, 578, 454, 580, 583, 566, 584, 587, 527,
+ 528, 475, 535, 478, 454, 454, 537, 540, 541, 542,
+ -146, -133, 544, 546, 454, 454, 585, 454, 550, 553,
+ 554, 510, -744, 515, 514, 517, -744, 519, 521, 525,
+ 529, 530, 58, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, 533, -744, 534, -744, 10, -744, -744,
+ -744, 538, -744, 536, 539, 545, -744, 115, -744, -744,
+ -744, -744, -744, 582, 547, -744, 532, -744, 640, 643,
+ 549, -744, 555, 559, 560, -744, 562, 569, 572, -744,
+ 573, 70, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, 558, 588, 595, 597, 146, -744, -744, -744, -744,
+ 623, 625, 687, 658, 659, 454, 606, -744, -744, 704,
+ 663, 706, 707, 709, 713, 714, 715, 79, 159, 717,
+ 718, 646, 719, 720, 626, -744, 628, 622, -744, 624,
+ 128, -744, -744, -744, -744, 629, 630, -744, 22, -744,
+ -744, -744, 728, 632, -744, 634, 635, 636, -744, 637,
+ 639, 641, 430, 642, 645, 648, 649, 650, 651, 652,
+ 653, 654, 656, 657, -744, -744, 754, 756, 454, 759,
+ 776, 778, 779, 761, 784, 785, 454, 454, 786, 786,
+ 671, -744, -744, 769, 122, 770, 729, 672, 773, 774,
+ 775, 777, 795, 780, 781, 782, 681, -744, 783, 787,
+ 682, -744, 689, -744, 788, 789, 690, 694, -744, 695,
+ 696, 697, 698, 699, 702, 703, 705, 708, 710, 712,
+ 716, 721, 722, 723, 724, 725, 726, 727, 730, 731,
+ 732, 733, 734, 735, 736, 737, 738, 739, 551, 740,
+ 599, 741, 742, 743, 744, 745, 746, 747, 748, 749,
+ 750, 751, 752, 753, 755, 757, 758, 760, 762, 763,
+ -744, -744, 801, 764, 711, 803, 823, 810, 812, 814,
+ 765, -744, 815, 766, 817, 767, -744, -744, 768, 825,
+ 826, 870, 772, -744, 790, -744, 184, 791, 792, -744,
+ -744, 853, 816, 771, 856, 861, 863, 793, 865, 794,
+ -744, -744, 867, 872, 873, 797, -744, 798, 799, 800,
+ 802, 804, 805, -744, 806, 808, 809, 811, 813, 818,
+ 819, 820, -744, -744, -195, -744, -744, -744, -172, -744,
+ 821, 822, 824, 827, 828, -744, -744, 874, 829, 875,
+ 830, -744, -744, 876, 831, 833, -744, 835, -744, -744,
+ -744, -744, -744, -744, -744, 454, 454, 454, 454, 454,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, 836, 837, 838, 839, 840, 841, 842,
+ 843, 844, 845, 846, 847, 314, 848, 849, -744, 850,
+ 851, 852, 854, 855, 13, 857, 858, 859, 860, 862,
+ 864, 866, 868, -744, 869, 871, -744, -744, 877, 878,
+ 879, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -167, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -154, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, 880, 881, 309, 882, 883,
+ 884, 885, 886, -744, 887, 893, 888, -744, -33, 889,
+ 890, 832, 891, -744, -744, -744, 892, 894, -744, 895,
+ 154, -744, -744, -744, -744, -744, -744, 896, 899, 511,
+ 900, 901, 902, 627, 903, -744, 904, 905, 906, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, 79, -744, 159, -744, -744,
+ -744, -744, -744, 907, 460, 908, -744, 909, 665, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, 786, 786,
+ 786, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -145, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, -50, -744, -744,
+ 551, -744, 599, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -41, -744, -744, -744, -744, -744,
+ -744, -744, -744, -27, -744, -744, -744, -744, -744, -17,
+ -744, -744, -744, 898, 870, 910, -744, 911, 912, -86,
+ 913, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, 34, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, 40, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, 53, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, 63, -744, -744, -744, -744, -744, 13, -744, 879,
+ -744, -744, -744, 309, -744, 893, -744, -33, -744, -744,
+ -744, 914, 277, 916, 917, -744, -744, 511, -744, 627,
+ -744, 460, -744, 665, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, 68, -744, -744,
+ -744, -744, -744, -744, -744, -744, 277, -744
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -744, -744, -744, -743, -298, -663, -598, -744, -744, 897,
+ -744, -744, -744, -744, 915, -744, -744, -744, 14, -744,
+ 1, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, 924, -744, -744, -744,
+ -744, -744, 796, -744, -744, -744, -744, 48, -744, -744,
+ -744, -744, -744, -226, -744, -744, -744, 500, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, -196, -744, -744,
+ -744, -193, -744, -744, -744, 680, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -177, -744, 548, -744, -744,
+ -744, -62, -744, -744, -744, -744, -744, 575, -744, -744,
+ -744, -744, -744, -744, -744, -153, -744, -744, -744, -744,
+ -744, -744, 516, -744, -744, -744, -744, -744, 918, -744,
+ -744, -744, -744, 482, -744, -744, -744, -744, -744, -163,
+ -744, -744, -744, 483, -744, -744, -744, -744, -159, -744,
+ -744, -744, 688, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -137, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -117, -744, 604, -744, -744, -744,
+ -744, -744, 700, -744, -744, -744, -744, 966, -744, -744,
+ -744, -744, -744, -744, -99, -744, 701, -744, -744, -744,
+ -744, 919, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, 35,
+ -744, -744, -744, 32, -744, -744, -744, -744, -744, 997,
+ -744, -744, -744, -744, -744, -744, -744, -744, -744, -744,
+ -744, -744, -744, -744, -744, -744, 920, -744, -744, -744,
+ -744, -744, -744
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -108
+static const yytype_int16 yytable[] =
+{
+ 806, 807, 573, 574, 236, 220, 45, 46, 220, 373,
+ 581, 462, 383, 805, 667, 668, 286, 110, 1076, 67,
+ 984, 1030, 227, 555, 985, 462, 286, 669, 670, 110,
+ 47, 555, 1001, 1002, 1003, 1004, 1005, 383, 48, 116,
+ 237, 52, 68, 986, 117, 118, 54, 987, 1049, 69,
+ 119, 58, 1050, 59, 238, 239, 240, 241, 120, 443,
+ 227, 1051, 67, 291, 121, 1052, 122, 123, 124, 374,
+ 1176, 492, 242, 125, 1177, 444, 251, 111, 62, 126,
+ 127, 63, 128, 129, 130, 68, 66, 493, 131, 111,
+ 445, 107, 69, 132, 446, 630, 631, 133, 134, 252,
+ 384, 135, 494, 638, 287, 640, 495, 70, 228, 1193,
+ 136, 556, 647, 108, 287, 650, 471, 137, 138, 556,
+ 139, 140, 141, 142, 143, 384, 661, 662, 375, 546,
+ 463, 385, 253, 109, 229, 144, 673, 674, 115, 676,
+ 217, 145, 146, 147, 463, 148, 228, 511, 149, 150,
+ 70, 472, 151, 1077, 218, 946, 385, 219, 1078, 496,
+ 512, 464, 386, 76, 254, 1178, 255, 256, 234, 1179,
+ 447, 473, 229, 557, 1182, 464, 474, 235, 1183, 448,
+ 449, 557, 497, 77, 78, 946, 152, 386, 1184, 79,
+ 153, 284, 1185, 154, 155, 156, 157, 158, 1186, 498,
+ 159, 160, 1187, 257, 1031, 258, 259, 260, 261, 546,
+ 511, 450, 221, 742, 743, 221, 465, 547, -107, 526,
+ 484, -107, 262, 512, 620, 565, 695, 732, 80, 81,
+ 465, 563, 475, 313, 295, 82, 83, 84, 765, 513,
+ 161, 162, 163, 947, 381, 164, 263, 314, 315, 1196,
+ 165, 316, 627, 1197, 441, 1198, 264, 85, 86, 1199,
+ 471, 344, 499, 345, 451, 346, 514, 373, 1200, 285,
+ 87, 88, 1201, 947, 690, 490, 500, 347, 1202, 548,
+ 292, 89, 1203, 1225, 265, 266, 719, 1226, 482, 90,
+ 795, 544, 348, 746, 747, 472, 349, 547, 803, 804,
+ 810, 811, 513, 293, 294, 948, 297, 298, 317, 318,
+ 319, 299, 300, 320, 301, 473, 350, 1210, 351, 302,
+ 474, 321, 1055, 1018, 1019, 1020, 303, 374, 352, 514,
+ 304, 702, 322, 323, 549, 948, 305, 306, 443, 1211,
+ 486, 1212, 1056, 307, 760, 308, 487, 324, 325, 353,
+ 309, 310, 1057, 380, 444, 1173, 1174, 1175, 1058, 548,
+ 392, 393, 725, 394, 528, 395, 396, 949, 397, 445,
+ 1090, 398, 566, 446, 1059, 326, 475, 354, 311, 1213,
+ 568, 399, 251, 116, 400, 401, 375, 402, 117, 118,
+ 492, 403, 404, 405, 119, 406, 407, 949, 408, 1060,
+ 409, 410, 120, 411, 355, 252, 493, 1061, 121, 412,
+ 122, 123, 124, 805, 549, 413, 327, 125, 414, 415,
+ 416, 494, 417, 126, 127, 495, 128, 129, 130, 418,
+ 419, 356, 131, 420, 422, 424, 425, 132, 253, 426,
+ 427, 133, 134, 428, 429, 135, 1062, 430, 600, 447,
+ 1214, 1215, 431, 432, 136, 433, 434, 435, 448, 449,
+ 436, 137, 138, 1063, 139, 140, 141, 142, 143, 357,
+ 254, 437, 255, 256, 438, 439, 616, 567, 496, 144,
+ 440, 483, 488, 1216, 569, 145, 146, 147, 489, 148,
+ 450, 1194, 149, 150, 520, 570, 151, 521, 522, 523,
+ 344, 497, 345, 524, 346, 525, 529, 530, 531, 257,
+ 532, 258, 259, 260, 261, 1094, 347, 533, 498, 534,
+ 535, 536, 537, 538, 1147, 539, 540, 571, 262, 572,
+ 152, 348, 313, 541, 153, 349, 1095, 154, 155, 156,
+ 157, 158, 542, 451, 159, 160, 314, 315, 543, 562,
+ 316, 1096, 263, 572, 575, 350, 576, 351, 1097, 578,
+ 577, 579, 264, 580, 582, 583, 584, 352, 775, 776,
+ 777, 778, 779, 585, 586, 1098, 622, 629, 587, 588,
+ 589, 499, 590, 591, 161, 162, 163, 592, 353, 164,
+ 265, 266, 593, 594, 165, 500, 1148, 595, 1099, 602,
+ 632, 596, 861, 633, 597, 1100, 598, 317, 318, 319,
+ 2, 3, 320, 599, 4, 603, 354, 1101, 604, 634,
+ 321, 605, 623, 635, 5, 1149, 606, 6, 7, 608,
+ 609, 322, 323, 8, 1150, 1102, 1103, 1104, 610, 236,
+ 1151, 611, 612, 355, 9, 613, 324, 325, 10, 11,
+ 884, 614, 615, 618, 1152, 619, 1153, 1154, 12, 624,
+ 625, 636, 637, 639, 641, 1155, 642, 643, 644, 645,
+ 356, 1156, 13, 646, 326, 237, 648, 649, 1118, 651,
+ 14, 15, 652, 654, 653, 1105, 655, 656, 657, 238,
+ 239, 240, 241, 658, 1106, 659, 660, 663, 16, 1107,
+ 664, 665, 666, 675, 671, 1108, 672, 242, 357, 1109,
+ 677, 1110, 17, 678, 679, 327, 1111, 862, 863, 864,
+ 865, 866, 1112, 867, 868, 680, 869, 870, 871, 1161,
+ 681, 872, 682, 873, 874, 683, 875, 685, 876, 686,
+ 877, 878, 704, 687, 879, 752, 18, 688, 689, 706,
+ 880, 692, 694, 697, 699, 19, 20, 700, 707, 21,
+ 22, 708, 705, 701, 709, 885, 886, 887, 888, 889,
+ 710, 890, 891, 721, 892, 893, 894, 711, 712, 895,
+ 714, 896, 897, 727, 898, 728, 899, 715, 900, 901,
+ 716, 718, 902, 1119, 1120, 1121, 1122, 1123, 903, 1124,
+ 1125, 1162, 1126, 1127, 1128, 729, 722, 1129, 76, 1130,
+ 1131, 23, 1132, 723, 1133, 724, 1134, 1135, 730, 731,
+ 1136, 733, 734, 735, 736, 737, 1137, 738, 77, 78,
+ 1163, 739, 740, 741, 79, 750, 751, 753, 754, 1164,
+ 757, 755, 759, 756, 762, 1165, 767, 768, 763, 769,
+ 770, 771, 772, 793, 773, 794, 774, 782, 796, 1166,
+ 783, 1167, 1168, 784, 785, 786, 787, 788, 789, 790,
+ 1169, 791, 792, 80, 81, 797, 1170, 798, 799, 800,
+ 82, 83, 84, 801, 802, 805, 808, 809, 812, 813,
+ 814, 815, 816, 817, 819, 818, 823, 826, 820, 821,
+ 822, 824, 85, 86, 827, 825, 828, 829, 830, 831,
+ 832, 833, 834, 835, 836, 87, 88, 837, 838, 925,
+ 839, 928, 929, 840, 926, 841, 89, 842, 930, 927,
+ 931, 843, 932, 934, 90, 936, 844, 845, 846, 847,
+ 848, 849, 850, 939, 940, 851, 852, 853, 854, 855,
+ 856, 857, 858, 859, 860, 883, 906, 907, 908, 909,
+ 910, 911, 912, 913, 914, 915, 916, 917, 918, 941,
+ 919, 957, 920, 921, 960, 922, 958, 923, 924, 961,
+ 933, 962, 937, 964, 935, 966, 938, 944, 1145, 959,
+ 967, 968, 993, 995, 997, 296, 1083, 1188, 1091, 1144,
+ 1227, 720, 1046, 1222, 1221, 945, 955, 956, 601, 965,
+ 1208, 963, 969, 970, 971, 972, 1072, 973, 485, 974,
+ 975, 976, 1189, 977, 978, 703, 979, 691, 980, 1191,
+ 1206, 726, 761, 981, 982, 983, 988, 989, 1223, 990,
+ 1204, 766, 991, 992, 1224, 996, 617, 994, 999, 998,
+ 1000, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014,
+ 1015, 1016, 1017, 1023, 1024, 1025, 1026, 1027, 1207, 1028,
+ 1029, 696, 1034, 1035, 1036, 1037, 621, 1038, 382, 1039,
+ 1205, 1040, 1180, 1041, 1042, 442, 1043, 1181, 312, 628,
+ 0, 0, 1044, 1045, 0, 1053, 1054, 1066, 1067, 1068,
+ 1069, 1070, 1071, 1075, 1081, 1082, 0, 1086, 0, 0,
+ 1084, 1092, 1087, 1089, 1093, 1115, 1116, 1117, 1140, 1141,
+ 1142, 1143, 1146, 1159, 1160, 1190, 0, 491, 1195, 1209,
+ 1192, 1219, 1220, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 527, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 545, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 564
+};
+
+#define yypact_value_is_default(yystate) \
+ ((yystate) == (-744))
+
+#define yytable_value_is_error(yytable_value) \
+ YYID (0)
+
+static const yytype_int16 yycheck[] =
+{
+ 598, 599, 300, 301, 1, 1, 215, 216, 1, 1,
+ 308, 1, 1, 99, 160, 161, 1, 1, 51, 1,
+ 215, 8, 1, 1, 219, 1, 1, 160, 161, 1,
+ 217, 1, 775, 776, 777, 778, 779, 1, 217, 1,
+ 37, 217, 24, 215, 6, 7, 217, 219, 215, 31,
+ 12, 217, 219, 217, 51, 52, 53, 54, 20, 1,
+ 1, 215, 1, 215, 26, 219, 28, 29, 30, 61,
+ 215, 1, 69, 35, 219, 17, 1, 61, 217, 41,
+ 42, 217, 44, 45, 46, 24, 217, 17, 50, 61,
+ 32, 217, 31, 55, 36, 393, 394, 59, 60, 24,
+ 89, 63, 32, 401, 89, 403, 36, 89, 87, 195,
+ 72, 89, 410, 217, 89, 413, 1, 79, 80, 89,
+ 82, 83, 84, 85, 86, 89, 424, 425, 120, 1,
+ 120, 120, 57, 217, 113, 97, 434, 435, 217, 437,
+ 217, 103, 104, 105, 120, 107, 87, 1, 110, 111,
+ 89, 36, 114, 186, 217, 1, 120, 217, 191, 89,
+ 14, 151, 151, 1, 89, 215, 91, 92, 217, 219,
+ 112, 56, 113, 151, 215, 151, 61, 217, 219, 121,
+ 122, 151, 112, 21, 22, 1, 148, 151, 215, 27,
+ 152, 217, 219, 155, 156, 157, 158, 159, 215, 129,
+ 162, 163, 219, 128, 191, 130, 131, 132, 133, 1,
+ 1, 153, 208, 134, 135, 208, 206, 89, 214, 216,
+ 216, 214, 147, 14, 216, 118, 216, 525, 66, 67,
+ 206, 216, 117, 1, 216, 73, 74, 75, 216, 93,
+ 202, 203, 204, 89, 216, 207, 171, 15, 16, 215,
+ 212, 19, 216, 219, 216, 215, 181, 95, 96, 219,
+ 1, 1, 192, 3, 206, 5, 120, 1, 215, 217,
+ 108, 109, 219, 89, 216, 216, 206, 17, 215, 151,
+ 218, 119, 219, 215, 209, 210, 216, 219, 215, 127,
+ 588, 216, 32, 134, 135, 36, 36, 89, 596, 597,
+ 178, 179, 93, 218, 218, 151, 218, 218, 76, 77,
+ 78, 218, 218, 81, 218, 56, 56, 40, 58, 218,
+ 61, 89, 13, 9, 10, 11, 218, 61, 68, 120,
+ 218, 216, 100, 101, 206, 151, 218, 218, 1, 62,
+ 214, 64, 33, 218, 216, 218, 215, 115, 116, 89,
+ 218, 218, 43, 218, 17, 1018, 1019, 1020, 49, 151,
+ 218, 218, 216, 218, 215, 218, 218, 213, 218, 32,
+ 216, 218, 118, 36, 65, 143, 117, 117, 216, 102,
+ 215, 218, 1, 1, 218, 218, 120, 218, 6, 7,
+ 1, 218, 218, 218, 12, 218, 218, 213, 218, 90,
+ 218, 218, 20, 218, 144, 24, 17, 98, 26, 218,
+ 28, 29, 30, 99, 206, 218, 184, 35, 218, 218,
+ 218, 32, 218, 41, 42, 36, 44, 45, 46, 218,
+ 218, 171, 50, 218, 218, 218, 218, 55, 57, 218,
+ 218, 59, 60, 218, 218, 63, 137, 218, 216, 112,
+ 173, 174, 218, 218, 72, 218, 218, 218, 121, 122,
+ 218, 79, 80, 154, 82, 83, 84, 85, 86, 209,
+ 89, 218, 91, 92, 218, 218, 216, 118, 89, 97,
+ 218, 218, 218, 206, 99, 103, 104, 105, 218, 107,
+ 153, 1089, 110, 111, 218, 99, 114, 218, 218, 218,
+ 1, 112, 3, 218, 5, 218, 218, 218, 218, 128,
+ 218, 130, 131, 132, 133, 4, 17, 218, 129, 218,
+ 218, 218, 218, 218, 64, 218, 218, 160, 147, 99,
+ 148, 32, 1, 218, 152, 36, 25, 155, 156, 157,
+ 158, 159, 218, 206, 162, 163, 15, 16, 218, 218,
+ 19, 40, 171, 99, 99, 56, 99, 58, 47, 160,
+ 99, 160, 181, 99, 160, 160, 215, 68, 138, 139,
+ 140, 141, 142, 215, 218, 64, 118, 160, 218, 218,
+ 218, 192, 218, 218, 202, 203, 204, 218, 89, 207,
+ 209, 210, 218, 218, 212, 206, 136, 218, 87, 215,
+ 99, 218, 51, 160, 218, 94, 218, 76, 77, 78,
+ 0, 1, 81, 218, 4, 218, 117, 106, 218, 160,
+ 89, 218, 215, 99, 14, 165, 218, 17, 18, 218,
+ 218, 100, 101, 23, 174, 124, 125, 126, 218, 1,
+ 180, 218, 218, 144, 34, 218, 115, 116, 38, 39,
+ 51, 218, 218, 218, 194, 218, 196, 197, 48, 218,
+ 218, 118, 160, 160, 99, 205, 99, 99, 160, 160,
+ 171, 211, 62, 160, 143, 37, 99, 99, 51, 99,
+ 70, 71, 99, 99, 118, 174, 99, 160, 160, 51,
+ 52, 53, 54, 218, 183, 160, 218, 160, 88, 188,
+ 160, 160, 160, 118, 160, 194, 160, 69, 209, 198,
+ 160, 200, 102, 160, 160, 184, 205, 166, 167, 168,
+ 169, 170, 211, 172, 173, 215, 175, 176, 177, 64,
+ 215, 180, 218, 182, 183, 218, 185, 218, 187, 218,
+ 189, 190, 160, 218, 193, 99, 136, 218, 218, 217,
+ 199, 218, 218, 215, 218, 145, 146, 218, 118, 149,
+ 150, 118, 215, 218, 215, 166, 167, 168, 169, 170,
+ 215, 172, 173, 215, 175, 176, 177, 218, 218, 180,
+ 218, 182, 183, 160, 185, 160, 187, 218, 189, 190,
+ 218, 218, 193, 166, 167, 168, 169, 170, 199, 172,
+ 173, 136, 175, 176, 177, 118, 218, 180, 1, 182,
+ 183, 201, 185, 218, 187, 218, 189, 190, 160, 160,
+ 193, 215, 118, 160, 118, 118, 199, 118, 21, 22,
+ 165, 118, 118, 118, 27, 118, 118, 118, 118, 174,
+ 218, 215, 218, 215, 215, 180, 118, 215, 218, 215,
+ 215, 215, 215, 99, 215, 99, 215, 215, 99, 194,
+ 215, 196, 197, 215, 215, 215, 215, 215, 215, 215,
+ 205, 215, 215, 66, 67, 99, 211, 99, 99, 118,
+ 73, 74, 75, 99, 99, 99, 215, 118, 118, 160,
+ 218, 118, 118, 118, 99, 118, 215, 215, 118, 118,
+ 118, 118, 95, 96, 215, 118, 118, 118, 218, 215,
+ 215, 215, 215, 215, 215, 108, 109, 215, 215, 118,
+ 215, 118, 99, 215, 160, 215, 119, 215, 118, 218,
+ 118, 215, 118, 118, 127, 118, 215, 215, 215, 215,
+ 215, 215, 215, 118, 118, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 99,
+ 215, 118, 215, 215, 118, 215, 160, 215, 215, 118,
+ 215, 118, 215, 118, 218, 118, 218, 215, 987, 218,
+ 118, 118, 118, 118, 118, 71, 164, 99, 950, 985,
+ 1226, 501, 123, 1199, 1197, 215, 215, 215, 328, 215,
+ 1187, 218, 215, 215, 215, 215, 123, 215, 222, 215,
+ 215, 215, 1084, 215, 215, 477, 215, 452, 215, 118,
+ 1183, 515, 550, 215, 215, 215, 215, 215, 1201, 215,
+ 1177, 558, 215, 215, 1203, 215, 358, 218, 215, 218,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 1185, 215,
+ 215, 467, 215, 215, 215, 215, 376, 215, 112, 215,
+ 1179, 215, 1050, 215, 215, 166, 215, 1052, 91, 388,
+ -1, -1, 215, 215, -1, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, -1, 215, -1, -1,
+ 219, 215, 218, 218, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, -1, 230, 215, 215,
+ 218, 215, 215, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 243, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 267, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 288
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint16 yystos[] =
+{
+ 0, 221, 0, 1, 4, 14, 17, 18, 23, 34,
+ 38, 39, 48, 62, 70, 71, 88, 102, 136, 145,
+ 146, 149, 150, 201, 222, 227, 232, 254, 260, 274,
+ 292, 310, 324, 339, 346, 350, 360, 369, 389, 399,
+ 405, 409, 419, 477, 494, 215, 216, 217, 217, 293,
+ 370, 400, 217, 410, 217, 325, 390, 311, 217, 217,
+ 275, 340, 217, 217, 351, 361, 217, 1, 24, 31,
+ 89, 255, 256, 257, 258, 259, 1, 21, 22, 27,
+ 66, 67, 73, 74, 75, 95, 96, 108, 109, 119,
+ 127, 478, 479, 480, 481, 482, 483, 484, 485, 486,
+ 487, 488, 489, 490, 491, 492, 493, 217, 217, 217,
+ 1, 61, 406, 407, 408, 217, 1, 6, 7, 12,
+ 20, 26, 28, 29, 30, 35, 41, 42, 44, 45,
+ 46, 50, 55, 59, 60, 63, 72, 79, 80, 82,
+ 83, 84, 85, 86, 97, 103, 104, 105, 107, 110,
+ 111, 114, 148, 152, 155, 156, 157, 158, 159, 162,
+ 163, 202, 203, 204, 207, 212, 420, 421, 422, 423,
+ 424, 425, 426, 427, 428, 429, 430, 431, 432, 433,
+ 434, 435, 436, 437, 438, 439, 440, 441, 442, 443,
+ 444, 445, 446, 447, 448, 449, 450, 451, 452, 453,
+ 454, 455, 456, 457, 458, 459, 460, 461, 462, 463,
+ 464, 465, 466, 470, 474, 475, 476, 217, 217, 217,
+ 1, 208, 261, 262, 263, 264, 265, 1, 87, 113,
+ 228, 229, 230, 231, 217, 217, 1, 37, 51, 52,
+ 53, 54, 69, 495, 496, 497, 498, 499, 500, 501,
+ 502, 1, 24, 57, 89, 91, 92, 128, 130, 131,
+ 132, 133, 147, 171, 181, 209, 210, 233, 234, 235,
+ 236, 241, 242, 243, 244, 245, 246, 247, 248, 249,
+ 250, 251, 252, 253, 217, 217, 1, 89, 347, 348,
+ 349, 215, 218, 218, 218, 216, 256, 218, 218, 218,
+ 218, 218, 218, 218, 218, 218, 218, 218, 218, 218,
+ 218, 216, 479, 1, 15, 16, 19, 76, 77, 78,
+ 81, 89, 100, 101, 115, 116, 143, 184, 294, 295,
+ 296, 297, 298, 299, 300, 301, 302, 303, 304, 305,
+ 306, 307, 308, 309, 1, 3, 5, 17, 32, 36,
+ 56, 58, 68, 89, 117, 144, 171, 209, 371, 372,
+ 373, 374, 375, 376, 377, 378, 379, 380, 384, 385,
+ 386, 387, 388, 1, 61, 120, 401, 402, 403, 404,
+ 218, 216, 407, 1, 89, 120, 151, 411, 415, 416,
+ 417, 418, 218, 218, 218, 218, 218, 218, 218, 218,
+ 218, 218, 218, 218, 218, 218, 218, 218, 218, 218,
+ 218, 218, 218, 218, 218, 218, 218, 218, 218, 218,
+ 218, 471, 218, 467, 218, 218, 218, 218, 218, 218,
+ 218, 218, 218, 218, 218, 218, 218, 218, 218, 218,
+ 218, 216, 421, 1, 17, 32, 36, 112, 121, 122,
+ 153, 206, 326, 327, 328, 329, 330, 331, 332, 336,
+ 337, 338, 1, 120, 151, 206, 391, 395, 396, 397,
+ 398, 1, 36, 56, 61, 117, 312, 316, 317, 318,
+ 322, 323, 215, 218, 216, 262, 214, 215, 218, 218,
+ 216, 229, 1, 17, 32, 36, 89, 112, 129, 192,
+ 206, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 288, 1, 14, 93, 120, 341, 342, 343, 344, 345,
+ 218, 218, 218, 218, 218, 218, 216, 496, 215, 218,
+ 218, 218, 218, 218, 218, 218, 218, 218, 218, 218,
+ 218, 218, 218, 218, 216, 234, 1, 89, 151, 206,
+ 352, 353, 354, 355, 356, 1, 89, 151, 362, 363,
+ 364, 365, 218, 216, 348, 118, 118, 118, 215, 99,
+ 99, 160, 99, 224, 224, 99, 99, 99, 160, 160,
+ 99, 224, 160, 160, 215, 215, 218, 218, 218, 218,
+ 218, 218, 218, 218, 218, 218, 218, 218, 218, 218,
+ 216, 295, 215, 218, 218, 218, 218, 381, 218, 218,
+ 218, 218, 218, 218, 218, 218, 216, 372, 218, 218,
+ 216, 402, 118, 215, 218, 218, 412, 216, 416, 160,
+ 224, 224, 99, 160, 160, 99, 118, 160, 224, 160,
+ 224, 99, 99, 99, 160, 160, 160, 224, 99, 99,
+ 224, 99, 99, 118, 99, 99, 160, 160, 218, 160,
+ 218, 224, 224, 160, 160, 160, 160, 160, 161, 160,
+ 161, 160, 160, 224, 224, 118, 224, 160, 160, 160,
+ 215, 215, 218, 218, 333, 218, 218, 218, 218, 218,
+ 216, 327, 218, 392, 218, 216, 396, 215, 313, 218,
+ 218, 218, 216, 317, 160, 215, 217, 118, 118, 215,
+ 215, 218, 218, 289, 218, 218, 218, 285, 218, 216,
+ 277, 215, 218, 218, 218, 216, 342, 160, 160, 118,
+ 160, 160, 224, 215, 118, 160, 118, 118, 118, 118,
+ 118, 118, 134, 135, 237, 238, 134, 135, 239, 240,
+ 118, 118, 99, 118, 118, 215, 215, 218, 357, 218,
+ 216, 353, 215, 218, 366, 216, 363, 118, 215, 215,
+ 215, 215, 215, 215, 215, 138, 139, 140, 141, 142,
+ 223, 224, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 99, 99, 224, 99, 99, 99, 99,
+ 118, 99, 99, 224, 224, 99, 226, 226, 215, 118,
+ 178, 179, 118, 160, 218, 118, 118, 118, 118, 99,
+ 118, 118, 118, 215, 118, 118, 215, 215, 118, 118,
+ 218, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 51, 166, 167, 168, 169, 170, 172, 173, 175,
+ 176, 177, 180, 182, 183, 185, 187, 189, 190, 193,
+ 199, 472, 473, 215, 51, 166, 167, 168, 169, 170,
+ 172, 173, 175, 176, 177, 180, 182, 183, 185, 187,
+ 189, 190, 193, 199, 468, 469, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 118, 160, 218, 118, 99,
+ 118, 118, 118, 215, 118, 218, 118, 215, 218, 118,
+ 118, 99, 320, 321, 215, 215, 1, 89, 151, 213,
+ 266, 267, 268, 269, 270, 215, 215, 118, 160, 218,
+ 118, 118, 118, 218, 118, 215, 118, 118, 118, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 219, 215, 219, 215, 215,
+ 215, 215, 215, 118, 218, 118, 215, 118, 218, 215,
+ 215, 223, 223, 223, 223, 223, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 9, 10,
+ 11, 225, 226, 215, 215, 215, 215, 215, 215, 215,
+ 8, 191, 382, 383, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 123, 413, 414, 215,
+ 219, 215, 219, 215, 215, 13, 33, 43, 49, 65,
+ 90, 98, 137, 154, 334, 335, 215, 215, 215, 215,
+ 215, 215, 123, 393, 394, 215, 51, 186, 191, 314,
+ 315, 215, 215, 164, 219, 319, 215, 218, 271, 218,
+ 216, 267, 215, 215, 4, 25, 40, 47, 64, 87,
+ 94, 106, 124, 125, 126, 174, 183, 188, 194, 198,
+ 200, 205, 211, 290, 291, 215, 215, 215, 51, 166,
+ 167, 168, 169, 170, 172, 173, 175, 176, 177, 180,
+ 182, 183, 185, 187, 189, 190, 193, 199, 286, 287,
+ 215, 215, 215, 215, 238, 240, 215, 64, 136, 165,
+ 174, 180, 194, 196, 197, 205, 211, 358, 359, 215,
+ 215, 64, 136, 165, 174, 180, 194, 196, 197, 205,
+ 211, 367, 368, 225, 225, 225, 215, 219, 215, 219,
+ 473, 469, 215, 219, 215, 219, 215, 219, 99, 321,
+ 215, 118, 218, 195, 226, 215, 215, 219, 215, 219,
+ 215, 219, 215, 219, 383, 414, 335, 394, 315, 215,
+ 40, 62, 64, 102, 173, 174, 206, 272, 273, 215,
+ 215, 291, 287, 359, 368, 215, 219, 273
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. However,
+ YYFAIL appears to be in use. Nevertheless, it is formally deprecated
+ in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+ discussed. */
+
+#define YYFAIL goto yyerrlab
+#if defined YYFAIL
+ /* This is here to suppress warnings from the GCC cpp's
+ -Wunused-macros. Normally we don't worry about that warning, but
+ some users do, and we want to make it easy for users to remove
+ YYFAIL uses, which will produce warnings from Bison 2.5. */
+#endif
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+
+
+
+/* This macro is provided for backward compatibility. */
+
+#ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ FILE *yyo = yyoutput;
+ YYUSE (yyo);
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+ yytype_int16 *yybottom;
+ yytype_int16 *yytop;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return 2 if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+ yytype_int16 *yyssp, int yytoken)
+{
+ YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = YY_NULL;
+ /* Arguments of yyformat. */
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ /* Number of reported tokens (one for the "unexpected", one per
+ "expected"). */
+ int yycount = 0;
+
+ /* There are many possibilities here to consider:
+ - Assume YYFAIL is not used. It's too flawed to consider. See
+ <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
+ for details. YYERROR is fine as it does not invoke this
+ function.
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yytoken != YYEMPTY)
+ {
+ int yyn = yypact[*yyssp];
+ yyarg[yycount++] = yytname[yytoken];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
+ if (! (yysize <= yysize1
+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+ }
+ }
+
+ switch (yycount)
+ {
+# define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+ }
+
+ yysize1 = yysize + yystrlen (yyformat);
+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return 1;
+ }
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyformat += 2;
+ }
+ else
+ {
+ yyp++;
+ yyformat++;
+ }
+ }
+ return 0;
+}
+#endif /* YYERROR_VERBOSE */
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+
+
+/* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+ `yyss': related to states.
+ `yyvs': related to semantic values.
+
+ Refer to the stacks through separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
+
+ YYSIZE_T yystacksize;
+
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ yytoken = 0;
+ yyss = yyssa;
+ yyvs = yyvsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+ yyssp = yyss;
+ yyvsp = yyvs;
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yypact_value_is_default (yyn))
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yytable_value_is_error (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 26:
+/* Line 1787 of yacc.c */
+#line 359 "conf_parser.y"
+ { (yyval.number) = 0; }
+ break;
+
+ case 28:
+/* Line 1787 of yacc.c */
+#line 361 "conf_parser.y"
+ {
+ (yyval.number) = (yyvsp[(1) - (2)].number) + (yyvsp[(2) - (2)].number);
+ }
+ break;
+
+ case 29:
+/* Line 1787 of yacc.c */
+#line 365 "conf_parser.y"
+ {
+ (yyval.number) = (yyvsp[(1) - (3)].number) + (yyvsp[(3) - (3)].number);
+ }
+ break;
+
+ case 30:
+/* Line 1787 of yacc.c */
+#line 369 "conf_parser.y"
+ {
+ (yyval.number) = (yyvsp[(1) - (3)].number) * 60 + (yyvsp[(3) - (3)].number);
+ }
+ break;
+
+ case 31:
+/* Line 1787 of yacc.c */
+#line 373 "conf_parser.y"
+ {
+ (yyval.number) = (yyvsp[(1) - (3)].number) * 60 * 60 + (yyvsp[(3) - (3)].number);
+ }
+ break;
+
+ case 32:
+/* Line 1787 of yacc.c */
+#line 377 "conf_parser.y"
+ {
+ (yyval.number) = (yyvsp[(1) - (3)].number) * 60 * 60 * 24 + (yyvsp[(3) - (3)].number);
+ }
+ break;
+
+ case 33:
+/* Line 1787 of yacc.c */
+#line 381 "conf_parser.y"
+ {
+ (yyval.number) = (yyvsp[(1) - (3)].number) * 60 * 60 * 24 * 7 + (yyvsp[(3) - (3)].number);
+ }
+ break;
+
+ case 34:
+/* Line 1787 of yacc.c */
+#line 386 "conf_parser.y"
+ { (yyval.number) = 0; }
+ break;
+
+ case 36:
+/* Line 1787 of yacc.c */
+#line 387 "conf_parser.y"
+ { (yyval.number) = (yyvsp[(1) - (2)].number) + (yyvsp[(2) - (2)].number); }
+ break;
+
+ case 37:
+/* Line 1787 of yacc.c */
+#line 388 "conf_parser.y"
+ { (yyval.number) = (yyvsp[(1) - (3)].number) + (yyvsp[(3) - (3)].number); }
+ break;
+
+ case 38:
+/* Line 1787 of yacc.c */
+#line 389 "conf_parser.y"
+ { (yyval.number) = (yyvsp[(1) - (3)].number) * 1024 + (yyvsp[(3) - (3)].number); }
+ break;
+
+ case 39:
+/* Line 1787 of yacc.c */
+#line 390 "conf_parser.y"
+ { (yyval.number) = (yyvsp[(1) - (3)].number) * 1024 * 1024 + (yyvsp[(3) - (3)].number); }
+ break;
+
+ case 46:
+/* Line 1787 of yacc.c */
+#line 404 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ add_conf_module(libio_basename(yylval.string));
+}
+ break;
+
+ case 47:
+/* Line 1787 of yacc.c */
+#line 410 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ mod_add_path(yylval.string);
+}
+ break;
+
+ case 71:
+/* Line 1787 of yacc.c */
+#line 435 "conf_parser.y"
+ {
+#ifdef HAVE_LIBCRYPTO
+ if (conf_parser_ctx.pass == 2 && ServerInfo.client_ctx)
+ SSL_CTX_clear_options(ServerInfo.client_ctx, SSL_OP_NO_SSLv3);
+#endif
+}
+ break;
+
+ case 72:
+/* Line 1787 of yacc.c */
+#line 441 "conf_parser.y"
+ {
+#ifdef HAVE_LIBCRYPTO
+ if (conf_parser_ctx.pass == 2 && ServerInfo.client_ctx)
+ SSL_CTX_clear_options(ServerInfo.client_ctx, SSL_OP_NO_TLSv1);
+#endif
+}
+ break;
+
+ case 75:
+/* Line 1787 of yacc.c */
+#line 450 "conf_parser.y"
+ {
+#ifdef HAVE_LIBCRYPTO
+ if (conf_parser_ctx.pass == 2 && ServerInfo.server_ctx)
+ SSL_CTX_clear_options(ServerInfo.server_ctx, SSL_OP_NO_SSLv3);
+#endif
+}
+ break;
+
+ case 76:
+/* Line 1787 of yacc.c */
+#line 456 "conf_parser.y"
+ {
+#ifdef HAVE_LIBCRYPTO
+ if (conf_parser_ctx.pass == 2 && ServerInfo.server_ctx)
+ SSL_CTX_clear_options(ServerInfo.server_ctx, SSL_OP_NO_TLSv1);
+#endif
+}
+ break;
+
+ case 77:
+/* Line 1787 of yacc.c */
+#line 464 "conf_parser.y"
+ {
+#ifdef HAVE_LIBCRYPTO
+ if (conf_parser_ctx.pass == 2 && ServerInfo.server_ctx)
+ {
+ if (!ServerInfo.rsa_private_key_file)
+ {
+ yyerror("No rsa_private_key_file specified, SSL disabled");
+ break;
+ }
+
+ if (SSL_CTX_use_certificate_file(ServerInfo.server_ctx, yylval.string,
+ SSL_FILETYPE_PEM) <= 0 ||
+ SSL_CTX_use_certificate_file(ServerInfo.client_ctx, yylval.string,
+ SSL_FILETYPE_PEM) <= 0)
+ {
+ yyerror(ERR_lib_error_string(ERR_get_error()));
+ break;
+ }
+
+ if (SSL_CTX_use_PrivateKey_file(ServerInfo.server_ctx, ServerInfo.rsa_private_key_file,
+ SSL_FILETYPE_PEM) <= 0 ||
+ SSL_CTX_use_PrivateKey_file(ServerInfo.client_ctx, ServerInfo.rsa_private_key_file,
+ SSL_FILETYPE_PEM) <= 0)
+ {
+ yyerror(ERR_lib_error_string(ERR_get_error()));
+ break;
+ }
+
+ if (!SSL_CTX_check_private_key(ServerInfo.server_ctx) ||
+ !SSL_CTX_check_private_key(ServerInfo.client_ctx))
+ {
+ yyerror(ERR_lib_error_string(ERR_get_error()));
+ break;
+ }
+ }
+#endif
+}
+ break;
+
+ case 78:
+/* Line 1787 of yacc.c */
+#line 503 "conf_parser.y"
+ {
+#ifdef HAVE_LIBCRYPTO
+ if (conf_parser_ctx.pass == 1)
+ {
+ BIO *file;
+
+ if (ServerInfo.rsa_private_key)
+ {
+ RSA_free(ServerInfo.rsa_private_key);
+ ServerInfo.rsa_private_key = NULL;
+ }
+
+ if (ServerInfo.rsa_private_key_file)
+ {
+ MyFree(ServerInfo.rsa_private_key_file);
+ ServerInfo.rsa_private_key_file = NULL;
+ }
+
+ DupString(ServerInfo.rsa_private_key_file, yylval.string);
+
+ if ((file = BIO_new_file(yylval.string, "r")) == NULL)
+ {
+ yyerror("File open failed, ignoring");
+ break;
+ }
+
+ ServerInfo.rsa_private_key = PEM_read_bio_RSAPrivateKey(file, NULL, 0, NULL);
+
+ BIO_set_close(file, BIO_CLOSE);
+ BIO_free(file);
+
+ if (ServerInfo.rsa_private_key == NULL)
+ {
+ yyerror("Couldn't extract key, ignoring");
+ break;
+ }
+
+ if (!RSA_check_key(ServerInfo.rsa_private_key))
+ {
+ RSA_free(ServerInfo.rsa_private_key);
+ ServerInfo.rsa_private_key = NULL;
+
+ yyerror("Invalid key, ignoring");
+ break;
+ }
+
+ /* require 2048 bit (256 byte) key */
+ if (RSA_size(ServerInfo.rsa_private_key) != 256)
+ {
+ RSA_free(ServerInfo.rsa_private_key);
+ ServerInfo.rsa_private_key = NULL;
+
+ yyerror("Not a 2048 bit key, ignoring");
+ }
+ }
+#endif
+}
+ break;
+
+ case 79:
+/* Line 1787 of yacc.c */
+#line 562 "conf_parser.y"
+ {
+/* TBD - XXX: error reporting */
+#ifdef HAVE_LIBCRYPTO
+ if (conf_parser_ctx.pass == 2 && ServerInfo.server_ctx)
+ {
+ BIO *file = BIO_new_file(yylval.string, "r");
+
+ if (file)
+ {
+ DH *dh = PEM_read_bio_DHparams(file, NULL, NULL, NULL);
+
+ BIO_free(file);
+
+ if (dh)
+ {
+ if (DH_size(dh) < 128)
+ ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::ssl_dh_param_file -- need at least a 1024 bit DH prime size");
+ else
+ SSL_CTX_set_tmp_dh(ServerInfo.server_ctx, dh);
+
+ DH_free(dh);
+ }
+ }
+ }
+#endif
+}
+ break;
+
+ case 80:
+/* Line 1787 of yacc.c */
+#line 590 "conf_parser.y"
+ {
+#ifdef HAVE_LIBCRYPTO
+ if (conf_parser_ctx.pass == 2 && ServerInfo.server_ctx)
+ SSL_CTX_set_cipher_list(ServerInfo.server_ctx, yylval.string);
+#endif
+}
+ break;
+
+ case 81:
+/* Line 1787 of yacc.c */
+#line 598 "conf_parser.y"
+ {
+ /* this isn't rehashable */
+ if (conf_parser_ctx.pass == 2 && !ServerInfo.name)
+ {
+ if (valid_servname(yylval.string))
+ DupString(ServerInfo.name, yylval.string);
+ else
+ {
+ ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::name -- invalid name. Aborting.");
+ exit(0);
+ }
+ }
+}
+ break;
+
+ case 82:
+/* Line 1787 of yacc.c */
+#line 613 "conf_parser.y"
+ {
+ /* this isn't rehashable */
+ if (conf_parser_ctx.pass == 2 && !ServerInfo.sid)
+ {
+ if (valid_sid(yylval.string))
+ DupString(ServerInfo.sid, yylval.string);
+ else
+ {
+ ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::sid -- invalid SID. Aborting.");
+ exit(0);
+ }
+ }
+}
+ break;
+
+ case 83:
+/* Line 1787 of yacc.c */
+#line 628 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(ServerInfo.description);
+ DupString(ServerInfo.description,yylval.string);
+ }
+}
+ break;
+
+ case 84:
+/* Line 1787 of yacc.c */
+#line 637 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ char *p;
+
+ if ((p = strchr(yylval.string, ' ')) != NULL)
+ p = '\0';
+
+ MyFree(ServerInfo.network_name);
+ DupString(ServerInfo.network_name, yylval.string);
+ }
+}
+ break;
+
+ case 85:
+/* Line 1787 of yacc.c */
+#line 651 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(ServerInfo.network_desc);
+ DupString(ServerInfo.network_desc, yylval.string);
+ }
+}
+ break;
+
+ case 86:
+/* Line 1787 of yacc.c */
+#line 660 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2 && *yylval.string != '*')
+ {
+ struct addrinfo hints, *res;
+
+ memset(&hints, 0, sizeof(hints));
+
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
+
+ if (getaddrinfo(yylval.string, NULL, &hints, &res))
+ ilog(LOG_TYPE_IRCD, "Invalid netmask for server vhost(%s)", yylval.string);
+ else
+ {
+ assert(res != NULL);
+
+ memcpy(&ServerInfo.ip, res->ai_addr, res->ai_addrlen);
+ ServerInfo.ip.ss.ss_family = res->ai_family;
+ ServerInfo.ip.ss_len = res->ai_addrlen;
+ freeaddrinfo(res);
+
+ ServerInfo.specific_ipv4_vhost = 1;
+ }
+ }
+}
+ break;
+
+ case 87:
+/* Line 1787 of yacc.c */
+#line 688 "conf_parser.y"
+ {
+#ifdef IPV6
+ if (conf_parser_ctx.pass == 2 && *yylval.string != '*')
+ {
+ struct addrinfo hints, *res;
+
+ memset(&hints, 0, sizeof(hints));
+
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
+
+ if (getaddrinfo(yylval.string, NULL, &hints, &res))
+ ilog(LOG_TYPE_IRCD, "Invalid netmask for server vhost6(%s)", yylval.string);
+ else
+ {
+ assert(res != NULL);
+
+ memcpy(&ServerInfo.ip6, res->ai_addr, res->ai_addrlen);
+ ServerInfo.ip6.ss.ss_family = res->ai_family;
+ ServerInfo.ip6.ss_len = res->ai_addrlen;
+ freeaddrinfo(res);
+
+ ServerInfo.specific_ipv6_vhost = 1;
+ }
+ }
+#endif
+}
+ break;
+
+ case 88:
+/* Line 1787 of yacc.c */
+#line 718 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ recalc_fdlimit(NULL);
+
+ if ((yyvsp[(3) - (4)].number) < MAXCLIENTS_MIN)
+ {
+ char buf[IRCD_BUFSIZE];
+ ircsprintf(buf, "MAXCLIENTS too low, setting to %d", MAXCLIENTS_MIN);
+ yyerror(buf);
+ }
+ else if ((yyvsp[(3) - (4)].number) > MAXCLIENTS_MAX)
+ {
+ char buf[IRCD_BUFSIZE];
+ ircsprintf(buf, "MAXCLIENTS too high, setting to %d", MAXCLIENTS_MAX);
+ yyerror(buf);
+ }
+ else
+ ServerInfo.max_clients = (yyvsp[(3) - (4)].number);
+ }
+}
+ break;
+
+ case 89:
+/* Line 1787 of yacc.c */
+#line 741 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ ServerInfo.hub = yylval.number;
+}
+ break;
+
+ case 97:
+/* Line 1787 of yacc.c */
+#line 756 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(AdminInfo.name);
+ DupString(AdminInfo.name, yylval.string);
+ }
+}
+ break;
+
+ case 98:
+/* Line 1787 of yacc.c */
+#line 765 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(AdminInfo.email);
+ DupString(AdminInfo.email, yylval.string);
+ }
+}
+ break;
+
+ case 99:
+/* Line 1787 of yacc.c */
+#line 774 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(AdminInfo.description);
+ DupString(AdminInfo.description, yylval.string);
+ }
+}
+ break;
+
+ case 106:
+/* Line 1787 of yacc.c */
+#line 792 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ ConfigLoggingEntry.use_logging = yylval.number;
+}
+ break;
+
+ case 107:
+/* Line 1787 of yacc.c */
+#line 798 "conf_parser.y"
+ {
+ lfile[0] = '\0';
+ ltype = 0;
+ lsize = 0;
+}
+ break;
+
+ case 108:
+/* Line 1787 of yacc.c */
+#line 803 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2 && ltype > 0)
+ log_add_file(ltype, lsize, lfile);
+}
+ break;
+
+ case 115:
+/* Line 1787 of yacc.c */
+#line 815 "conf_parser.y"
+ {
+ strlcpy(lfile, yylval.string, sizeof(lfile));
+}
+ break;
+
+ case 116:
+/* Line 1787 of yacc.c */
+#line 820 "conf_parser.y"
+ {
+ lsize = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 117:
+/* Line 1787 of yacc.c */
+#line 823 "conf_parser.y"
+ {
+ lsize = 0;
+}
+ break;
+
+ case 118:
+/* Line 1787 of yacc.c */
+#line 828 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ ltype = 0;
+}
+ break;
+
+ case 122:
+/* Line 1787 of yacc.c */
+#line 835 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ ltype = LOG_TYPE_USER;
+}
+ break;
+
+ case 123:
+/* Line 1787 of yacc.c */
+#line 839 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ ltype = LOG_TYPE_OPER;
+}
+ break;
+
+ case 124:
+/* Line 1787 of yacc.c */
+#line 843 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ ltype = LOG_TYPE_GLINE;
+}
+ break;
+
+ case 125:
+/* Line 1787 of yacc.c */
+#line 847 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ ltype = LOG_TYPE_DLINE;
+}
+ break;
+
+ case 126:
+/* Line 1787 of yacc.c */
+#line 851 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ ltype = LOG_TYPE_KLINE;
+}
+ break;
+
+ case 127:
+/* Line 1787 of yacc.c */
+#line 855 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ ltype = LOG_TYPE_KILL;
+}
+ break;
+
+ case 128:
+/* Line 1787 of yacc.c */
+#line 859 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ ltype = LOG_TYPE_DEBUG;
+}
+ break;
+
+ case 129:
+/* Line 1787 of yacc.c */
+#line 869 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ yy_conf = make_conf_item(OPER_TYPE);
+ yy_aconf = map_to_conf(yy_conf);
+ SetConfEncrypted(yy_aconf); /* Yes, the default is encrypted */
+ }
+ else
+ {
+ MyFree(class_name);
+ class_name = NULL;
+ }
+}
+ break;
+
+ case 130:
+/* Line 1787 of yacc.c */
+#line 882 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ struct CollectItem *yy_tmp;
+ dlink_node *ptr;
+ dlink_node *next_ptr;
+
+ conf_add_class_to_conf(yy_conf, class_name);
+
+ /* Now, make sure there is a copy of the "base" given oper
+ * block in each of the collected copies
+ */
+
+ DLINK_FOREACH_SAFE(ptr, next_ptr, col_conf_list.head)
+ {
+ struct AccessItem *new_aconf;
+ struct ConfItem *new_conf;
+ yy_tmp = ptr->data;
+
+ new_conf = make_conf_item(OPER_TYPE);
+ new_aconf = (struct AccessItem *)map_to_conf(new_conf);
+
+ new_aconf->flags = yy_aconf->flags;
+
+ if (yy_conf->name != NULL)
+ DupString(new_conf->name, yy_conf->name);
+ if (yy_tmp->user != NULL)
+ DupString(new_aconf->user, yy_tmp->user);
+ else
+ DupString(new_aconf->user, "*");
+ if (yy_tmp->host != NULL)
+ DupString(new_aconf->host, yy_tmp->host);
+ else
+ DupString(new_aconf->host, "*");
+
+ new_aconf->type = parse_netmask(new_aconf->host, &new_aconf->addr,
+ &new_aconf->bits);
+
+ conf_add_class_to_conf(new_conf, class_name);
+ if (yy_aconf->passwd != NULL)
+ DupString(new_aconf->passwd, yy_aconf->passwd);
+
+ new_aconf->port = yy_aconf->port;
+#ifdef HAVE_LIBCRYPTO
+ if (yy_aconf->rsa_public_key_file != NULL)
+ {
+ BIO *file;
+
+ DupString(new_aconf->rsa_public_key_file,
+ yy_aconf->rsa_public_key_file);
+
+ file = BIO_new_file(yy_aconf->rsa_public_key_file, "r");
+ new_aconf->rsa_public_key = PEM_read_bio_RSA_PUBKEY(file,
+ NULL, 0, NULL);
+ BIO_set_close(file, BIO_CLOSE);
+ BIO_free(file);
+ }
+#endif
+
+#ifdef HAVE_LIBCRYPTO
+ if (yy_tmp->name && (yy_tmp->passwd || yy_aconf->rsa_public_key)
+ && yy_tmp->host)
+#else
+ if (yy_tmp->name && yy_tmp->passwd && yy_tmp->host)
+#endif
+ {
+ conf_add_class_to_conf(new_conf, class_name);
+ if (yy_tmp->name != NULL)
+ DupString(new_conf->name, yy_tmp->name);
+ }
+
+ dlinkDelete(&yy_tmp->node, &col_conf_list);
+ free_collect_item(yy_tmp);
+ }
+
+ yy_conf = NULL;
+ yy_aconf = NULL;
+
+
+ MyFree(class_name);
+ class_name = NULL;
+ }
+}
+ break;
+
+ case 142:
+/* Line 1787 of yacc.c */
+#line 972 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(yy_conf->name);
+ DupString(yy_conf->name, yylval.string);
+ }
+}
+ break;
+
+ case 143:
+/* Line 1787 of yacc.c */
+#line 981 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ struct split_nuh_item nuh;
+
+ nuh.nuhmask = yylval.string;
+ nuh.nickptr = NULL;
+ nuh.userptr = userbuf;
+ nuh.hostptr = hostbuf;
+
+ nuh.nicksize = 0;
+ nuh.usersize = sizeof(userbuf);
+ nuh.hostsize = sizeof(hostbuf);
+
+ split_nuh(&nuh);
+
+ if (yy_aconf->user == NULL)
+ {
+ DupString(yy_aconf->user, userbuf);
+ DupString(yy_aconf->host, hostbuf);
+
+ yy_aconf->type = parse_netmask(yy_aconf->host, &yy_aconf->addr,
+ &yy_aconf->bits);
+ }
+ else
+ {
+ struct CollectItem *yy_tmp = MyMalloc(sizeof(struct CollectItem));
+
+ DupString(yy_tmp->user, userbuf);
+ DupString(yy_tmp->host, hostbuf);
+
+ dlinkAdd(yy_tmp, &yy_tmp->node, &col_conf_list);
+ }
+ }
+}
+ break;
+
+ case 144:
+/* Line 1787 of yacc.c */
+#line 1018 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (yy_aconf->passwd != NULL)
+ memset(yy_aconf->passwd, 0, strlen(yy_aconf->passwd));
+
+ MyFree(yy_aconf->passwd);
+ DupString(yy_aconf->passwd, yylval.string);
+ }
+}
+ break;
+
+ case 145:
+/* Line 1787 of yacc.c */
+#line 1030 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (yylval.number)
+ SetConfEncrypted(yy_aconf);
+ else
+ ClearConfEncrypted(yy_aconf);
+ }
+}
+ break;
+
+ case 146:
+/* Line 1787 of yacc.c */
+#line 1041 "conf_parser.y"
+ {
+#ifdef HAVE_LIBCRYPTO
+ if (conf_parser_ctx.pass == 2)
+ {
+ BIO *file;
+
+ if (yy_aconf->rsa_public_key != NULL)
+ {
+ RSA_free(yy_aconf->rsa_public_key);
+ yy_aconf->rsa_public_key = NULL;
+ }
+
+ if (yy_aconf->rsa_public_key_file != NULL)
+ {
+ MyFree(yy_aconf->rsa_public_key_file);
+ yy_aconf->rsa_public_key_file = NULL;
+ }
+
+ DupString(yy_aconf->rsa_public_key_file, yylval.string);
+ file = BIO_new_file(yylval.string, "r");
+
+ if (file == NULL)
+ {
+ yyerror("Ignoring rsa_public_key_file -- file doesn't exist");
+ break;
+ }
+
+ yy_aconf->rsa_public_key = PEM_read_bio_RSA_PUBKEY(file, NULL, 0, NULL);
+
+ if (yy_aconf->rsa_public_key == NULL)
+ {
+ yyerror("Ignoring rsa_public_key_file -- Key invalid; check key syntax.");
+ break;
+ }
+
+ BIO_set_close(file, BIO_CLOSE);
+ BIO_free(file);
+ }
+#endif /* HAVE_LIBCRYPTO */
+}
+ break;
+
+ case 147:
+/* Line 1787 of yacc.c */
+#line 1083 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(class_name);
+ DupString(class_name, yylval.string);
+ }
+}
+ break;
+
+ case 148:
+/* Line 1787 of yacc.c */
+#line 1092 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes = 0;
+}
+ break;
+
+ case 152:
+/* Line 1787 of yacc.c */
+#line 1099 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_BOTS;
+}
+ break;
+
+ case 153:
+/* Line 1787 of yacc.c */
+#line 1103 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_CCONN;
+}
+ break;
+
+ case 154:
+/* Line 1787 of yacc.c */
+#line 1107 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_CCONN_FULL;
+}
+ break;
+
+ case 155:
+/* Line 1787 of yacc.c */
+#line 1111 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_DEAF;
+}
+ break;
+
+ case 156:
+/* Line 1787 of yacc.c */
+#line 1115 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_DEBUG;
+}
+ break;
+
+ case 157:
+/* Line 1787 of yacc.c */
+#line 1119 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_FULL;
+}
+ break;
+
+ case 158:
+/* Line 1787 of yacc.c */
+#line 1123 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_HIDDEN;
+}
+ break;
+
+ case 159:
+/* Line 1787 of yacc.c */
+#line 1127 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_SKILL;
+}
+ break;
+
+ case 160:
+/* Line 1787 of yacc.c */
+#line 1131 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_NCHANGE;
+}
+ break;
+
+ case 161:
+/* Line 1787 of yacc.c */
+#line 1135 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_REJ;
+}
+ break;
+
+ case 162:
+/* Line 1787 of yacc.c */
+#line 1139 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_UNAUTH;
+}
+ break;
+
+ case 163:
+/* Line 1787 of yacc.c */
+#line 1143 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_SPY;
+}
+ break;
+
+ case 164:
+/* Line 1787 of yacc.c */
+#line 1147 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_EXTERNAL;
+}
+ break;
+
+ case 165:
+/* Line 1787 of yacc.c */
+#line 1151 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_OPERWALL;
+}
+ break;
+
+ case 166:
+/* Line 1787 of yacc.c */
+#line 1155 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_SERVNOTICE;
+}
+ break;
+
+ case 167:
+/* Line 1787 of yacc.c */
+#line 1159 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_INVISIBLE;
+}
+ break;
+
+ case 168:
+/* Line 1787 of yacc.c */
+#line 1163 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_WALLOP;
+}
+ break;
+
+ case 169:
+/* Line 1787 of yacc.c */
+#line 1167 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_SOFTCALLERID;
+}
+ break;
+
+ case 170:
+/* Line 1787 of yacc.c */
+#line 1171 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_CALLERID;
+}
+ break;
+
+ case 171:
+/* Line 1787 of yacc.c */
+#line 1175 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_LOCOPS;
+}
+ break;
+
+ case 172:
+/* Line 1787 of yacc.c */
+#line 1181 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port = 0;
+}
+ break;
+
+ case 176:
+/* Line 1787 of yacc.c */
+#line 1188 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_GLOBAL_KILL;
+}
+ break;
+
+ case 177:
+/* Line 1787 of yacc.c */
+#line 1192 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_REMOTE;
+}
+ break;
+
+ case 178:
+/* Line 1787 of yacc.c */
+#line 1196 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_K;
+}
+ break;
+
+ case 179:
+/* Line 1787 of yacc.c */
+#line 1200 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_UNKLINE;
+}
+ break;
+
+ case 180:
+/* Line 1787 of yacc.c */
+#line 1204 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_DLINE;
+}
+ break;
+
+ case 181:
+/* Line 1787 of yacc.c */
+#line 1208 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_UNDLINE;
+}
+ break;
+
+ case 182:
+/* Line 1787 of yacc.c */
+#line 1212 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_X;
+}
+ break;
+
+ case 183:
+/* Line 1787 of yacc.c */
+#line 1216 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_GLINE;
+}
+ break;
+
+ case 184:
+/* Line 1787 of yacc.c */
+#line 1220 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_DIE;
+}
+ break;
+
+ case 185:
+/* Line 1787 of yacc.c */
+#line 1224 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_RESTART;
+}
+ break;
+
+ case 186:
+/* Line 1787 of yacc.c */
+#line 1228 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_REHASH;
+}
+ break;
+
+ case 187:
+/* Line 1787 of yacc.c */
+#line 1232 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_ADMIN;
+}
+ break;
+
+ case 188:
+/* Line 1787 of yacc.c */
+#line 1236 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_N;
+}
+ break;
+
+ case 189:
+/* Line 1787 of yacc.c */
+#line 1240 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_OPERWALL;
+}
+ break;
+
+ case 190:
+/* Line 1787 of yacc.c */
+#line 1244 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_GLOBOPS;
+}
+ break;
+
+ case 191:
+/* Line 1787 of yacc.c */
+#line 1248 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_OPER_SPY;
+}
+ break;
+
+ case 192:
+/* Line 1787 of yacc.c */
+#line 1252 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_REMOTEBAN;
+}
+ break;
+
+ case 193:
+/* Line 1787 of yacc.c */
+#line 1256 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_SET;
+}
+ break;
+
+ case 194:
+/* Line 1787 of yacc.c */
+#line 1260 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_MODULE;
+}
+ break;
+
+ case 195:
+/* Line 1787 of yacc.c */
+#line 1270 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 1)
+ {
+ yy_conf = make_conf_item(CLASS_TYPE);
+ yy_class = map_to_conf(yy_conf);
+ }
+}
+ break;
+
+ case 196:
+/* Line 1787 of yacc.c */
+#line 1277 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 1)
+ {
+ struct ConfItem *cconf = NULL;
+ struct ClassItem *class = NULL;
+
+ if (yy_class_name == NULL)
+ delete_conf_item(yy_conf);
+ else
+ {
+ cconf = find_exact_name_conf(CLASS_TYPE, NULL, yy_class_name, NULL, NULL);
+
+ if (cconf != NULL) /* The class existed already */
+ {
+ int user_count = 0;
+
+ rebuild_cidr_class(cconf, yy_class);
+
+ class = map_to_conf(cconf);
+
+ user_count = class->curr_user_count;
+ memcpy(class, yy_class, sizeof(*class));
+ class->curr_user_count = user_count;
+ class->active = 1;
+
+ delete_conf_item(yy_conf);
+
+ MyFree(cconf->name); /* Allows case change of class name */
+ cconf->name = yy_class_name;
+ }
+ else /* Brand new class */
+ {
+ MyFree(yy_conf->name); /* just in case it was allocated */
+ yy_conf->name = yy_class_name;
+ yy_class->active = 1;
+ }
+ }
+
+ yy_class_name = NULL;
+ }
+}
+ break;
+
+ case 214:
+/* Line 1787 of yacc.c */
+#line 1335 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 1)
+ {
+ MyFree(yy_class_name);
+ DupString(yy_class_name, yylval.string);
+ }
+}
+ break;
+
+ case 215:
+/* Line 1787 of yacc.c */
+#line 1344 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 1)
+ yy_class->ping_freq = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 216:
+/* Line 1787 of yacc.c */
+#line 1350 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 1)
+ yy_class->ping_warning = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 217:
+/* Line 1787 of yacc.c */
+#line 1356 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 1)
+ yy_class->max_perip = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 218:
+/* Line 1787 of yacc.c */
+#line 1362 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 1)
+ yy_class->con_freq = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 219:
+/* Line 1787 of yacc.c */
+#line 1368 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 1)
+ yy_class->max_total = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 220:
+/* Line 1787 of yacc.c */
+#line 1374 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 1)
+ yy_class->max_global = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 221:
+/* Line 1787 of yacc.c */
+#line 1380 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 1)
+ yy_class->max_local = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 222:
+/* Line 1787 of yacc.c */
+#line 1386 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 1)
+ yy_class->max_ident = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 223:
+/* Line 1787 of yacc.c */
+#line 1392 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 1)
+ yy_class->max_sendq = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 224:
+/* Line 1787 of yacc.c */
+#line 1398 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 1)
+ if ((yyvsp[(3) - (4)].number) >= CLIENT_FLOOD_MIN && (yyvsp[(3) - (4)].number) <= CLIENT_FLOOD_MAX)
+ yy_class->max_recvq = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 225:
+/* Line 1787 of yacc.c */
+#line 1405 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 1)
+ yy_class->cidr_bitlen_ipv4 = (yyvsp[(3) - (4)].number) > 32 ? 32 : (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 226:
+/* Line 1787 of yacc.c */
+#line 1411 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 1)
+ yy_class->cidr_bitlen_ipv6 = (yyvsp[(3) - (4)].number) > 128 ? 128 : (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 227:
+/* Line 1787 of yacc.c */
+#line 1417 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 1)
+ yy_class->number_per_cidr = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 228:
+/* Line 1787 of yacc.c */
+#line 1426 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ listener_address = NULL;
+ listener_flags = 0;
+ }
+}
+ break;
+
+ case 229:
+/* Line 1787 of yacc.c */
+#line 1433 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(listener_address);
+ listener_address = NULL;
+ }
+}
+ break;
+
+ case 230:
+/* Line 1787 of yacc.c */
+#line 1442 "conf_parser.y"
+ {
+ listener_flags = 0;
+}
+ break;
+
+ case 234:
+/* Line 1787 of yacc.c */
+#line 1448 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ listener_flags |= LISTENER_SSL;
+}
+ break;
+
+ case 235:
+/* Line 1787 of yacc.c */
+#line 1452 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ listener_flags |= LISTENER_HIDDEN;
+}
+ break;
+
+ case 236:
+/* Line 1787 of yacc.c */
+#line 1456 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ listener_flags |= LISTENER_SERVER;
+}
+ break;
+
+ case 244:
+/* Line 1787 of yacc.c */
+#line 1466 "conf_parser.y"
+ { listener_flags = 0; }
+ break;
+
+ case 248:
+/* Line 1787 of yacc.c */
+#line 1471 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ if ((listener_flags & LISTENER_SSL))
+#ifdef HAVE_LIBCRYPTO
+ if (!ServerInfo.server_ctx)
+#endif
+ {
+ yyerror("SSL not available - port closed");
+ break;
+ }
+ add_listener((yyvsp[(1) - (1)].number), listener_address, listener_flags);
+ }
+}
+ break;
+
+ case 249:
+/* Line 1787 of yacc.c */
+#line 1485 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ int i;
+
+ if ((listener_flags & LISTENER_SSL))
+#ifdef HAVE_LIBCRYPTO
+ if (!ServerInfo.server_ctx)
+#endif
+ {
+ yyerror("SSL not available - port closed");
+ break;
+ }
+
+ for (i = (yyvsp[(1) - (3)].number); i <= (yyvsp[(3) - (3)].number); ++i)
+ add_listener(i, listener_address, listener_flags);
+ }
+}
+ break;
+
+ case 250:
+/* Line 1787 of yacc.c */
+#line 1505 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(listener_address);
+ DupString(listener_address, yylval.string);
+ }
+}
+ break;
+
+ case 251:
+/* Line 1787 of yacc.c */
+#line 1514 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(listener_address);
+ DupString(listener_address, yylval.string);
+ }
+}
+ break;
+
+ case 252:
+/* Line 1787 of yacc.c */
+#line 1526 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ yy_conf = make_conf_item(CLIENT_TYPE);
+ yy_aconf = map_to_conf(yy_conf);
+ }
+ else
+ {
+ MyFree(class_name);
+ class_name = NULL;
+ }
+}
+ break;
+
+ case 253:
+/* Line 1787 of yacc.c */
+#line 1538 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ struct CollectItem *yy_tmp = NULL;
+ dlink_node *ptr = NULL, *next_ptr = NULL;
+
+ if (yy_aconf->user && yy_aconf->host)
+ {
+ conf_add_class_to_conf(yy_conf, class_name);
+ add_conf_by_address(CONF_CLIENT, yy_aconf);
+ }
+ else
+ delete_conf_item(yy_conf);
+
+ /* copy over settings from first struct */
+ DLINK_FOREACH_SAFE(ptr, next_ptr, col_conf_list.head)
+ {
+ struct AccessItem *new_aconf;
+ struct ConfItem *new_conf;
+
+ new_conf = make_conf_item(CLIENT_TYPE);
+ new_aconf = map_to_conf(new_conf);
+
+ yy_tmp = ptr->data;
+
+ assert(yy_tmp->user && yy_tmp->host);
+
+ if (yy_aconf->passwd != NULL)
+ DupString(new_aconf->passwd, yy_aconf->passwd);
+ if (yy_conf->name != NULL)
+ DupString(new_conf->name, yy_conf->name);
+ if (yy_aconf->passwd != NULL)
+ DupString(new_aconf->passwd, yy_aconf->passwd);
+
+ new_aconf->flags = yy_aconf->flags;
+ new_aconf->port = yy_aconf->port;
+
+ DupString(new_aconf->user, yy_tmp->user);
+ collapse(new_aconf->user);
+
+ DupString(new_aconf->host, yy_tmp->host);
+ collapse(new_aconf->host);
+
+ conf_add_class_to_conf(new_conf, class_name);
+ add_conf_by_address(CONF_CLIENT, new_aconf);
+ dlinkDelete(&yy_tmp->node, &col_conf_list);
+ free_collect_item(yy_tmp);
+ }
+
+ MyFree(class_name);
+ class_name = NULL;
+ yy_conf = NULL;
+ yy_aconf = NULL;
+ }
+}
+ break;
+
+ case 265:
+/* Line 1787 of yacc.c */
+#line 1600 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ struct CollectItem *yy_tmp = NULL;
+ struct split_nuh_item nuh;
+
+ nuh.nuhmask = yylval.string;
+ nuh.nickptr = NULL;
+ nuh.userptr = userbuf;
+ nuh.hostptr = hostbuf;
+
+ nuh.nicksize = 0;
+ nuh.usersize = sizeof(userbuf);
+ nuh.hostsize = sizeof(hostbuf);
+
+ split_nuh(&nuh);
+
+ if (yy_aconf->user == NULL)
+ {
+ DupString(yy_aconf->user, userbuf);
+ DupString(yy_aconf->host, hostbuf);
+ }
+ else
+ {
+ yy_tmp = MyMalloc(sizeof(struct CollectItem));
+
+ DupString(yy_tmp->user, userbuf);
+ DupString(yy_tmp->host, hostbuf);
+
+ dlinkAdd(yy_tmp, &yy_tmp->node, &col_conf_list);
+ }
+ }
+}
+ break;
+
+ case 266:
+/* Line 1787 of yacc.c */
+#line 1635 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ /* be paranoid */
+ if (yy_aconf->passwd != NULL)
+ memset(yy_aconf->passwd, 0, strlen(yy_aconf->passwd));
+
+ MyFree(yy_aconf->passwd);
+ DupString(yy_aconf->passwd, yylval.string);
+ }
+}
+ break;
+
+ case 267:
+/* Line 1787 of yacc.c */
+#line 1648 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(class_name);
+ DupString(class_name, yylval.string);
+ }
+}
+ break;
+
+ case 268:
+/* Line 1787 of yacc.c */
+#line 1657 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (yylval.number)
+ SetConfEncrypted(yy_aconf);
+ else
+ ClearConfEncrypted(yy_aconf);
+ }
+}
+ break;
+
+ case 269:
+/* Line 1787 of yacc.c */
+#line 1668 "conf_parser.y"
+ {
+}
+ break;
+
+ case 273:
+/* Line 1787 of yacc.c */
+#line 1673 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->flags |= CONF_FLAGS_SPOOF_NOTICE;
+}
+ break;
+
+ case 274:
+/* Line 1787 of yacc.c */
+#line 1677 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->flags |= CONF_FLAGS_NOLIMIT;
+}
+ break;
+
+ case 275:
+/* Line 1787 of yacc.c */
+#line 1681 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->flags |= CONF_FLAGS_EXEMPTKLINE;
+}
+ break;
+
+ case 276:
+/* Line 1787 of yacc.c */
+#line 1685 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->flags |= CONF_FLAGS_NEED_IDENTD;
+}
+ break;
+
+ case 277:
+/* Line 1787 of yacc.c */
+#line 1689 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->flags |= CONF_FLAGS_CAN_FLOOD;
+}
+ break;
+
+ case 278:
+/* Line 1787 of yacc.c */
+#line 1693 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->flags |= CONF_FLAGS_NO_TILDE;
+}
+ break;
+
+ case 279:
+/* Line 1787 of yacc.c */
+#line 1697 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->flags |= CONF_FLAGS_EXEMPTGLINE;
+}
+ break;
+
+ case 280:
+/* Line 1787 of yacc.c */
+#line 1701 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->flags |= CONF_FLAGS_EXEMPTRESV;
+}
+ break;
+
+ case 281:
+/* Line 1787 of yacc.c */
+#line 1705 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->flags |= CONF_FLAGS_NEED_PASSWORD;
+}
+ break;
+
+ case 282:
+/* Line 1787 of yacc.c */
+#line 1711 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(yy_conf->name);
+
+ if (strlen(yylval.string) <= HOSTLEN && valid_hostname(yylval.string))
+ {
+ DupString(yy_conf->name, yylval.string);
+ yy_aconf->flags |= CONF_FLAGS_SPOOF_IP;
+ }
+ else
+ {
+ ilog(LOG_TYPE_IRCD, "Spoof either is too long or contains invalid characters. Ignoring it.");
+ yy_conf->name = NULL;
+ }
+ }
+}
+ break;
+
+ case 283:
+/* Line 1787 of yacc.c */
+#line 1730 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ yy_aconf->flags |= CONF_FLAGS_REDIR;
+ MyFree(yy_conf->name);
+ DupString(yy_conf->name, yylval.string);
+ }
+}
+ break;
+
+ case 284:
+/* Line 1787 of yacc.c */
+#line 1740 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ yy_aconf->flags |= CONF_FLAGS_REDIR;
+ yy_aconf->port = (yyvsp[(3) - (4)].number);
+ }
+}
+ break;
+
+ case 285:
+/* Line 1787 of yacc.c */
+#line 1753 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(resv_reason);
+ resv_reason = NULL;
+ }
+}
+ break;
+
+ case 286:
+/* Line 1787 of yacc.c */
+#line 1760 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(resv_reason);
+ resv_reason = NULL;
+ }
+}
+ break;
+
+ case 293:
+/* Line 1787 of yacc.c */
+#line 1772 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(resv_reason);
+ DupString(resv_reason, yylval.string);
+ }
+}
+ break;
+
+ case 294:
+/* Line 1787 of yacc.c */
+#line 1781 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (IsChanPrefix(*yylval.string))
+ {
+ char def_reason[] = "No reason";
+
+ create_channel_resv(yylval.string, resv_reason != NULL ? resv_reason : def_reason, 1);
+ }
+ }
+ /* ignore it for now.. but we really should make a warning if
+ * its an erroneous name --fl_ */
+}
+ break;
+
+ case 295:
+/* Line 1787 of yacc.c */
+#line 1796 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ char def_reason[] = "No reason";
+
+ create_nick_resv(yylval.string, resv_reason != NULL ? resv_reason : def_reason, 1);
+ }
+}
+ break;
+
+ case 301:
+/* Line 1787 of yacc.c */
+#line 1814 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (valid_servname(yylval.string))
+ {
+ yy_conf = make_conf_item(SERVICE_TYPE);
+ DupString(yy_conf->name, yylval.string);
+ }
+ }
+}
+ break;
+
+ case 302:
+/* Line 1787 of yacc.c */
+#line 1829 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ yy_conf = make_conf_item(ULINE_TYPE);
+ yy_match_item = map_to_conf(yy_conf);
+ yy_match_item->action = SHARED_ALL;
+ }
+}
+ break;
+
+ case 303:
+/* Line 1787 of yacc.c */
+#line 1837 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ yy_conf = NULL;
+ }
+}
+ break;
+
+ case 310:
+/* Line 1787 of yacc.c */
+#line 1848 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(yy_conf->name);
+ DupString(yy_conf->name, yylval.string);
+ }
+}
+ break;
+
+ case 311:
+/* Line 1787 of yacc.c */
+#line 1857 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ struct split_nuh_item nuh;
+
+ nuh.nuhmask = yylval.string;
+ nuh.nickptr = NULL;
+ nuh.userptr = userbuf;
+ nuh.hostptr = hostbuf;
+
+ nuh.nicksize = 0;
+ nuh.usersize = sizeof(userbuf);
+ nuh.hostsize = sizeof(hostbuf);
+
+ split_nuh(&nuh);
+
+ DupString(yy_match_item->user, userbuf);
+ DupString(yy_match_item->host, hostbuf);
+ }
+}
+ break;
+
+ case 312:
+/* Line 1787 of yacc.c */
+#line 1879 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_match_item->action = 0;
+}
+ break;
+
+ case 316:
+/* Line 1787 of yacc.c */
+#line 1886 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_match_item->action |= SHARED_KLINE;
+}
+ break;
+
+ case 317:
+/* Line 1787 of yacc.c */
+#line 1890 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_match_item->action |= SHARED_UNKLINE;
+}
+ break;
+
+ case 318:
+/* Line 1787 of yacc.c */
+#line 1894 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_match_item->action |= SHARED_DLINE;
+}
+ break;
+
+ case 319:
+/* Line 1787 of yacc.c */
+#line 1898 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_match_item->action |= SHARED_UNDLINE;
+}
+ break;
+
+ case 320:
+/* Line 1787 of yacc.c */
+#line 1902 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_match_item->action |= SHARED_XLINE;
+}
+ break;
+
+ case 321:
+/* Line 1787 of yacc.c */
+#line 1906 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_match_item->action |= SHARED_UNXLINE;
+}
+ break;
+
+ case 322:
+/* Line 1787 of yacc.c */
+#line 1910 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_match_item->action |= SHARED_RESV;
+}
+ break;
+
+ case 323:
+/* Line 1787 of yacc.c */
+#line 1914 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_match_item->action |= SHARED_UNRESV;
+}
+ break;
+
+ case 324:
+/* Line 1787 of yacc.c */
+#line 1918 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_match_item->action |= SHARED_LOCOPS;
+}
+ break;
+
+ case 325:
+/* Line 1787 of yacc.c */
+#line 1922 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_match_item->action = SHARED_ALL;
+}
+ break;
+
+ case 326:
+/* Line 1787 of yacc.c */
+#line 1931 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ yy_conf = make_conf_item(CLUSTER_TYPE);
+ yy_conf->flags = SHARED_ALL;
+ }
+}
+ break;
+
+ case 327:
+/* Line 1787 of yacc.c */
+#line 1938 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (yy_conf->name == NULL)
+ DupString(yy_conf->name, "*");
+ yy_conf = NULL;
+ }
+}
+ break;
+
+ case 333:
+/* Line 1787 of yacc.c */
+#line 1951 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ DupString(yy_conf->name, yylval.string);
+}
+ break;
+
+ case 334:
+/* Line 1787 of yacc.c */
+#line 1957 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_conf->flags = 0;
+}
+ break;
+
+ case 338:
+/* Line 1787 of yacc.c */
+#line 1964 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_conf->flags |= SHARED_KLINE;
+}
+ break;
+
+ case 339:
+/* Line 1787 of yacc.c */
+#line 1968 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_conf->flags |= SHARED_UNKLINE;
+}
+ break;
+
+ case 340:
+/* Line 1787 of yacc.c */
+#line 1972 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_conf->flags |= SHARED_DLINE;
+}
+ break;
+
+ case 341:
+/* Line 1787 of yacc.c */
+#line 1976 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_conf->flags |= SHARED_UNDLINE;
+}
+ break;
+
+ case 342:
+/* Line 1787 of yacc.c */
+#line 1980 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_conf->flags |= SHARED_XLINE;
+}
+ break;
+
+ case 343:
+/* Line 1787 of yacc.c */
+#line 1984 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_conf->flags |= SHARED_UNXLINE;
+}
+ break;
+
+ case 344:
+/* Line 1787 of yacc.c */
+#line 1988 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_conf->flags |= SHARED_RESV;
+}
+ break;
+
+ case 345:
+/* Line 1787 of yacc.c */
+#line 1992 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_conf->flags |= SHARED_UNRESV;
+}
+ break;
+
+ case 346:
+/* Line 1787 of yacc.c */
+#line 1996 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_conf->flags |= SHARED_LOCOPS;
+}
+ break;
+
+ case 347:
+/* Line 1787 of yacc.c */
+#line 2000 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_conf->flags = SHARED_ALL;
+}
+ break;
+
+ case 348:
+/* Line 1787 of yacc.c */
+#line 2009 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ yy_conf = make_conf_item(SERVER_TYPE);
+ yy_aconf = map_to_conf(yy_conf);
+
+ /* defaults */
+ yy_aconf->port = PORTNUM;
+ }
+ else
+ {
+ MyFree(class_name);
+ class_name = NULL;
+ }
+}
+ break;
+
+ case 349:
+/* Line 1787 of yacc.c */
+#line 2024 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (yy_aconf->host && yy_aconf->passwd && yy_aconf->spasswd)
+ {
+ if (conf_add_server(yy_conf, class_name) == -1)
+ delete_conf_item(yy_conf);
+ }
+ else
+ {
+ if (yy_conf->name != NULL)
+ {
+ if (yy_aconf->host == NULL)
+ yyerror("Ignoring connect block -- missing host");
+ else if (!yy_aconf->passwd || !yy_aconf->spasswd)
+ yyerror("Ignoring connect block -- missing password");
+ }
+
+ /* XXX
+ * This fixes a try_connections() core (caused by invalid class_ptr
+ * pointers) reported by metalrock. That's an ugly fix, but there
+ * is currently no better way. The entire config subsystem needs an
+ * rewrite ASAP. make_conf_item() shouldn't really add things onto
+ * a doubly linked list immediately without any sanity checks! -Michael
+ */
+ delete_conf_item(yy_conf);
+ }
+
+ MyFree(class_name);
+ class_name = NULL;
+ yy_conf = NULL;
+ yy_aconf = NULL;
+ }
+}
+ break;
+
+ case 366:
+/* Line 1787 of yacc.c */
+#line 2068 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(yy_conf->name);
+ DupString(yy_conf->name, yylval.string);
+ }
+}
+ break;
+
+ case 367:
+/* Line 1787 of yacc.c */
+#line 2077 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(yy_aconf->host);
+ DupString(yy_aconf->host, yylval.string);
+ }
+}
+ break;
+
+ case 368:
+/* Line 1787 of yacc.c */
+#line 2086 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ struct addrinfo hints, *res;
+
+ memset(&hints, 0, sizeof(hints));
+
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
+
+ if (getaddrinfo(yylval.string, NULL, &hints, &res))
+ ilog(LOG_TYPE_IRCD, "Invalid netmask for server vhost(%s)", yylval.string);
+ else
+ {
+ assert(res != NULL);
+
+ memcpy(&yy_aconf->bind, res->ai_addr, res->ai_addrlen);
+ yy_aconf->bind.ss.ss_family = res->ai_family;
+ yy_aconf->bind.ss_len = res->ai_addrlen;
+ freeaddrinfo(res);
+ }
+ }
+}
+ break;
+
+ case 369:
+/* Line 1787 of yacc.c */
+#line 2112 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ if ((yyvsp[(3) - (4)].string)[0] == ':')
+ yyerror("Server passwords cannot begin with a colon");
+ else if (strchr((yyvsp[(3) - (4)].string), ' ') != NULL)
+ yyerror("Server passwords cannot contain spaces");
+ else {
+ if (yy_aconf->spasswd != NULL)
+ memset(yy_aconf->spasswd, 0, strlen(yy_aconf->spasswd));
+
+ MyFree(yy_aconf->spasswd);
+ DupString(yy_aconf->spasswd, yylval.string);
+ }
+ }
+}
+ break;
+
+ case 370:
+/* Line 1787 of yacc.c */
+#line 2130 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ if ((yyvsp[(3) - (4)].string)[0] == ':')
+ yyerror("Server passwords cannot begin with a colon");
+ else if (strchr((yyvsp[(3) - (4)].string), ' ') != NULL)
+ yyerror("Server passwords cannot contain spaces");
+ else {
+ if (yy_aconf->passwd != NULL)
+ memset(yy_aconf->passwd, 0, strlen(yy_aconf->passwd));
+
+ MyFree(yy_aconf->passwd);
+ DupString(yy_aconf->passwd, yylval.string);
+ }
+ }
+}
+ break;
+
+ case 371:
+/* Line 1787 of yacc.c */
+#line 2148 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 372:
+/* Line 1787 of yacc.c */
+#line 2154 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->aftype = AF_INET;
+}
+ break;
+
+ case 373:
+/* Line 1787 of yacc.c */
+#line 2158 "conf_parser.y"
+ {
+#ifdef IPV6
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->aftype = AF_INET6;
+#endif
+}
+ break;
+
+ case 374:
+/* Line 1787 of yacc.c */
+#line 2166 "conf_parser.y"
+ {
+}
+ break;
+
+ case 378:
+/* Line 1787 of yacc.c */
+#line 2171 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ SetConfAllowAutoConn(yy_aconf);
+}
+ break;
+
+ case 379:
+/* Line 1787 of yacc.c */
+#line 2175 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ SetConfSSL(yy_aconf);
+}
+ break;
+
+ case 380:
+/* Line 1787 of yacc.c */
+#line 2181 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (yylval.number)
+ yy_aconf->flags |= CONF_FLAGS_ENCRYPTED;
+ else
+ yy_aconf->flags &= ~CONF_FLAGS_ENCRYPTED;
+ }
+}
+ break;
+
+ case 381:
+/* Line 1787 of yacc.c */
+#line 2192 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ char *mask;
+
+ DupString(mask, yylval.string);
+ dlinkAdd(mask, make_dlink_node(), &yy_aconf->hub_list);
+ }
+}
+ break;
+
+ case 382:
+/* Line 1787 of yacc.c */
+#line 2203 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ char *mask;
+
+ DupString(mask, yylval.string);
+ dlinkAdd(mask, make_dlink_node(), &yy_aconf->leaf_list);
+ }
+}
+ break;
+
+ case 383:
+/* Line 1787 of yacc.c */
+#line 2214 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(class_name);
+ DupString(class_name, yylval.string);
+ }
+}
+ break;
+
+ case 384:
+/* Line 1787 of yacc.c */
+#line 2223 "conf_parser.y"
+ {
+#ifdef HAVE_LIBCRYPTO
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(yy_aconf->cipher_list);
+ DupString(yy_aconf->cipher_list, yylval.string);
+ }
+#else
+ if (conf_parser_ctx.pass == 2)
+ yyerror("Ignoring connect::ciphers -- no OpenSSL support");
+#endif
+}
+ break;
+
+ case 385:
+/* Line 1787 of yacc.c */
+#line 2241 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ userbuf[0] = hostbuf[0] = reasonbuf[0] = '\0';
+ regex_ban = 0;
+ }
+}
+ break;
+
+ case 386:
+/* Line 1787 of yacc.c */
+#line 2248 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (userbuf[0] && hostbuf[0])
+ {
+ if (regex_ban)
+ {
+#ifdef HAVE_LIBPCRE
+ void *exp_user = NULL;
+ void *exp_host = NULL;
+ const char *errptr = NULL;
+
+ if (!(exp_user = ircd_pcre_compile(userbuf, &errptr)) ||
+ !(exp_host = ircd_pcre_compile(hostbuf, &errptr)))
+ {
+ ilog(LOG_TYPE_IRCD, "Failed to add regular expression based K-Line: %s",
+ errptr);
+ break;
+ }
+
+ yy_aconf = map_to_conf(make_conf_item(RKLINE_TYPE));
+ yy_aconf->regexuser = exp_user;
+ yy_aconf->regexhost = exp_host;
+
+ DupString(yy_aconf->user, userbuf);
+ DupString(yy_aconf->host, hostbuf);
+
+ if (reasonbuf[0])
+ DupString(yy_aconf->reason, reasonbuf);
+ else
+ DupString(yy_aconf->reason, "No reason");
+#else
+ ilog(LOG_TYPE_IRCD, "Failed to add regular expression based K-Line: no PCRE support");
+ break;
+#endif
+ }
+ else
+ {
+ find_and_delete_temporary(userbuf, hostbuf, CONF_KLINE);
+
+ yy_aconf = map_to_conf(make_conf_item(KLINE_TYPE));
+
+ DupString(yy_aconf->user, userbuf);
+ DupString(yy_aconf->host, hostbuf);
+
+ if (reasonbuf[0])
+ DupString(yy_aconf->reason, reasonbuf);
+ else
+ DupString(yy_aconf->reason, "No reason");
+ add_conf_by_address(CONF_KLINE, yy_aconf);
+ }
+ }
+
+ yy_aconf = NULL;
+ }
+}
+ break;
+
+ case 387:
+/* Line 1787 of yacc.c */
+#line 2306 "conf_parser.y"
+ {
+}
+ break;
+
+ case 391:
+/* Line 1787 of yacc.c */
+#line 2311 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ regex_ban = 1;
+}
+ break;
+
+ case 398:
+/* Line 1787 of yacc.c */
+#line 2320 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ struct split_nuh_item nuh;
+
+ nuh.nuhmask = yylval.string;
+ nuh.nickptr = NULL;
+ nuh.userptr = userbuf;
+ nuh.hostptr = hostbuf;
+
+ nuh.nicksize = 0;
+ nuh.usersize = sizeof(userbuf);
+ nuh.hostsize = sizeof(hostbuf);
+
+ split_nuh(&nuh);
+ }
+}
+ break;
+
+ case 399:
+/* Line 1787 of yacc.c */
+#line 2339 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ strlcpy(reasonbuf, yylval.string, sizeof(reasonbuf));
+}
+ break;
+
+ case 400:
+/* Line 1787 of yacc.c */
+#line 2348 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ hostbuf[0] = reasonbuf[0] = '\0';
+}
+ break;
+
+ case 401:
+/* Line 1787 of yacc.c */
+#line 2352 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (hostbuf[0] && parse_netmask(hostbuf, NULL, NULL) != HM_HOST)
+ {
+ find_and_delete_temporary(NULL, hostbuf, CONF_DLINE);
+
+ yy_aconf = map_to_conf(make_conf_item(DLINE_TYPE));
+ DupString(yy_aconf->host, hostbuf);
+
+ if (reasonbuf[0])
+ DupString(yy_aconf->reason, reasonbuf);
+ else
+ DupString(yy_aconf->reason, "No reason");
+ add_conf_by_address(CONF_DLINE, yy_aconf);
+ yy_aconf = NULL;
+ }
+ }
+}
+ break;
+
+ case 407:
+/* Line 1787 of yacc.c */
+#line 2376 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ strlcpy(hostbuf, yylval.string, sizeof(hostbuf));
+}
+ break;
+
+ case 408:
+/* Line 1787 of yacc.c */
+#line 2382 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ strlcpy(reasonbuf, yylval.string, sizeof(reasonbuf));
+}
+ break;
+
+ case 414:
+/* Line 1787 of yacc.c */
+#line 2396 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (yylval.string[0] && parse_netmask(yylval.string, NULL, NULL) != HM_HOST)
+ {
+ yy_aconf = map_to_conf(make_conf_item(EXEMPTDLINE_TYPE));
+ DupString(yy_aconf->host, yylval.string);
+
+ add_conf_by_address(CONF_EXEMPTDLINE, yy_aconf);
+ yy_aconf = NULL;
+ }
+ }
+}
+ break;
+
+ case 415:
+/* Line 1787 of yacc.c */
+#line 2414 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ regex_ban = 0;
+ reasonbuf[0] = gecos_name[0] = '\0';
+ }
+}
+ break;
+
+ case 416:
+/* Line 1787 of yacc.c */
+#line 2421 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (gecos_name[0])
+ {
+ if (regex_ban)
+ {
+#ifdef HAVE_LIBPCRE
+ void *exp_p = NULL;
+ const char *errptr = NULL;
+
+ if (!(exp_p = ircd_pcre_compile(gecos_name, &errptr)))
+ {
+ ilog(LOG_TYPE_IRCD, "Failed to add regular expression based X-Line: %s",
+ errptr);
+ break;
+ }
+
+ yy_conf = make_conf_item(RXLINE_TYPE);
+ yy_conf->regexpname = exp_p;
+#else
+ ilog(LOG_TYPE_IRCD, "Failed to add regular expression based X-Line: no PCRE support");
+ break;
+#endif
+ }
+ else
+ yy_conf = make_conf_item(XLINE_TYPE);
+
+ yy_match_item = map_to_conf(yy_conf);
+ DupString(yy_conf->name, gecos_name);
+
+ if (reasonbuf[0])
+ DupString(yy_match_item->reason, reasonbuf);
+ else
+ DupString(yy_match_item->reason, "No reason");
+ }
+ }
+}
+ break;
+
+ case 417:
+/* Line 1787 of yacc.c */
+#line 2461 "conf_parser.y"
+ {
+}
+ break;
+
+ case 421:
+/* Line 1787 of yacc.c */
+#line 2466 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ regex_ban = 1;
+}
+ break;
+
+ case 428:
+/* Line 1787 of yacc.c */
+#line 2475 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ strlcpy(gecos_name, yylval.string, sizeof(gecos_name));
+}
+ break;
+
+ case 429:
+/* Line 1787 of yacc.c */
+#line 2481 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ strlcpy(reasonbuf, yylval.string, sizeof(reasonbuf));
+}
+ break;
+
+ case 483:
+/* Line 1787 of yacc.c */
+#line 2526 "conf_parser.y"
+ {
+ ConfigFileEntry.max_watch = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 484:
+/* Line 1787 of yacc.c */
+#line 2531 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ ConfigFileEntry.glines = yylval.number;
+}
+ break;
+
+ case 485:
+/* Line 1787 of yacc.c */
+#line 2537 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ ConfigFileEntry.gline_time = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 486:
+/* Line 1787 of yacc.c */
+#line 2543 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ ConfigFileEntry.gline_request_time = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 487:
+/* Line 1787 of yacc.c */
+#line 2549 "conf_parser.y"
+ {
+ ConfigFileEntry.gline_min_cidr = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 488:
+/* Line 1787 of yacc.c */
+#line 2554 "conf_parser.y"
+ {
+ ConfigFileEntry.gline_min_cidr6 = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 489:
+/* Line 1787 of yacc.c */
+#line 2559 "conf_parser.y"
+ {
+ ConfigFileEntry.tkline_expire_notices = yylval.number;
+}
+ break;
+
+ case 490:
+/* Line 1787 of yacc.c */
+#line 2564 "conf_parser.y"
+ {
+ ConfigFileEntry.kill_chase_time_limit = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 491:
+/* Line 1787 of yacc.c */
+#line 2569 "conf_parser.y"
+ {
+ ConfigFileEntry.hide_spoof_ips = yylval.number;
+}
+ break;
+
+ case 492:
+/* Line 1787 of yacc.c */
+#line 2574 "conf_parser.y"
+ {
+ ConfigFileEntry.ignore_bogus_ts = yylval.number;
+}
+ break;
+
+ case 493:
+/* Line 1787 of yacc.c */
+#line 2579 "conf_parser.y"
+ {
+ ConfigFileEntry.disable_remote = yylval.number;
+}
+ break;
+
+ case 494:
+/* Line 1787 of yacc.c */
+#line 2584 "conf_parser.y"
+ {
+ ConfigFileEntry.failed_oper_notice = yylval.number;
+}
+ break;
+
+ case 495:
+/* Line 1787 of yacc.c */
+#line 2589 "conf_parser.y"
+ {
+ ConfigFileEntry.anti_nick_flood = yylval.number;
+}
+ break;
+
+ case 496:
+/* Line 1787 of yacc.c */
+#line 2594 "conf_parser.y"
+ {
+ ConfigFileEntry.max_nick_time = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 497:
+/* Line 1787 of yacc.c */
+#line 2599 "conf_parser.y"
+ {
+ ConfigFileEntry.max_nick_changes = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 498:
+/* Line 1787 of yacc.c */
+#line 2604 "conf_parser.y"
+ {
+ ConfigFileEntry.max_accept = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 499:
+/* Line 1787 of yacc.c */
+#line 2609 "conf_parser.y"
+ {
+ ConfigFileEntry.anti_spam_exit_message_time = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 500:
+/* Line 1787 of yacc.c */
+#line 2614 "conf_parser.y"
+ {
+ ConfigFileEntry.ts_warn_delta = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 501:
+/* Line 1787 of yacc.c */
+#line 2619 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ ConfigFileEntry.ts_max_delta = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 502:
+/* Line 1787 of yacc.c */
+#line 2625 "conf_parser.y"
+ {
+ if (((yyvsp[(3) - (4)].number) > 0) && conf_parser_ctx.pass == 1)
+ {
+ ilog(LOG_TYPE_IRCD, "You haven't read your config file properly.");
+ ilog(LOG_TYPE_IRCD, "There is a line in the example conf that will kill your server if not removed.");
+ ilog(LOG_TYPE_IRCD, "Consider actually reading/editing the conf file, and removing this line.");
+ exit(0);
+ }
+}
+ break;
+
+ case 503:
+/* Line 1787 of yacc.c */
+#line 2636 "conf_parser.y"
+ {
+ ConfigFileEntry.invisible_on_connect = yylval.number;
+}
+ break;
+
+ case 504:
+/* Line 1787 of yacc.c */
+#line 2641 "conf_parser.y"
+ {
+ ConfigFileEntry.warn_no_nline = yylval.number;
+}
+ break;
+
+ case 505:
+/* Line 1787 of yacc.c */
+#line 2646 "conf_parser.y"
+ {
+ ConfigFileEntry.stats_e_disabled = yylval.number;
+}
+ break;
+
+ case 506:
+/* Line 1787 of yacc.c */
+#line 2651 "conf_parser.y"
+ {
+ ConfigFileEntry.stats_o_oper_only = yylval.number;
+}
+ break;
+
+ case 507:
+/* Line 1787 of yacc.c */
+#line 2656 "conf_parser.y"
+ {
+ ConfigFileEntry.stats_P_oper_only = yylval.number;
+}
+ break;
+
+ case 508:
+/* Line 1787 of yacc.c */
+#line 2661 "conf_parser.y"
+ {
+ ConfigFileEntry.stats_k_oper_only = 2 * yylval.number;
+}
+ break;
+
+ case 509:
+/* Line 1787 of yacc.c */
+#line 2664 "conf_parser.y"
+ {
+ ConfigFileEntry.stats_k_oper_only = 1;
+}
+ break;
+
+ case 510:
+/* Line 1787 of yacc.c */
+#line 2669 "conf_parser.y"
+ {
+ ConfigFileEntry.stats_i_oper_only = 2 * yylval.number;
+}
+ break;
+
+ case 511:
+/* Line 1787 of yacc.c */
+#line 2672 "conf_parser.y"
+ {
+ ConfigFileEntry.stats_i_oper_only = 1;
+}
+ break;
+
+ case 512:
+/* Line 1787 of yacc.c */
+#line 2677 "conf_parser.y"
+ {
+ ConfigFileEntry.pace_wait = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 513:
+/* Line 1787 of yacc.c */
+#line 2682 "conf_parser.y"
+ {
+ ConfigFileEntry.caller_id_wait = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 514:
+/* Line 1787 of yacc.c */
+#line 2687 "conf_parser.y"
+ {
+ ConfigFileEntry.opers_bypass_callerid = yylval.number;
+}
+ break;
+
+ case 515:
+/* Line 1787 of yacc.c */
+#line 2692 "conf_parser.y"
+ {
+ ConfigFileEntry.pace_wait_simple = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 516:
+/* Line 1787 of yacc.c */
+#line 2697 "conf_parser.y"
+ {
+ ConfigFileEntry.short_motd = yylval.number;
+}
+ break;
+
+ case 517:
+/* Line 1787 of yacc.c */
+#line 2702 "conf_parser.y"
+ {
+ ConfigFileEntry.no_oper_flood = yylval.number;
+}
+ break;
+
+ case 518:
+/* Line 1787 of yacc.c */
+#line 2707 "conf_parser.y"
+ {
+ ConfigFileEntry.true_no_oper_flood = yylval.number;
+}
+ break;
+
+ case 519:
+/* Line 1787 of yacc.c */
+#line 2712 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_pass_resv = yylval.number;
+}
+ break;
+
+ case 520:
+/* Line 1787 of yacc.c */
+#line 2717 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (strlen(yylval.string) > LOCALE_LENGTH-2)
+ yylval.string[LOCALE_LENGTH-1] = '\0';
+
+ set_locale(yylval.string);
+ }
+}
+ break;
+
+ case 521:
+/* Line 1787 of yacc.c */
+#line 2728 "conf_parser.y"
+ {
+ ConfigFileEntry.dots_in_ident = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 522:
+/* Line 1787 of yacc.c */
+#line 2733 "conf_parser.y"
+ {
+ ConfigFileEntry.max_targets = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 523:
+/* Line 1787 of yacc.c */
+#line 2738 "conf_parser.y"
+ {
+ ConfigFileEntry.use_egd = yylval.number;
+}
+ break;
+
+ case 524:
+/* Line 1787 of yacc.c */
+#line 2743 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(ConfigFileEntry.egdpool_path);
+ DupString(ConfigFileEntry.egdpool_path, yylval.string);
+ }
+}
+ break;
+
+ case 525:
+/* Line 1787 of yacc.c */
+#line 2752 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2 && valid_servname(yylval.string))
+ {
+ MyFree(ConfigFileEntry.service_name);
+ DupString(ConfigFileEntry.service_name, yylval.string);
+ }
+}
+ break;
+
+ case 526:
+/* Line 1787 of yacc.c */
+#line 2761 "conf_parser.y"
+ {
+ ConfigFileEntry.ping_cookie = yylval.number;
+}
+ break;
+
+ case 527:
+/* Line 1787 of yacc.c */
+#line 2766 "conf_parser.y"
+ {
+ ConfigFileEntry.disable_auth = yylval.number;
+}
+ break;
+
+ case 528:
+/* Line 1787 of yacc.c */
+#line 2771 "conf_parser.y"
+ {
+ ConfigFileEntry.throttle_time = yylval.number;
+}
+ break;
+
+ case 529:
+/* Line 1787 of yacc.c */
+#line 2776 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_umodes = 0;
+}
+ break;
+
+ case 533:
+/* Line 1787 of yacc.c */
+#line 2782 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_umodes |= UMODE_BOTS;
+}
+ break;
+
+ case 534:
+/* Line 1787 of yacc.c */
+#line 2785 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_umodes |= UMODE_CCONN;
+}
+ break;
+
+ case 535:
+/* Line 1787 of yacc.c */
+#line 2788 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_umodes |= UMODE_CCONN_FULL;
+}
+ break;
+
+ case 536:
+/* Line 1787 of yacc.c */
+#line 2791 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_umodes |= UMODE_DEAF;
+}
+ break;
+
+ case 537:
+/* Line 1787 of yacc.c */
+#line 2794 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_umodes |= UMODE_DEBUG;
+}
+ break;
+
+ case 538:
+/* Line 1787 of yacc.c */
+#line 2797 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_umodes |= UMODE_FULL;
+}
+ break;
+
+ case 539:
+/* Line 1787 of yacc.c */
+#line 2800 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_umodes |= UMODE_HIDDEN;
+}
+ break;
+
+ case 540:
+/* Line 1787 of yacc.c */
+#line 2803 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_umodes |= UMODE_SKILL;
+}
+ break;
+
+ case 541:
+/* Line 1787 of yacc.c */
+#line 2806 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_umodes |= UMODE_NCHANGE;
+}
+ break;
+
+ case 542:
+/* Line 1787 of yacc.c */
+#line 2809 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_umodes |= UMODE_REJ;
+}
+ break;
+
+ case 543:
+/* Line 1787 of yacc.c */
+#line 2812 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_umodes |= UMODE_UNAUTH;
+}
+ break;
+
+ case 544:
+/* Line 1787 of yacc.c */
+#line 2815 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_umodes |= UMODE_SPY;
+}
+ break;
+
+ case 545:
+/* Line 1787 of yacc.c */
+#line 2818 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_umodes |= UMODE_EXTERNAL;
+}
+ break;
+
+ case 546:
+/* Line 1787 of yacc.c */
+#line 2821 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_umodes |= UMODE_OPERWALL;
+}
+ break;
+
+ case 547:
+/* Line 1787 of yacc.c */
+#line 2824 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_umodes |= UMODE_SERVNOTICE;
+}
+ break;
+
+ case 548:
+/* Line 1787 of yacc.c */
+#line 2827 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_umodes |= UMODE_INVISIBLE;
+}
+ break;
+
+ case 549:
+/* Line 1787 of yacc.c */
+#line 2830 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_umodes |= UMODE_WALLOP;
+}
+ break;
+
+ case 550:
+/* Line 1787 of yacc.c */
+#line 2833 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_umodes |= UMODE_SOFTCALLERID;
+}
+ break;
+
+ case 551:
+/* Line 1787 of yacc.c */
+#line 2836 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_umodes |= UMODE_CALLERID;
+}
+ break;
+
+ case 552:
+/* Line 1787 of yacc.c */
+#line 2839 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_umodes |= UMODE_LOCOPS;
+}
+ break;
+
+ case 553:
+/* Line 1787 of yacc.c */
+#line 2844 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_only_umodes = 0;
+}
+ break;
+
+ case 557:
+/* Line 1787 of yacc.c */
+#line 2850 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_only_umodes |= UMODE_BOTS;
+}
+ break;
+
+ case 558:
+/* Line 1787 of yacc.c */
+#line 2853 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_only_umodes |= UMODE_CCONN;
+}
+ break;
+
+ case 559:
+/* Line 1787 of yacc.c */
+#line 2856 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_only_umodes |= UMODE_CCONN_FULL;
+}
+ break;
+
+ case 560:
+/* Line 1787 of yacc.c */
+#line 2859 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_only_umodes |= UMODE_DEAF;
+}
+ break;
+
+ case 561:
+/* Line 1787 of yacc.c */
+#line 2862 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_only_umodes |= UMODE_DEBUG;
+}
+ break;
+
+ case 562:
+/* Line 1787 of yacc.c */
+#line 2865 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_only_umodes |= UMODE_FULL;
+}
+ break;
+
+ case 563:
+/* Line 1787 of yacc.c */
+#line 2868 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_only_umodes |= UMODE_SKILL;
+}
+ break;
+
+ case 564:
+/* Line 1787 of yacc.c */
+#line 2871 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_only_umodes |= UMODE_HIDDEN;
+}
+ break;
+
+ case 565:
+/* Line 1787 of yacc.c */
+#line 2874 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_only_umodes |= UMODE_NCHANGE;
+}
+ break;
+
+ case 566:
+/* Line 1787 of yacc.c */
+#line 2877 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_only_umodes |= UMODE_REJ;
+}
+ break;
+
+ case 567:
+/* Line 1787 of yacc.c */
+#line 2880 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_only_umodes |= UMODE_UNAUTH;
+}
+ break;
+
+ case 568:
+/* Line 1787 of yacc.c */
+#line 2883 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_only_umodes |= UMODE_SPY;
+}
+ break;
+
+ case 569:
+/* Line 1787 of yacc.c */
+#line 2886 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_only_umodes |= UMODE_EXTERNAL;
+}
+ break;
+
+ case 570:
+/* Line 1787 of yacc.c */
+#line 2889 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_only_umodes |= UMODE_OPERWALL;
+}
+ break;
+
+ case 571:
+/* Line 1787 of yacc.c */
+#line 2892 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_only_umodes |= UMODE_SERVNOTICE;
+}
+ break;
+
+ case 572:
+/* Line 1787 of yacc.c */
+#line 2895 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_only_umodes |= UMODE_INVISIBLE;
+}
+ break;
+
+ case 573:
+/* Line 1787 of yacc.c */
+#line 2898 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_only_umodes |= UMODE_WALLOP;
+}
+ break;
+
+ case 574:
+/* Line 1787 of yacc.c */
+#line 2901 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_only_umodes |= UMODE_SOFTCALLERID;
+}
+ break;
+
+ case 575:
+/* Line 1787 of yacc.c */
+#line 2904 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_only_umodes |= UMODE_CALLERID;
+}
+ break;
+
+ case 576:
+/* Line 1787 of yacc.c */
+#line 2907 "conf_parser.y"
+ {
+ ConfigFileEntry.oper_only_umodes |= UMODE_LOCOPS;
+}
+ break;
+
+ case 577:
+/* Line 1787 of yacc.c */
+#line 2912 "conf_parser.y"
+ {
+ ConfigFileEntry.min_nonwildcard = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 578:
+/* Line 1787 of yacc.c */
+#line 2917 "conf_parser.y"
+ {
+ ConfigFileEntry.min_nonwildcard_simple = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 579:
+/* Line 1787 of yacc.c */
+#line 2922 "conf_parser.y"
+ {
+ ConfigFileEntry.default_floodcount = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 598:
+/* Line 1787 of yacc.c */
+#line 2945 "conf_parser.y"
+ {
+ ConfigChannel.disable_fake_channels = yylval.number;
+}
+ break;
+
+ case 599:
+/* Line 1787 of yacc.c */
+#line 2950 "conf_parser.y"
+ {
+ ConfigChannel.restrict_channels = yylval.number;
+}
+ break;
+
+ case 600:
+/* Line 1787 of yacc.c */
+#line 2955 "conf_parser.y"
+ {
+ ConfigChannel.knock_delay = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 601:
+/* Line 1787 of yacc.c */
+#line 2960 "conf_parser.y"
+ {
+ ConfigChannel.knock_delay_channel = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 602:
+/* Line 1787 of yacc.c */
+#line 2965 "conf_parser.y"
+ {
+ ConfigChannel.max_chans_per_user = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 603:
+/* Line 1787 of yacc.c */
+#line 2970 "conf_parser.y"
+ {
+ ConfigChannel.max_chans_per_oper = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 604:
+/* Line 1787 of yacc.c */
+#line 2975 "conf_parser.y"
+ {
+ ConfigChannel.quiet_on_ban = yylval.number;
+}
+ break;
+
+ case 605:
+/* Line 1787 of yacc.c */
+#line 2980 "conf_parser.y"
+ {
+ ConfigChannel.max_bans = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 606:
+/* Line 1787 of yacc.c */
+#line 2985 "conf_parser.y"
+ {
+ ConfigChannel.default_split_user_count = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 607:
+/* Line 1787 of yacc.c */
+#line 2990 "conf_parser.y"
+ {
+ ConfigChannel.default_split_server_count = (yyvsp[(3) - (4)].number);
+}
+ break;
+
+ case 608:
+/* Line 1787 of yacc.c */
+#line 2995 "conf_parser.y"
+ {
+ ConfigChannel.no_create_on_split = yylval.number;
+}
+ break;
+
+ case 609:
+/* Line 1787 of yacc.c */
+#line 3000 "conf_parser.y"
+ {
+ ConfigChannel.no_join_on_split = yylval.number;
+}
+ break;
+
+ case 610:
+/* Line 1787 of yacc.c */
+#line 3005 "conf_parser.y"
+ {
+ GlobalSetOptions.joinfloodcount = yylval.number;
+}
+ break;
+
+ case 611:
+/* Line 1787 of yacc.c */
+#line 3010 "conf_parser.y"
+ {
+ GlobalSetOptions.joinfloodtime = yylval.number;
+}
+ break;
+
+ case 622:
+/* Line 1787 of yacc.c */
+#line 3028 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ ConfigServerHide.flatten_links = yylval.number;
+}
+ break;
+
+ case 623:
+/* Line 1787 of yacc.c */
+#line 3034 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ ConfigServerHide.hide_servers = yylval.number;
+}
+ break;
+
+ case 624:
+/* Line 1787 of yacc.c */
+#line 3040 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(ConfigServerHide.hidden_name);
+ DupString(ConfigServerHide.hidden_name, yylval.string);
+ }
+}
+ break;
+
+ case 625:
+/* Line 1787 of yacc.c */
+#line 3049 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (((yyvsp[(3) - (4)].number) > 0) && ConfigServerHide.links_disabled == 1)
+ {
+ eventAddIsh("write_links_file", write_links_file, NULL, (yyvsp[(3) - (4)].number));
+ ConfigServerHide.links_disabled = 0;
+ }
+
+ ConfigServerHide.links_delay = (yyvsp[(3) - (4)].number);
+ }
+}
+ break;
+
+ case 626:
+/* Line 1787 of yacc.c */
+#line 3063 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ ConfigServerHide.hidden = yylval.number;
+}
+ break;
+
+ case 627:
+/* Line 1787 of yacc.c */
+#line 3069 "conf_parser.y"
+ {
+ if (conf_parser_ctx.pass == 2)
+ ConfigServerHide.hide_server_ips = yylval.number;
+}
+ break;
+
+
+/* Line 1787 of yacc.c */
+#line 6844 "conf_parser.c"
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+ yyssp, yytoken)
+ {
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == 1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+ if (!yymsg)
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = 2;
+ }
+ else
+ {
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ yymsgp = yymsg;
+ }
+ }
+ yyerror (yymsgp);
+ if (yysyntax_error_status == 2)
+ goto yyexhaustedlab;
+ }
+# undef YYSYNTAX_ERROR
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#if !defined yyoverflow || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEMPTY)
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ }
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
diff --git a/src/conf_parser.h b/src/conf_parser.h
new file mode 100644
index 0000000..89bb943
--- /dev/null
+++ b/src/conf_parser.h
@@ -0,0 +1,513 @@
+/* A Bison parser, made by GNU Bison 2.6.2. */
+
+/* Bison interface for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+#ifndef YY_Y_TAB_H
+# define YY_Y_TAB_H
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ ACCEPT_PASSWORD = 258,
+ ADMIN = 259,
+ AFTYPE = 260,
+ ANTI_NICK_FLOOD = 261,
+ ANTI_SPAM_EXIT_MESSAGE_TIME = 262,
+ AUTOCONN = 263,
+ BYTES = 264,
+ KBYTES = 265,
+ MBYTES = 266,
+ CALLER_ID_WAIT = 267,
+ CAN_FLOOD = 268,
+ CHANNEL = 269,
+ CIDR_BITLEN_IPV4 = 270,
+ CIDR_BITLEN_IPV6 = 271,
+ CLASS = 272,
+ CONNECT = 273,
+ CONNECTFREQ = 274,
+ DEFAULT_FLOODCOUNT = 275,
+ DEFAULT_SPLIT_SERVER_COUNT = 276,
+ DEFAULT_SPLIT_USER_COUNT = 277,
+ DENY = 278,
+ DESCRIPTION = 279,
+ DIE = 280,
+ DISABLE_AUTH = 281,
+ DISABLE_FAKE_CHANNELS = 282,
+ DISABLE_REMOTE_COMMANDS = 283,
+ DOTS_IN_IDENT = 284,
+ EGDPOOL_PATH = 285,
+ EMAIL = 286,
+ ENCRYPTED = 287,
+ EXCEED_LIMIT = 288,
+ EXEMPT = 289,
+ FAILED_OPER_NOTICE = 290,
+ IRCD_FLAGS = 291,
+ FLATTEN_LINKS = 292,
+ GECOS = 293,
+ GENERAL = 294,
+ GLINE = 295,
+ GLINE_DURATION = 296,
+ GLINE_ENABLE = 297,
+ GLINE_EXEMPT = 298,
+ GLINE_REQUEST_DURATION = 299,
+ GLINE_MIN_CIDR = 300,
+ GLINE_MIN_CIDR6 = 301,
+ GLOBAL_KILL = 302,
+ IRCD_AUTH = 303,
+ NEED_IDENT = 304,
+ HAVENT_READ_CONF = 305,
+ HIDDEN = 306,
+ HIDDEN_NAME = 307,
+ HIDE_SERVER_IPS = 308,
+ HIDE_SERVERS = 309,
+ HIDE_SPOOF_IPS = 310,
+ HOST = 311,
+ HUB = 312,
+ HUB_MASK = 313,
+ IGNORE_BOGUS_TS = 314,
+ INVISIBLE_ON_CONNECT = 315,
+ IP = 316,
+ KILL = 317,
+ KILL_CHASE_TIME_LIMIT = 318,
+ KLINE = 319,
+ KLINE_EXEMPT = 320,
+ KNOCK_DELAY = 321,
+ KNOCK_DELAY_CHANNEL = 322,
+ LEAF_MASK = 323,
+ LINKS_DELAY = 324,
+ LISTEN = 325,
+ T_LOG = 326,
+ MAX_ACCEPT = 327,
+ MAX_BANS = 328,
+ MAX_CHANS_PER_OPER = 329,
+ MAX_CHANS_PER_USER = 330,
+ MAX_GLOBAL = 331,
+ MAX_IDENT = 332,
+ MAX_LOCAL = 333,
+ MAX_NICK_CHANGES = 334,
+ MAX_NICK_TIME = 335,
+ MAX_NUMBER = 336,
+ MAX_TARGETS = 337,
+ MAX_WATCH = 338,
+ MESSAGE_LOCALE = 339,
+ MIN_NONWILDCARD = 340,
+ MIN_NONWILDCARD_SIMPLE = 341,
+ MODULE = 342,
+ MODULES = 343,
+ NAME = 344,
+ NEED_PASSWORD = 345,
+ NETWORK_DESC = 346,
+ NETWORK_NAME = 347,
+ NICK = 348,
+ NICK_CHANGES = 349,
+ NO_CREATE_ON_SPLIT = 350,
+ NO_JOIN_ON_SPLIT = 351,
+ NO_OPER_FLOOD = 352,
+ NO_TILDE = 353,
+ NUMBER = 354,
+ NUMBER_PER_CIDR = 355,
+ NUMBER_PER_IP = 356,
+ OPERATOR = 357,
+ OPERS_BYPASS_CALLERID = 358,
+ OPER_ONLY_UMODES = 359,
+ OPER_PASS_RESV = 360,
+ OPER_SPY_T = 361,
+ OPER_UMODES = 362,
+ JOIN_FLOOD_COUNT = 363,
+ JOIN_FLOOD_TIME = 364,
+ PACE_WAIT = 365,
+ PACE_WAIT_SIMPLE = 366,
+ PASSWORD = 367,
+ PATH = 368,
+ PING_COOKIE = 369,
+ PING_TIME = 370,
+ PING_WARNING = 371,
+ PORT = 372,
+ QSTRING = 373,
+ QUIET_ON_BAN = 374,
+ REASON = 375,
+ REDIRPORT = 376,
+ REDIRSERV = 377,
+ REGEX_T = 378,
+ REHASH = 379,
+ REMOTE = 380,
+ REMOTEBAN = 381,
+ RESTRICT_CHANNELS = 382,
+ RSA_PRIVATE_KEY_FILE = 383,
+ RSA_PUBLIC_KEY_FILE = 384,
+ SSL_CERTIFICATE_FILE = 385,
+ SSL_DH_PARAM_FILE = 386,
+ T_SSL_CLIENT_METHOD = 387,
+ T_SSL_SERVER_METHOD = 388,
+ T_SSLV3 = 389,
+ T_TLSV1 = 390,
+ RESV = 391,
+ RESV_EXEMPT = 392,
+ SECONDS = 393,
+ MINUTES = 394,
+ HOURS = 395,
+ DAYS = 396,
+ WEEKS = 397,
+ SENDQ = 398,
+ SEND_PASSWORD = 399,
+ SERVERHIDE = 400,
+ SERVERINFO = 401,
+ IRCD_SID = 402,
+ TKLINE_EXPIRE_NOTICES = 403,
+ T_SHARED = 404,
+ T_CLUSTER = 405,
+ TYPE = 406,
+ SHORT_MOTD = 407,
+ SPOOF = 408,
+ SPOOF_NOTICE = 409,
+ STATS_E_DISABLED = 410,
+ STATS_I_OPER_ONLY = 411,
+ STATS_K_OPER_ONLY = 412,
+ STATS_O_OPER_ONLY = 413,
+ STATS_P_OPER_ONLY = 414,
+ TBOOL = 415,
+ TMASKED = 416,
+ TS_MAX_DELTA = 417,
+ TS_WARN_DELTA = 418,
+ TWODOTS = 419,
+ T_ALL = 420,
+ T_BOTS = 421,
+ T_SOFTCALLERID = 422,
+ T_CALLERID = 423,
+ T_CCONN = 424,
+ T_CCONN_FULL = 425,
+ T_SSL_CIPHER_LIST = 426,
+ T_DEAF = 427,
+ T_DEBUG = 428,
+ T_DLINE = 429,
+ T_EXTERNAL = 430,
+ T_FULL = 431,
+ T_INVISIBLE = 432,
+ T_IPV4 = 433,
+ T_IPV6 = 434,
+ T_LOCOPS = 435,
+ T_MAX_CLIENTS = 436,
+ T_NCHANGE = 437,
+ T_OPERWALL = 438,
+ T_RECVQ = 439,
+ T_REJ = 440,
+ T_SERVER = 441,
+ T_SERVNOTICE = 442,
+ T_SET = 443,
+ T_SKILL = 444,
+ T_SPY = 445,
+ T_SSL = 446,
+ T_UMODES = 447,
+ T_UNAUTH = 448,
+ T_UNDLINE = 449,
+ T_UNLIMITED = 450,
+ T_UNRESV = 451,
+ T_UNXLINE = 452,
+ T_GLOBOPS = 453,
+ T_WALLOP = 454,
+ T_RESTART = 455,
+ T_SERVICE = 456,
+ T_SERVICES_NAME = 457,
+ THROTTLE_TIME = 458,
+ TRUE_NO_OPER_FLOOD = 459,
+ UNKLINE = 460,
+ USER = 461,
+ USE_EGD = 462,
+ USE_LOGGING = 463,
+ VHOST = 464,
+ VHOST6 = 465,
+ XLINE = 466,
+ WARN_NO_NLINE = 467,
+ T_SIZE = 468,
+ T_FILE = 469
+ };
+#endif
+/* Tokens. */
+#define ACCEPT_PASSWORD 258
+#define ADMIN 259
+#define AFTYPE 260
+#define ANTI_NICK_FLOOD 261
+#define ANTI_SPAM_EXIT_MESSAGE_TIME 262
+#define AUTOCONN 263
+#define BYTES 264
+#define KBYTES 265
+#define MBYTES 266
+#define CALLER_ID_WAIT 267
+#define CAN_FLOOD 268
+#define CHANNEL 269
+#define CIDR_BITLEN_IPV4 270
+#define CIDR_BITLEN_IPV6 271
+#define CLASS 272
+#define CONNECT 273
+#define CONNECTFREQ 274
+#define DEFAULT_FLOODCOUNT 275
+#define DEFAULT_SPLIT_SERVER_COUNT 276
+#define DEFAULT_SPLIT_USER_COUNT 277
+#define DENY 278
+#define DESCRIPTION 279
+#define DIE 280
+#define DISABLE_AUTH 281
+#define DISABLE_FAKE_CHANNELS 282
+#define DISABLE_REMOTE_COMMANDS 283
+#define DOTS_IN_IDENT 284
+#define EGDPOOL_PATH 285
+#define EMAIL 286
+#define ENCRYPTED 287
+#define EXCEED_LIMIT 288
+#define EXEMPT 289
+#define FAILED_OPER_NOTICE 290
+#define IRCD_FLAGS 291
+#define FLATTEN_LINKS 292
+#define GECOS 293
+#define GENERAL 294
+#define GLINE 295
+#define GLINE_DURATION 296
+#define GLINE_ENABLE 297
+#define GLINE_EXEMPT 298
+#define GLINE_REQUEST_DURATION 299
+#define GLINE_MIN_CIDR 300
+#define GLINE_MIN_CIDR6 301
+#define GLOBAL_KILL 302
+#define IRCD_AUTH 303
+#define NEED_IDENT 304
+#define HAVENT_READ_CONF 305
+#define HIDDEN 306
+#define HIDDEN_NAME 307
+#define HIDE_SERVER_IPS 308
+#define HIDE_SERVERS 309
+#define HIDE_SPOOF_IPS 310
+#define HOST 311
+#define HUB 312
+#define HUB_MASK 313
+#define IGNORE_BOGUS_TS 314
+#define INVISIBLE_ON_CONNECT 315
+#define IP 316
+#define KILL 317
+#define KILL_CHASE_TIME_LIMIT 318
+#define KLINE 319
+#define KLINE_EXEMPT 320
+#define KNOCK_DELAY 321
+#define KNOCK_DELAY_CHANNEL 322
+#define LEAF_MASK 323
+#define LINKS_DELAY 324
+#define LISTEN 325
+#define T_LOG 326
+#define MAX_ACCEPT 327
+#define MAX_BANS 328
+#define MAX_CHANS_PER_OPER 329
+#define MAX_CHANS_PER_USER 330
+#define MAX_GLOBAL 331
+#define MAX_IDENT 332
+#define MAX_LOCAL 333
+#define MAX_NICK_CHANGES 334
+#define MAX_NICK_TIME 335
+#define MAX_NUMBER 336
+#define MAX_TARGETS 337
+#define MAX_WATCH 338
+#define MESSAGE_LOCALE 339
+#define MIN_NONWILDCARD 340
+#define MIN_NONWILDCARD_SIMPLE 341
+#define MODULE 342
+#define MODULES 343
+#define NAME 344
+#define NEED_PASSWORD 345
+#define NETWORK_DESC 346
+#define NETWORK_NAME 347
+#define NICK 348
+#define NICK_CHANGES 349
+#define NO_CREATE_ON_SPLIT 350
+#define NO_JOIN_ON_SPLIT 351
+#define NO_OPER_FLOOD 352
+#define NO_TILDE 353
+#define NUMBER 354
+#define NUMBER_PER_CIDR 355
+#define NUMBER_PER_IP 356
+#define OPERATOR 357
+#define OPERS_BYPASS_CALLERID 358
+#define OPER_ONLY_UMODES 359
+#define OPER_PASS_RESV 360
+#define OPER_SPY_T 361
+#define OPER_UMODES 362
+#define JOIN_FLOOD_COUNT 363
+#define JOIN_FLOOD_TIME 364
+#define PACE_WAIT 365
+#define PACE_WAIT_SIMPLE 366
+#define PASSWORD 367
+#define PATH 368
+#define PING_COOKIE 369
+#define PING_TIME 370
+#define PING_WARNING 371
+#define PORT 372
+#define QSTRING 373
+#define QUIET_ON_BAN 374
+#define REASON 375
+#define REDIRPORT 376
+#define REDIRSERV 377
+#define REGEX_T 378
+#define REHASH 379
+#define REMOTE 380
+#define REMOTEBAN 381
+#define RESTRICT_CHANNELS 382
+#define RSA_PRIVATE_KEY_FILE 383
+#define RSA_PUBLIC_KEY_FILE 384
+#define SSL_CERTIFICATE_FILE 385
+#define SSL_DH_PARAM_FILE 386
+#define T_SSL_CLIENT_METHOD 387
+#define T_SSL_SERVER_METHOD 388
+#define T_SSLV3 389
+#define T_TLSV1 390
+#define RESV 391
+#define RESV_EXEMPT 392
+#define SECONDS 393
+#define MINUTES 394
+#define HOURS 395
+#define DAYS 396
+#define WEEKS 397
+#define SENDQ 398
+#define SEND_PASSWORD 399
+#define SERVERHIDE 400
+#define SERVERINFO 401
+#define IRCD_SID 402
+#define TKLINE_EXPIRE_NOTICES 403
+#define T_SHARED 404
+#define T_CLUSTER 405
+#define TYPE 406
+#define SHORT_MOTD 407
+#define SPOOF 408
+#define SPOOF_NOTICE 409
+#define STATS_E_DISABLED 410
+#define STATS_I_OPER_ONLY 411
+#define STATS_K_OPER_ONLY 412
+#define STATS_O_OPER_ONLY 413
+#define STATS_P_OPER_ONLY 414
+#define TBOOL 415
+#define TMASKED 416
+#define TS_MAX_DELTA 417
+#define TS_WARN_DELTA 418
+#define TWODOTS 419
+#define T_ALL 420
+#define T_BOTS 421
+#define T_SOFTCALLERID 422
+#define T_CALLERID 423
+#define T_CCONN 424
+#define T_CCONN_FULL 425
+#define T_SSL_CIPHER_LIST 426
+#define T_DEAF 427
+#define T_DEBUG 428
+#define T_DLINE 429
+#define T_EXTERNAL 430
+#define T_FULL 431
+#define T_INVISIBLE 432
+#define T_IPV4 433
+#define T_IPV6 434
+#define T_LOCOPS 435
+#define T_MAX_CLIENTS 436
+#define T_NCHANGE 437
+#define T_OPERWALL 438
+#define T_RECVQ 439
+#define T_REJ 440
+#define T_SERVER 441
+#define T_SERVNOTICE 442
+#define T_SET 443
+#define T_SKILL 444
+#define T_SPY 445
+#define T_SSL 446
+#define T_UMODES 447
+#define T_UNAUTH 448
+#define T_UNDLINE 449
+#define T_UNLIMITED 450
+#define T_UNRESV 451
+#define T_UNXLINE 452
+#define T_GLOBOPS 453
+#define T_WALLOP 454
+#define T_RESTART 455
+#define T_SERVICE 456
+#define T_SERVICES_NAME 457
+#define THROTTLE_TIME 458
+#define TRUE_NO_OPER_FLOOD 459
+#define UNKLINE 460
+#define USER 461
+#define USE_EGD 462
+#define USE_LOGGING 463
+#define VHOST 464
+#define VHOST6 465
+#define XLINE 466
+#define WARN_NO_NLINE 467
+#define T_SIZE 468
+#define T_FILE 469
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+/* Line 2049 of yacc.c */
+#line 110 "conf_parser.y"
+
+ int number;
+ char *string;
+
+
+/* Line 2049 of yacc.c */
+#line 491 "conf_parser.h"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+extern YYSTYPE yylval;
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !YY_Y_TAB_H */
diff --git a/src/conf_parser.y b/src/conf_parser.y
new file mode 100644
index 0000000..1e5096b
--- /dev/null
+++ b/src/conf_parser.y
@@ -0,0 +1,3072 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * conf_parser.y: Parses the ircd configuration file.
+ *
+ * Copyright (C) 2005 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$
+ */
+
+%{
+
+#define YY_NO_UNPUT
+#include <sys/types.h>
+#include <string.h>
+
+#include "config.h"
+#include "stdinc.h"
+#include "ircd.h"
+#include "list.h"
+#include "conf.h"
+#include "event.h"
+#include "log.h"
+#include "client.h" /* for UMODE_ALL only */
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "memory.h"
+#include "modules.h"
+#include "s_serv.h"
+#include "hostmask.h"
+#include "send.h"
+#include "listener.h"
+#include "resv.h"
+#include "numeric.h"
+#include "s_user.h"
+
+#ifdef HAVE_LIBCRYPTO
+#include <openssl/rsa.h>
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+#include <openssl/dh.h>
+#endif
+
+int yylex(void);
+
+static char *class_name = NULL;
+static struct ConfItem *yy_conf = NULL;
+static struct AccessItem *yy_aconf = NULL;
+static struct MatchItem *yy_match_item = NULL;
+static struct ClassItem *yy_class = NULL;
+static char *yy_class_name = NULL;
+
+static dlink_list col_conf_list = { NULL, NULL, 0 };
+static unsigned int listener_flags = 0;
+static unsigned int regex_ban = 0;
+static char userbuf[IRCD_BUFSIZE];
+static char hostbuf[IRCD_BUFSIZE];
+static char reasonbuf[REASONLEN + 1];
+static char gecos_name[REALLEN * 4];
+static char lfile[IRCD_BUFSIZE];
+static unsigned int ltype = 0;
+static unsigned int lsize = 0;
+static char *resv_reason = NULL;
+static char *listener_address = NULL;
+
+struct CollectItem
+{
+ dlink_node node;
+ char *name;
+ char *user;
+ char *host;
+ char *passwd;
+ int port;
+ int flags;
+#ifdef HAVE_LIBCRYPTO
+ char *rsa_public_key_file;
+ RSA *rsa_public_key;
+#endif
+};
+
+static void
+free_collect_item(struct CollectItem *item)
+{
+ MyFree(item->name);
+ MyFree(item->user);
+ MyFree(item->host);
+ MyFree(item->passwd);
+#ifdef HAVE_LIBCRYPTO
+ MyFree(item->rsa_public_key_file);
+#endif
+ MyFree(item);
+}
+
+%}
+
+%union {
+ int number;
+ char *string;
+}
+
+%token ACCEPT_PASSWORD
+%token ADMIN
+%token AFTYPE
+%token ANTI_NICK_FLOOD
+%token ANTI_SPAM_EXIT_MESSAGE_TIME
+%token AUTOCONN
+%token BYTES KBYTES MBYTES
+%token CALLER_ID_WAIT
+%token CAN_FLOOD
+%token CHANNEL
+%token CIDR_BITLEN_IPV4
+%token CIDR_BITLEN_IPV6
+%token CLASS
+%token CONNECT
+%token CONNECTFREQ
+%token DEFAULT_FLOODCOUNT
+%token DEFAULT_SPLIT_SERVER_COUNT
+%token DEFAULT_SPLIT_USER_COUNT
+%token DENY
+%token DESCRIPTION
+%token DIE
+%token DISABLE_AUTH
+%token DISABLE_FAKE_CHANNELS
+%token DISABLE_REMOTE_COMMANDS
+%token DOTS_IN_IDENT
+%token EGDPOOL_PATH
+%token EMAIL
+%token ENCRYPTED
+%token EXCEED_LIMIT
+%token EXEMPT
+%token FAILED_OPER_NOTICE
+%token IRCD_FLAGS
+%token FLATTEN_LINKS
+%token GECOS
+%token GENERAL
+%token GLINE
+%token GLINE_DURATION
+%token GLINE_ENABLE
+%token GLINE_EXEMPT
+%token GLINE_REQUEST_DURATION
+%token GLINE_MIN_CIDR
+%token GLINE_MIN_CIDR6
+%token GLOBAL_KILL
+%token IRCD_AUTH
+%token NEED_IDENT
+%token HAVENT_READ_CONF
+%token HIDDEN
+%token HIDDEN_NAME
+%token HIDE_SERVER_IPS
+%token HIDE_SERVERS
+%token HIDE_SPOOF_IPS
+%token HOST
+%token HUB
+%token HUB_MASK
+%token IGNORE_BOGUS_TS
+%token INVISIBLE_ON_CONNECT
+%token IP
+%token KILL
+%token KILL_CHASE_TIME_LIMIT
+%token KLINE
+%token KLINE_EXEMPT
+%token KNOCK_DELAY
+%token KNOCK_DELAY_CHANNEL
+%token LEAF_MASK
+%token LINKS_DELAY
+%token LISTEN
+%token T_LOG
+%token MAX_ACCEPT
+%token MAX_BANS
+%token MAX_CHANS_PER_OPER
+%token MAX_CHANS_PER_USER
+%token MAX_GLOBAL
+%token MAX_IDENT
+%token MAX_LOCAL
+%token MAX_NICK_CHANGES
+%token MAX_NICK_TIME
+%token MAX_NUMBER
+%token MAX_TARGETS
+%token MAX_WATCH
+%token MESSAGE_LOCALE
+%token MIN_NONWILDCARD
+%token MIN_NONWILDCARD_SIMPLE
+%token MODULE
+%token MODULES
+%token NAME
+%token NEED_PASSWORD
+%token NETWORK_DESC
+%token NETWORK_NAME
+%token NICK
+%token NICK_CHANGES
+%token NO_CREATE_ON_SPLIT
+%token NO_JOIN_ON_SPLIT
+%token NO_OPER_FLOOD
+%token NO_TILDE
+%token NUMBER
+%token NUMBER_PER_CIDR
+%token NUMBER_PER_IP
+%token OPERATOR
+%token OPERS_BYPASS_CALLERID
+%token OPER_ONLY_UMODES
+%token OPER_PASS_RESV
+%token OPER_SPY_T
+%token OPER_UMODES
+%token JOIN_FLOOD_COUNT
+%token JOIN_FLOOD_TIME
+%token PACE_WAIT
+%token PACE_WAIT_SIMPLE
+%token PASSWORD
+%token PATH
+%token PING_COOKIE
+%token PING_TIME
+%token PING_WARNING
+%token PORT
+%token QSTRING
+%token QUIET_ON_BAN
+%token REASON
+%token REDIRPORT
+%token REDIRSERV
+%token REGEX_T
+%token REHASH
+%token REMOTE
+%token REMOTEBAN
+%token RESTRICT_CHANNELS
+%token RSA_PRIVATE_KEY_FILE
+%token RSA_PUBLIC_KEY_FILE
+%token SSL_CERTIFICATE_FILE
+%token SSL_DH_PARAM_FILE
+%token T_SSL_CLIENT_METHOD
+%token T_SSL_SERVER_METHOD
+%token T_SSLV3
+%token T_TLSV1
+%token RESV
+%token RESV_EXEMPT
+%token SECONDS MINUTES HOURS DAYS WEEKS
+%token SENDQ
+%token SEND_PASSWORD
+%token SERVERHIDE
+%token SERVERINFO
+%token IRCD_SID
+%token TKLINE_EXPIRE_NOTICES
+%token T_SHARED
+%token T_CLUSTER
+%token TYPE
+%token SHORT_MOTD
+%token SPOOF
+%token SPOOF_NOTICE
+%token STATS_E_DISABLED
+%token STATS_I_OPER_ONLY
+%token STATS_K_OPER_ONLY
+%token STATS_O_OPER_ONLY
+%token STATS_P_OPER_ONLY
+%token TBOOL
+%token TMASKED
+%token TS_MAX_DELTA
+%token TS_WARN_DELTA
+%token TWODOTS
+%token T_ALL
+%token T_BOTS
+%token T_SOFTCALLERID
+%token T_CALLERID
+%token T_CCONN
+%token T_CCONN_FULL
+%token T_SSL_CIPHER_LIST
+%token T_DEAF
+%token T_DEBUG
+%token T_DLINE
+%token T_EXTERNAL
+%token T_FULL
+%token T_INVISIBLE
+%token T_IPV4
+%token T_IPV6
+%token T_LOCOPS
+%token T_MAX_CLIENTS
+%token T_NCHANGE
+%token T_OPERWALL
+%token T_RECVQ
+%token T_REJ
+%token T_SERVER
+%token T_SERVNOTICE
+%token T_SET
+%token T_SKILL
+%token T_SPY
+%token T_SSL
+%token T_UMODES
+%token T_UNAUTH
+%token T_UNDLINE
+%token T_UNLIMITED
+%token T_UNRESV
+%token T_UNXLINE
+%token T_GLOBOPS
+%token T_WALLOP
+%token T_RESTART
+%token T_SERVICE
+%token T_SERVICES_NAME
+%token THROTTLE_TIME
+%token TRUE_NO_OPER_FLOOD
+%token UNKLINE
+%token USER
+%token USE_EGD
+%token USE_LOGGING
+%token VHOST
+%token VHOST6
+%token XLINE
+%token WARN_NO_NLINE
+%token T_SIZE
+%token T_FILE
+
+%type <string> QSTRING
+%type <number> NUMBER
+%type <number> timespec
+%type <number> timespec_
+%type <number> sizespec
+%type <number> sizespec_
+
+%%
+conf:
+ | conf conf_item
+ ;
+
+conf_item: admin_entry
+ | logging_entry
+ | oper_entry
+ | channel_entry
+ | class_entry
+ | listen_entry
+ | auth_entry
+ | serverinfo_entry
+ | serverhide_entry
+ | resv_entry
+ | service_entry
+ | shared_entry
+ | cluster_entry
+ | connect_entry
+ | kill_entry
+ | deny_entry
+ | exempt_entry
+ | general_entry
+ | gecos_entry
+ | modules_entry
+ | error ';'
+ | error '}'
+ ;
+
+
+timespec_: { $$ = 0; } | timespec;
+timespec: NUMBER timespec_
+ {
+ $$ = $1 + $2;
+ }
+ | NUMBER SECONDS timespec_
+ {
+ $$ = $1 + $3;
+ }
+ | NUMBER MINUTES timespec_
+ {
+ $$ = $1 * 60 + $3;
+ }
+ | NUMBER HOURS timespec_
+ {
+ $$ = $1 * 60 * 60 + $3;
+ }
+ | NUMBER DAYS timespec_
+ {
+ $$ = $1 * 60 * 60 * 24 + $3;
+ }
+ | NUMBER WEEKS timespec_
+ {
+ $$ = $1 * 60 * 60 * 24 * 7 + $3;
+ }
+ ;
+
+sizespec_: { $$ = 0; } | sizespec;
+sizespec: NUMBER sizespec_ { $$ = $1 + $2; }
+ | NUMBER BYTES sizespec_ { $$ = $1 + $3; }
+ | NUMBER KBYTES sizespec_ { $$ = $1 * 1024 + $3; }
+ | NUMBER MBYTES sizespec_ { $$ = $1 * 1024 * 1024 + $3; }
+ ;
+
+
+/***************************************************************************
+ * section modules
+ ***************************************************************************/
+modules_entry: MODULES
+ '{' modules_items '}' ';';
+
+modules_items: modules_items modules_item | modules_item;
+modules_item: modules_module | modules_path | error ';' ;
+
+modules_module: MODULE '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ add_conf_module(libio_basename(yylval.string));
+};
+
+modules_path: PATH '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ mod_add_path(yylval.string);
+};
+
+
+serverinfo_entry: SERVERINFO '{' serverinfo_items '}' ';';
+
+serverinfo_items: serverinfo_items serverinfo_item | serverinfo_item ;
+serverinfo_item: serverinfo_name | serverinfo_vhost |
+ serverinfo_hub | serverinfo_description |
+ serverinfo_network_name | serverinfo_network_desc |
+ serverinfo_max_clients | serverinfo_ssl_dh_param_file |
+ serverinfo_rsa_private_key_file | serverinfo_vhost6 |
+ serverinfo_sid | serverinfo_ssl_certificate_file |
+ serverinfo_ssl_client_method | serverinfo_ssl_server_method |
+ serverinfo_ssl_cipher_list |
+ error ';' ;
+
+
+serverinfo_ssl_client_method: T_SSL_CLIENT_METHOD '=' client_method_types ';' ;
+serverinfo_ssl_server_method: T_SSL_SERVER_METHOD '=' server_method_types ';' ;
+
+client_method_types: client_method_types ',' client_method_type_item | client_method_type_item;
+client_method_type_item: T_SSLV3
+{
+#ifdef HAVE_LIBCRYPTO
+ if (conf_parser_ctx.pass == 2 && ServerInfo.client_ctx)
+ SSL_CTX_clear_options(ServerInfo.client_ctx, SSL_OP_NO_SSLv3);
+#endif
+} | T_TLSV1
+{
+#ifdef HAVE_LIBCRYPTO
+ if (conf_parser_ctx.pass == 2 && ServerInfo.client_ctx)
+ SSL_CTX_clear_options(ServerInfo.client_ctx, SSL_OP_NO_TLSv1);
+#endif
+};
+
+server_method_types: server_method_types ',' server_method_type_item | server_method_type_item;
+server_method_type_item: T_SSLV3
+{
+#ifdef HAVE_LIBCRYPTO
+ if (conf_parser_ctx.pass == 2 && ServerInfo.server_ctx)
+ SSL_CTX_clear_options(ServerInfo.server_ctx, SSL_OP_NO_SSLv3);
+#endif
+} | T_TLSV1
+{
+#ifdef HAVE_LIBCRYPTO
+ if (conf_parser_ctx.pass == 2 && ServerInfo.server_ctx)
+ SSL_CTX_clear_options(ServerInfo.server_ctx, SSL_OP_NO_TLSv1);
+#endif
+};
+
+serverinfo_ssl_certificate_file: SSL_CERTIFICATE_FILE '=' QSTRING ';'
+{
+#ifdef HAVE_LIBCRYPTO
+ if (conf_parser_ctx.pass == 2 && ServerInfo.server_ctx)
+ {
+ if (!ServerInfo.rsa_private_key_file)
+ {
+ yyerror("No rsa_private_key_file specified, SSL disabled");
+ break;
+ }
+
+ if (SSL_CTX_use_certificate_file(ServerInfo.server_ctx, yylval.string,
+ SSL_FILETYPE_PEM) <= 0 ||
+ SSL_CTX_use_certificate_file(ServerInfo.client_ctx, yylval.string,
+ SSL_FILETYPE_PEM) <= 0)
+ {
+ yyerror(ERR_lib_error_string(ERR_get_error()));
+ break;
+ }
+
+ if (SSL_CTX_use_PrivateKey_file(ServerInfo.server_ctx, ServerInfo.rsa_private_key_file,
+ SSL_FILETYPE_PEM) <= 0 ||
+ SSL_CTX_use_PrivateKey_file(ServerInfo.client_ctx, ServerInfo.rsa_private_key_file,
+ SSL_FILETYPE_PEM) <= 0)
+ {
+ yyerror(ERR_lib_error_string(ERR_get_error()));
+ break;
+ }
+
+ if (!SSL_CTX_check_private_key(ServerInfo.server_ctx) ||
+ !SSL_CTX_check_private_key(ServerInfo.client_ctx))
+ {
+ yyerror(ERR_lib_error_string(ERR_get_error()));
+ break;
+ }
+ }
+#endif
+};
+
+serverinfo_rsa_private_key_file: RSA_PRIVATE_KEY_FILE '=' QSTRING ';'
+{
+#ifdef HAVE_LIBCRYPTO
+ if (conf_parser_ctx.pass == 1)
+ {
+ BIO *file;
+
+ if (ServerInfo.rsa_private_key)
+ {
+ RSA_free(ServerInfo.rsa_private_key);
+ ServerInfo.rsa_private_key = NULL;
+ }
+
+ if (ServerInfo.rsa_private_key_file)
+ {
+ MyFree(ServerInfo.rsa_private_key_file);
+ ServerInfo.rsa_private_key_file = NULL;
+ }
+
+ DupString(ServerInfo.rsa_private_key_file, yylval.string);
+
+ if ((file = BIO_new_file(yylval.string, "r")) == NULL)
+ {
+ yyerror("File open failed, ignoring");
+ break;
+ }
+
+ ServerInfo.rsa_private_key = PEM_read_bio_RSAPrivateKey(file, NULL, 0, NULL);
+
+ BIO_set_close(file, BIO_CLOSE);
+ BIO_free(file);
+
+ if (ServerInfo.rsa_private_key == NULL)
+ {
+ yyerror("Couldn't extract key, ignoring");
+ break;
+ }
+
+ if (!RSA_check_key(ServerInfo.rsa_private_key))
+ {
+ RSA_free(ServerInfo.rsa_private_key);
+ ServerInfo.rsa_private_key = NULL;
+
+ yyerror("Invalid key, ignoring");
+ break;
+ }
+
+ /* require 2048 bit (256 byte) key */
+ if (RSA_size(ServerInfo.rsa_private_key) != 256)
+ {
+ RSA_free(ServerInfo.rsa_private_key);
+ ServerInfo.rsa_private_key = NULL;
+
+ yyerror("Not a 2048 bit key, ignoring");
+ }
+ }
+#endif
+};
+
+serverinfo_ssl_dh_param_file: SSL_DH_PARAM_FILE '=' QSTRING ';'
+{
+/* TBD - XXX: error reporting */
+#ifdef HAVE_LIBCRYPTO
+ if (conf_parser_ctx.pass == 2 && ServerInfo.server_ctx)
+ {
+ BIO *file = BIO_new_file(yylval.string, "r");
+
+ if (file)
+ {
+ DH *dh = PEM_read_bio_DHparams(file, NULL, NULL, NULL);
+
+ BIO_free(file);
+
+ if (dh)
+ {
+ if (DH_size(dh) < 128)
+ ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::ssl_dh_param_file -- need at least a 1024 bit DH prime size");
+ else
+ SSL_CTX_set_tmp_dh(ServerInfo.server_ctx, dh);
+
+ DH_free(dh);
+ }
+ }
+ }
+#endif
+};
+
+serverinfo_ssl_cipher_list: T_SSL_CIPHER_LIST '=' QSTRING ';'
+{
+#ifdef HAVE_LIBCRYPTO
+ if (conf_parser_ctx.pass == 2 && ServerInfo.server_ctx)
+ SSL_CTX_set_cipher_list(ServerInfo.server_ctx, yylval.string);
+#endif
+};
+
+serverinfo_name: NAME '=' QSTRING ';'
+{
+ /* this isn't rehashable */
+ if (conf_parser_ctx.pass == 2 && !ServerInfo.name)
+ {
+ if (valid_servname(yylval.string))
+ DupString(ServerInfo.name, yylval.string);
+ else
+ {
+ ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::name -- invalid name. Aborting.");
+ exit(0);
+ }
+ }
+};
+
+serverinfo_sid: IRCD_SID '=' QSTRING ';'
+{
+ /* this isn't rehashable */
+ if (conf_parser_ctx.pass == 2 && !ServerInfo.sid)
+ {
+ if (valid_sid(yylval.string))
+ DupString(ServerInfo.sid, yylval.string);
+ else
+ {
+ ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::sid -- invalid SID. Aborting.");
+ exit(0);
+ }
+ }
+};
+
+serverinfo_description: DESCRIPTION '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(ServerInfo.description);
+ DupString(ServerInfo.description,yylval.string);
+ }
+};
+
+serverinfo_network_name: NETWORK_NAME '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ char *p;
+
+ if ((p = strchr(yylval.string, ' ')) != NULL)
+ p = '\0';
+
+ MyFree(ServerInfo.network_name);
+ DupString(ServerInfo.network_name, yylval.string);
+ }
+};
+
+serverinfo_network_desc: NETWORK_DESC '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(ServerInfo.network_desc);
+ DupString(ServerInfo.network_desc, yylval.string);
+ }
+};
+
+serverinfo_vhost: VHOST '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2 && *yylval.string != '*')
+ {
+ struct addrinfo hints, *res;
+
+ memset(&hints, 0, sizeof(hints));
+
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
+
+ if (getaddrinfo(yylval.string, NULL, &hints, &res))
+ ilog(LOG_TYPE_IRCD, "Invalid netmask for server vhost(%s)", yylval.string);
+ else
+ {
+ assert(res != NULL);
+
+ memcpy(&ServerInfo.ip, res->ai_addr, res->ai_addrlen);
+ ServerInfo.ip.ss.ss_family = res->ai_family;
+ ServerInfo.ip.ss_len = res->ai_addrlen;
+ freeaddrinfo(res);
+
+ ServerInfo.specific_ipv4_vhost = 1;
+ }
+ }
+};
+
+serverinfo_vhost6: VHOST6 '=' QSTRING ';'
+{
+#ifdef IPV6
+ if (conf_parser_ctx.pass == 2 && *yylval.string != '*')
+ {
+ struct addrinfo hints, *res;
+
+ memset(&hints, 0, sizeof(hints));
+
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
+
+ if (getaddrinfo(yylval.string, NULL, &hints, &res))
+ ilog(LOG_TYPE_IRCD, "Invalid netmask for server vhost6(%s)", yylval.string);
+ else
+ {
+ assert(res != NULL);
+
+ memcpy(&ServerInfo.ip6, res->ai_addr, res->ai_addrlen);
+ ServerInfo.ip6.ss.ss_family = res->ai_family;
+ ServerInfo.ip6.ss_len = res->ai_addrlen;
+ freeaddrinfo(res);
+
+ ServerInfo.specific_ipv6_vhost = 1;
+ }
+ }
+#endif
+};
+
+serverinfo_max_clients: T_MAX_CLIENTS '=' NUMBER ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ recalc_fdlimit(NULL);
+
+ if ($3 < MAXCLIENTS_MIN)
+ {
+ char buf[IRCD_BUFSIZE];
+ ircsprintf(buf, "MAXCLIENTS too low, setting to %d", MAXCLIENTS_MIN);
+ yyerror(buf);
+ }
+ else if ($3 > MAXCLIENTS_MAX)
+ {
+ char buf[IRCD_BUFSIZE];
+ ircsprintf(buf, "MAXCLIENTS too high, setting to %d", MAXCLIENTS_MAX);
+ yyerror(buf);
+ }
+ else
+ ServerInfo.max_clients = $3;
+ }
+};
+
+serverinfo_hub: HUB '=' TBOOL ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ ServerInfo.hub = yylval.number;
+};
+
+/***************************************************************************
+ * admin section
+ ***************************************************************************/
+admin_entry: ADMIN '{' admin_items '}' ';' ;
+
+admin_items: admin_items admin_item | admin_item;
+admin_item: admin_name | admin_description |
+ admin_email | error ';' ;
+
+admin_name: NAME '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(AdminInfo.name);
+ DupString(AdminInfo.name, yylval.string);
+ }
+};
+
+admin_email: EMAIL '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(AdminInfo.email);
+ DupString(AdminInfo.email, yylval.string);
+ }
+};
+
+admin_description: DESCRIPTION '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(AdminInfo.description);
+ DupString(AdminInfo.description, yylval.string);
+ }
+};
+
+/***************************************************************************
+ * section logging
+ ***************************************************************************/
+logging_entry: T_LOG '{' logging_items '}' ';' ;
+logging_items: logging_items logging_item | logging_item ;
+
+logging_item: logging_use_logging | logging_file_entry |
+ error ';' ;
+
+logging_use_logging: USE_LOGGING '=' TBOOL ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ ConfigLoggingEntry.use_logging = yylval.number;
+};
+
+logging_file_entry:
+{
+ lfile[0] = '\0';
+ ltype = 0;
+ lsize = 0;
+} T_FILE '{' logging_file_items '}' ';'
+{
+ if (conf_parser_ctx.pass == 2 && ltype > 0)
+ log_add_file(ltype, lsize, lfile);
+};
+
+logging_file_items: logging_file_items logging_file_item |
+ logging_file_item ;
+
+logging_file_item: logging_file_name | logging_file_type |
+ logging_file_size | error ';' ;
+
+logging_file_name: NAME '=' QSTRING ';'
+{
+ strlcpy(lfile, yylval.string, sizeof(lfile));
+}
+
+logging_file_size: T_SIZE '=' sizespec ';'
+{
+ lsize = $3;
+} | T_SIZE '=' T_UNLIMITED ';'
+{
+ lsize = 0;
+};
+
+logging_file_type: TYPE
+{
+ if (conf_parser_ctx.pass == 2)
+ ltype = 0;
+} '=' logging_file_type_items ';' ;
+
+logging_file_type_items: logging_file_type_items ',' logging_file_type_item | logging_file_type_item;
+logging_file_type_item: USER
+{
+ if (conf_parser_ctx.pass == 2)
+ ltype = LOG_TYPE_USER;
+} | OPERATOR
+{
+ if (conf_parser_ctx.pass == 2)
+ ltype = LOG_TYPE_OPER;
+} | GLINE
+{
+ if (conf_parser_ctx.pass == 2)
+ ltype = LOG_TYPE_GLINE;
+} | T_DLINE
+{
+ if (conf_parser_ctx.pass == 2)
+ ltype = LOG_TYPE_DLINE;
+} | KLINE
+{
+ if (conf_parser_ctx.pass == 2)
+ ltype = LOG_TYPE_KLINE;
+} | KILL
+{
+ if (conf_parser_ctx.pass == 2)
+ ltype = LOG_TYPE_KILL;
+} | T_DEBUG
+{
+ if (conf_parser_ctx.pass == 2)
+ ltype = LOG_TYPE_DEBUG;
+};
+
+
+/***************************************************************************
+ * section oper
+ ***************************************************************************/
+oper_entry: OPERATOR
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ yy_conf = make_conf_item(OPER_TYPE);
+ yy_aconf = map_to_conf(yy_conf);
+ SetConfEncrypted(yy_aconf); /* Yes, the default is encrypted */
+ }
+ else
+ {
+ MyFree(class_name);
+ class_name = NULL;
+ }
+} '{' oper_items '}' ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ struct CollectItem *yy_tmp;
+ dlink_node *ptr;
+ dlink_node *next_ptr;
+
+ conf_add_class_to_conf(yy_conf, class_name);
+
+ /* Now, make sure there is a copy of the "base" given oper
+ * block in each of the collected copies
+ */
+
+ DLINK_FOREACH_SAFE(ptr, next_ptr, col_conf_list.head)
+ {
+ struct AccessItem *new_aconf;
+ struct ConfItem *new_conf;
+ yy_tmp = ptr->data;
+
+ new_conf = make_conf_item(OPER_TYPE);
+ new_aconf = (struct AccessItem *)map_to_conf(new_conf);
+
+ new_aconf->flags = yy_aconf->flags;
+
+ if (yy_conf->name != NULL)
+ DupString(new_conf->name, yy_conf->name);
+ if (yy_tmp->user != NULL)
+ DupString(new_aconf->user, yy_tmp->user);
+ else
+ DupString(new_aconf->user, "*");
+ if (yy_tmp->host != NULL)
+ DupString(new_aconf->host, yy_tmp->host);
+ else
+ DupString(new_aconf->host, "*");
+
+ new_aconf->type = parse_netmask(new_aconf->host, &new_aconf->addr,
+ &new_aconf->bits);
+
+ conf_add_class_to_conf(new_conf, class_name);
+ if (yy_aconf->passwd != NULL)
+ DupString(new_aconf->passwd, yy_aconf->passwd);
+
+ new_aconf->port = yy_aconf->port;
+#ifdef HAVE_LIBCRYPTO
+ if (yy_aconf->rsa_public_key_file != NULL)
+ {
+ BIO *file;
+
+ DupString(new_aconf->rsa_public_key_file,
+ yy_aconf->rsa_public_key_file);
+
+ file = BIO_new_file(yy_aconf->rsa_public_key_file, "r");
+ new_aconf->rsa_public_key = PEM_read_bio_RSA_PUBKEY(file,
+ NULL, 0, NULL);
+ BIO_set_close(file, BIO_CLOSE);
+ BIO_free(file);
+ }
+#endif
+
+#ifdef HAVE_LIBCRYPTO
+ if (yy_tmp->name && (yy_tmp->passwd || yy_aconf->rsa_public_key)
+ && yy_tmp->host)
+#else
+ if (yy_tmp->name && yy_tmp->passwd && yy_tmp->host)
+#endif
+ {
+ conf_add_class_to_conf(new_conf, class_name);
+ if (yy_tmp->name != NULL)
+ DupString(new_conf->name, yy_tmp->name);
+ }
+
+ dlinkDelete(&yy_tmp->node, &col_conf_list);
+ free_collect_item(yy_tmp);
+ }
+
+ yy_conf = NULL;
+ yy_aconf = NULL;
+
+
+ MyFree(class_name);
+ class_name = NULL;
+ }
+};
+
+oper_items: oper_items oper_item | oper_item;
+oper_item: oper_name | oper_user | oper_password |
+ oper_umodes | oper_class | oper_encrypted |
+ oper_rsa_public_key_file | oper_flags | error ';' ;
+
+oper_name: NAME '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(yy_conf->name);
+ DupString(yy_conf->name, yylval.string);
+ }
+};
+
+oper_user: USER '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ struct split_nuh_item nuh;
+
+ nuh.nuhmask = yylval.string;
+ nuh.nickptr = NULL;
+ nuh.userptr = userbuf;
+ nuh.hostptr = hostbuf;
+
+ nuh.nicksize = 0;
+ nuh.usersize = sizeof(userbuf);
+ nuh.hostsize = sizeof(hostbuf);
+
+ split_nuh(&nuh);
+
+ if (yy_aconf->user == NULL)
+ {
+ DupString(yy_aconf->user, userbuf);
+ DupString(yy_aconf->host, hostbuf);
+
+ yy_aconf->type = parse_netmask(yy_aconf->host, &yy_aconf->addr,
+ &yy_aconf->bits);
+ }
+ else
+ {
+ struct CollectItem *yy_tmp = MyMalloc(sizeof(struct CollectItem));
+
+ DupString(yy_tmp->user, userbuf);
+ DupString(yy_tmp->host, hostbuf);
+
+ dlinkAdd(yy_tmp, &yy_tmp->node, &col_conf_list);
+ }
+ }
+};
+
+oper_password: PASSWORD '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (yy_aconf->passwd != NULL)
+ memset(yy_aconf->passwd, 0, strlen(yy_aconf->passwd));
+
+ MyFree(yy_aconf->passwd);
+ DupString(yy_aconf->passwd, yylval.string);
+ }
+};
+
+oper_encrypted: ENCRYPTED '=' TBOOL ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (yylval.number)
+ SetConfEncrypted(yy_aconf);
+ else
+ ClearConfEncrypted(yy_aconf);
+ }
+};
+
+oper_rsa_public_key_file: RSA_PUBLIC_KEY_FILE '=' QSTRING ';'
+{
+#ifdef HAVE_LIBCRYPTO
+ if (conf_parser_ctx.pass == 2)
+ {
+ BIO *file;
+
+ if (yy_aconf->rsa_public_key != NULL)
+ {
+ RSA_free(yy_aconf->rsa_public_key);
+ yy_aconf->rsa_public_key = NULL;
+ }
+
+ if (yy_aconf->rsa_public_key_file != NULL)
+ {
+ MyFree(yy_aconf->rsa_public_key_file);
+ yy_aconf->rsa_public_key_file = NULL;
+ }
+
+ DupString(yy_aconf->rsa_public_key_file, yylval.string);
+ file = BIO_new_file(yylval.string, "r");
+
+ if (file == NULL)
+ {
+ yyerror("Ignoring rsa_public_key_file -- file doesn't exist");
+ break;
+ }
+
+ yy_aconf->rsa_public_key = PEM_read_bio_RSA_PUBKEY(file, NULL, 0, NULL);
+
+ if (yy_aconf->rsa_public_key == NULL)
+ {
+ yyerror("Ignoring rsa_public_key_file -- Key invalid; check key syntax.");
+ break;
+ }
+
+ BIO_set_close(file, BIO_CLOSE);
+ BIO_free(file);
+ }
+#endif /* HAVE_LIBCRYPTO */
+};
+
+oper_class: CLASS '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(class_name);
+ DupString(class_name, yylval.string);
+ }
+};
+
+oper_umodes: T_UMODES
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes = 0;
+} '=' oper_umodes_items ';' ;
+
+oper_umodes_items: oper_umodes_items ',' oper_umodes_item | oper_umodes_item;
+oper_umodes_item: T_BOTS
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_BOTS;
+} | T_CCONN
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_CCONN;
+} | T_CCONN_FULL
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_CCONN_FULL;
+} | T_DEAF
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_DEAF;
+} | T_DEBUG
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_DEBUG;
+} | T_FULL
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_FULL;
+} | HIDDEN
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_HIDDEN;
+} | T_SKILL
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_SKILL;
+} | T_NCHANGE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_NCHANGE;
+} | T_REJ
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_REJ;
+} | T_UNAUTH
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_UNAUTH;
+} | T_SPY
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_SPY;
+} | T_EXTERNAL
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_EXTERNAL;
+} | T_OPERWALL
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_OPERWALL;
+} | T_SERVNOTICE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_SERVNOTICE;
+} | T_INVISIBLE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_INVISIBLE;
+} | T_WALLOP
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_WALLOP;
+} | T_SOFTCALLERID
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_SOFTCALLERID;
+} | T_CALLERID
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_CALLERID;
+} | T_LOCOPS
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->modes |= UMODE_LOCOPS;
+};
+
+oper_flags: IRCD_FLAGS
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port = 0;
+} '=' oper_flags_items ';';
+
+oper_flags_items: oper_flags_items ',' oper_flags_item | oper_flags_item;
+oper_flags_item: GLOBAL_KILL
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_GLOBAL_KILL;
+} | REMOTE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_REMOTE;
+} | KLINE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_K;
+} | UNKLINE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_UNKLINE;
+} | T_DLINE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_DLINE;
+} | T_UNDLINE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_UNDLINE;
+} | XLINE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_X;
+} | GLINE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_GLINE;
+} | DIE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_DIE;
+} | T_RESTART
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_RESTART;
+} | REHASH
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_REHASH;
+} | ADMIN
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_ADMIN;
+} | NICK_CHANGES
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_N;
+} | T_OPERWALL
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_OPERWALL;
+} | T_GLOBOPS
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_GLOBOPS;
+} | OPER_SPY_T
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_OPER_SPY;
+} | REMOTEBAN
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_REMOTEBAN;
+} | T_SET
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_SET;
+} | MODULE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port |= OPER_FLAG_MODULE;
+};
+
+
+/***************************************************************************
+ * section class
+ ***************************************************************************/
+class_entry: CLASS
+{
+ if (conf_parser_ctx.pass == 1)
+ {
+ yy_conf = make_conf_item(CLASS_TYPE);
+ yy_class = map_to_conf(yy_conf);
+ }
+} '{' class_items '}' ';'
+{
+ if (conf_parser_ctx.pass == 1)
+ {
+ struct ConfItem *cconf = NULL;
+ struct ClassItem *class = NULL;
+
+ if (yy_class_name == NULL)
+ delete_conf_item(yy_conf);
+ else
+ {
+ cconf = find_exact_name_conf(CLASS_TYPE, NULL, yy_class_name, NULL, NULL);
+
+ if (cconf != NULL) /* The class existed already */
+ {
+ int user_count = 0;
+
+ rebuild_cidr_class(cconf, yy_class);
+
+ class = map_to_conf(cconf);
+
+ user_count = class->curr_user_count;
+ memcpy(class, yy_class, sizeof(*class));
+ class->curr_user_count = user_count;
+ class->active = 1;
+
+ delete_conf_item(yy_conf);
+
+ MyFree(cconf->name); /* Allows case change of class name */
+ cconf->name = yy_class_name;
+ }
+ else /* Brand new class */
+ {
+ MyFree(yy_conf->name); /* just in case it was allocated */
+ yy_conf->name = yy_class_name;
+ yy_class->active = 1;
+ }
+ }
+
+ yy_class_name = NULL;
+ }
+};
+
+class_items: class_items class_item | class_item;
+class_item: class_name |
+ class_cidr_bitlen_ipv4 | class_cidr_bitlen_ipv6 |
+ class_ping_time |
+ class_ping_warning |
+ class_number_per_cidr |
+ class_number_per_ip |
+ class_connectfreq |
+ class_max_number |
+ class_max_global |
+ class_max_local |
+ class_max_ident |
+ class_sendq | class_recvq |
+ error ';' ;
+
+class_name: NAME '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 1)
+ {
+ MyFree(yy_class_name);
+ DupString(yy_class_name, yylval.string);
+ }
+};
+
+class_ping_time: PING_TIME '=' timespec ';'
+{
+ if (conf_parser_ctx.pass == 1)
+ yy_class->ping_freq = $3;
+};
+
+class_ping_warning: PING_WARNING '=' timespec ';'
+{
+ if (conf_parser_ctx.pass == 1)
+ yy_class->ping_warning = $3;
+};
+
+class_number_per_ip: NUMBER_PER_IP '=' NUMBER ';'
+{
+ if (conf_parser_ctx.pass == 1)
+ yy_class->max_perip = $3;
+};
+
+class_connectfreq: CONNECTFREQ '=' timespec ';'
+{
+ if (conf_parser_ctx.pass == 1)
+ yy_class->con_freq = $3;
+};
+
+class_max_number: MAX_NUMBER '=' NUMBER ';'
+{
+ if (conf_parser_ctx.pass == 1)
+ yy_class->max_total = $3;
+};
+
+class_max_global: MAX_GLOBAL '=' NUMBER ';'
+{
+ if (conf_parser_ctx.pass == 1)
+ yy_class->max_global = $3;
+};
+
+class_max_local: MAX_LOCAL '=' NUMBER ';'
+{
+ if (conf_parser_ctx.pass == 1)
+ yy_class->max_local = $3;
+};
+
+class_max_ident: MAX_IDENT '=' NUMBER ';'
+{
+ if (conf_parser_ctx.pass == 1)
+ yy_class->max_ident = $3;
+};
+
+class_sendq: SENDQ '=' sizespec ';'
+{
+ if (conf_parser_ctx.pass == 1)
+ yy_class->max_sendq = $3;
+};
+
+class_recvq: T_RECVQ '=' sizespec ';'
+{
+ if (conf_parser_ctx.pass == 1)
+ if ($3 >= CLIENT_FLOOD_MIN && $3 <= CLIENT_FLOOD_MAX)
+ yy_class->max_recvq = $3;
+};
+
+class_cidr_bitlen_ipv4: CIDR_BITLEN_IPV4 '=' NUMBER ';'
+{
+ if (conf_parser_ctx.pass == 1)
+ yy_class->cidr_bitlen_ipv4 = $3 > 32 ? 32 : $3;
+};
+
+class_cidr_bitlen_ipv6: CIDR_BITLEN_IPV6 '=' NUMBER ';'
+{
+ if (conf_parser_ctx.pass == 1)
+ yy_class->cidr_bitlen_ipv6 = $3 > 128 ? 128 : $3;
+};
+
+class_number_per_cidr: NUMBER_PER_CIDR '=' NUMBER ';'
+{
+ if (conf_parser_ctx.pass == 1)
+ yy_class->number_per_cidr = $3;
+};
+
+/***************************************************************************
+ * section listen
+ ***************************************************************************/
+listen_entry: LISTEN
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ listener_address = NULL;
+ listener_flags = 0;
+ }
+} '{' listen_items '}' ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(listener_address);
+ listener_address = NULL;
+ }
+};
+
+listen_flags: IRCD_FLAGS
+{
+ listener_flags = 0;
+} '=' listen_flags_items ';';
+
+listen_flags_items: listen_flags_items ',' listen_flags_item | listen_flags_item;
+listen_flags_item: T_SSL
+{
+ if (conf_parser_ctx.pass == 2)
+ listener_flags |= LISTENER_SSL;
+} | HIDDEN
+{
+ if (conf_parser_ctx.pass == 2)
+ listener_flags |= LISTENER_HIDDEN;
+} | T_SERVER
+{
+ if (conf_parser_ctx.pass == 2)
+ listener_flags |= LISTENER_SERVER;
+};
+
+
+
+listen_items: listen_items listen_item | listen_item;
+listen_item: listen_port | listen_flags | listen_address | listen_host | error ';';
+
+listen_port: PORT '=' port_items { listener_flags = 0; } ';';
+
+port_items: port_items ',' port_item | port_item;
+
+port_item: NUMBER
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ if ((listener_flags & LISTENER_SSL))
+#ifdef HAVE_LIBCRYPTO
+ if (!ServerInfo.server_ctx)
+#endif
+ {
+ yyerror("SSL not available - port closed");
+ break;
+ }
+ add_listener($1, listener_address, listener_flags);
+ }
+} | NUMBER TWODOTS NUMBER
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ int i;
+
+ if ((listener_flags & LISTENER_SSL))
+#ifdef HAVE_LIBCRYPTO
+ if (!ServerInfo.server_ctx)
+#endif
+ {
+ yyerror("SSL not available - port closed");
+ break;
+ }
+
+ for (i = $1; i <= $3; ++i)
+ add_listener(i, listener_address, listener_flags);
+ }
+};
+
+listen_address: IP '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(listener_address);
+ DupString(listener_address, yylval.string);
+ }
+};
+
+listen_host: HOST '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(listener_address);
+ DupString(listener_address, yylval.string);
+ }
+};
+
+/***************************************************************************
+ * section auth
+ ***************************************************************************/
+auth_entry: IRCD_AUTH
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ yy_conf = make_conf_item(CLIENT_TYPE);
+ yy_aconf = map_to_conf(yy_conf);
+ }
+ else
+ {
+ MyFree(class_name);
+ class_name = NULL;
+ }
+} '{' auth_items '}' ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ struct CollectItem *yy_tmp = NULL;
+ dlink_node *ptr = NULL, *next_ptr = NULL;
+
+ if (yy_aconf->user && yy_aconf->host)
+ {
+ conf_add_class_to_conf(yy_conf, class_name);
+ add_conf_by_address(CONF_CLIENT, yy_aconf);
+ }
+ else
+ delete_conf_item(yy_conf);
+
+ /* copy over settings from first struct */
+ DLINK_FOREACH_SAFE(ptr, next_ptr, col_conf_list.head)
+ {
+ struct AccessItem *new_aconf;
+ struct ConfItem *new_conf;
+
+ new_conf = make_conf_item(CLIENT_TYPE);
+ new_aconf = map_to_conf(new_conf);
+
+ yy_tmp = ptr->data;
+
+ assert(yy_tmp->user && yy_tmp->host);
+
+ if (yy_aconf->passwd != NULL)
+ DupString(new_aconf->passwd, yy_aconf->passwd);
+ if (yy_conf->name != NULL)
+ DupString(new_conf->name, yy_conf->name);
+ if (yy_aconf->passwd != NULL)
+ DupString(new_aconf->passwd, yy_aconf->passwd);
+
+ new_aconf->flags = yy_aconf->flags;
+ new_aconf->port = yy_aconf->port;
+
+ DupString(new_aconf->user, yy_tmp->user);
+ collapse(new_aconf->user);
+
+ DupString(new_aconf->host, yy_tmp->host);
+ collapse(new_aconf->host);
+
+ conf_add_class_to_conf(new_conf, class_name);
+ add_conf_by_address(CONF_CLIENT, new_aconf);
+ dlinkDelete(&yy_tmp->node, &col_conf_list);
+ free_collect_item(yy_tmp);
+ }
+
+ MyFree(class_name);
+ class_name = NULL;
+ yy_conf = NULL;
+ yy_aconf = NULL;
+ }
+};
+
+auth_items: auth_items auth_item | auth_item;
+auth_item: auth_user | auth_passwd | auth_class | auth_flags |
+ auth_spoof | auth_redir_serv | auth_redir_port |
+ auth_encrypted | error ';' ;
+
+auth_user: USER '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ struct CollectItem *yy_tmp = NULL;
+ struct split_nuh_item nuh;
+
+ nuh.nuhmask = yylval.string;
+ nuh.nickptr = NULL;
+ nuh.userptr = userbuf;
+ nuh.hostptr = hostbuf;
+
+ nuh.nicksize = 0;
+ nuh.usersize = sizeof(userbuf);
+ nuh.hostsize = sizeof(hostbuf);
+
+ split_nuh(&nuh);
+
+ if (yy_aconf->user == NULL)
+ {
+ DupString(yy_aconf->user, userbuf);
+ DupString(yy_aconf->host, hostbuf);
+ }
+ else
+ {
+ yy_tmp = MyMalloc(sizeof(struct CollectItem));
+
+ DupString(yy_tmp->user, userbuf);
+ DupString(yy_tmp->host, hostbuf);
+
+ dlinkAdd(yy_tmp, &yy_tmp->node, &col_conf_list);
+ }
+ }
+};
+
+auth_passwd: PASSWORD '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ /* be paranoid */
+ if (yy_aconf->passwd != NULL)
+ memset(yy_aconf->passwd, 0, strlen(yy_aconf->passwd));
+
+ MyFree(yy_aconf->passwd);
+ DupString(yy_aconf->passwd, yylval.string);
+ }
+};
+
+auth_class: CLASS '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(class_name);
+ DupString(class_name, yylval.string);
+ }
+};
+
+auth_encrypted: ENCRYPTED '=' TBOOL ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (yylval.number)
+ SetConfEncrypted(yy_aconf);
+ else
+ ClearConfEncrypted(yy_aconf);
+ }
+};
+
+auth_flags: IRCD_FLAGS
+{
+} '=' auth_flags_items ';';
+
+auth_flags_items: auth_flags_items ',' auth_flags_item | auth_flags_item;
+auth_flags_item: SPOOF_NOTICE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->flags |= CONF_FLAGS_SPOOF_NOTICE;
+} | EXCEED_LIMIT
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->flags |= CONF_FLAGS_NOLIMIT;
+} | KLINE_EXEMPT
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->flags |= CONF_FLAGS_EXEMPTKLINE;
+} | NEED_IDENT
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->flags |= CONF_FLAGS_NEED_IDENTD;
+} | CAN_FLOOD
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->flags |= CONF_FLAGS_CAN_FLOOD;
+} | NO_TILDE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->flags |= CONF_FLAGS_NO_TILDE;
+} | GLINE_EXEMPT
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->flags |= CONF_FLAGS_EXEMPTGLINE;
+} | RESV_EXEMPT
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->flags |= CONF_FLAGS_EXEMPTRESV;
+} | NEED_PASSWORD
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->flags |= CONF_FLAGS_NEED_PASSWORD;
+};
+
+auth_spoof: SPOOF '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(yy_conf->name);
+
+ if (strlen(yylval.string) <= HOSTLEN && valid_hostname(yylval.string))
+ {
+ DupString(yy_conf->name, yylval.string);
+ yy_aconf->flags |= CONF_FLAGS_SPOOF_IP;
+ }
+ else
+ {
+ ilog(LOG_TYPE_IRCD, "Spoof either is too long or contains invalid characters. Ignoring it.");
+ yy_conf->name = NULL;
+ }
+ }
+};
+
+auth_redir_serv: REDIRSERV '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ yy_aconf->flags |= CONF_FLAGS_REDIR;
+ MyFree(yy_conf->name);
+ DupString(yy_conf->name, yylval.string);
+ }
+};
+
+auth_redir_port: REDIRPORT '=' NUMBER ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ yy_aconf->flags |= CONF_FLAGS_REDIR;
+ yy_aconf->port = $3;
+ }
+};
+
+
+/***************************************************************************
+ * section resv
+ ***************************************************************************/
+resv_entry: RESV
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(resv_reason);
+ resv_reason = NULL;
+ }
+} '{' resv_items '}' ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(resv_reason);
+ resv_reason = NULL;
+ }
+};
+
+resv_items: resv_items resv_item | resv_item;
+resv_item: resv_creason | resv_channel | resv_nick | error ';' ;
+
+resv_creason: REASON '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(resv_reason);
+ DupString(resv_reason, yylval.string);
+ }
+};
+
+resv_channel: CHANNEL '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (IsChanPrefix(*yylval.string))
+ {
+ char def_reason[] = "No reason";
+
+ create_channel_resv(yylval.string, resv_reason != NULL ? resv_reason : def_reason, 1);
+ }
+ }
+ /* ignore it for now.. but we really should make a warning if
+ * its an erroneous name --fl_ */
+};
+
+resv_nick: NICK '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ char def_reason[] = "No reason";
+
+ create_nick_resv(yylval.string, resv_reason != NULL ? resv_reason : def_reason, 1);
+ }
+};
+
+/***************************************************************************
+ * section service
+ ***************************************************************************/
+service_entry: T_SERVICE '{' service_items '}' ';';
+
+service_items: service_items service_item | service_item;
+service_item: service_name | error;
+
+service_name: NAME '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (valid_servname(yylval.string))
+ {
+ yy_conf = make_conf_item(SERVICE_TYPE);
+ DupString(yy_conf->name, yylval.string);
+ }
+ }
+};
+
+/***************************************************************************
+ * section shared, for sharing remote klines etc.
+ ***************************************************************************/
+shared_entry: T_SHARED
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ yy_conf = make_conf_item(ULINE_TYPE);
+ yy_match_item = map_to_conf(yy_conf);
+ yy_match_item->action = SHARED_ALL;
+ }
+} '{' shared_items '}' ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ yy_conf = NULL;
+ }
+};
+
+shared_items: shared_items shared_item | shared_item;
+shared_item: shared_name | shared_user | shared_type | error ';' ;
+
+shared_name: NAME '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(yy_conf->name);
+ DupString(yy_conf->name, yylval.string);
+ }
+};
+
+shared_user: USER '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ struct split_nuh_item nuh;
+
+ nuh.nuhmask = yylval.string;
+ nuh.nickptr = NULL;
+ nuh.userptr = userbuf;
+ nuh.hostptr = hostbuf;
+
+ nuh.nicksize = 0;
+ nuh.usersize = sizeof(userbuf);
+ nuh.hostsize = sizeof(hostbuf);
+
+ split_nuh(&nuh);
+
+ DupString(yy_match_item->user, userbuf);
+ DupString(yy_match_item->host, hostbuf);
+ }
+};
+
+shared_type: TYPE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_match_item->action = 0;
+} '=' shared_types ';' ;
+
+shared_types: shared_types ',' shared_type_item | shared_type_item;
+shared_type_item: KLINE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_match_item->action |= SHARED_KLINE;
+} | UNKLINE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_match_item->action |= SHARED_UNKLINE;
+} | T_DLINE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_match_item->action |= SHARED_DLINE;
+} | T_UNDLINE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_match_item->action |= SHARED_UNDLINE;
+} | XLINE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_match_item->action |= SHARED_XLINE;
+} | T_UNXLINE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_match_item->action |= SHARED_UNXLINE;
+} | RESV
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_match_item->action |= SHARED_RESV;
+} | T_UNRESV
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_match_item->action |= SHARED_UNRESV;
+} | T_LOCOPS
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_match_item->action |= SHARED_LOCOPS;
+} | T_ALL
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_match_item->action = SHARED_ALL;
+};
+
+/***************************************************************************
+ * section cluster
+ ***************************************************************************/
+cluster_entry: T_CLUSTER
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ yy_conf = make_conf_item(CLUSTER_TYPE);
+ yy_conf->flags = SHARED_ALL;
+ }
+} '{' cluster_items '}' ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (yy_conf->name == NULL)
+ DupString(yy_conf->name, "*");
+ yy_conf = NULL;
+ }
+};
+
+cluster_items: cluster_items cluster_item | cluster_item;
+cluster_item: cluster_name | cluster_type | error ';' ;
+
+cluster_name: NAME '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ DupString(yy_conf->name, yylval.string);
+};
+
+cluster_type: TYPE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_conf->flags = 0;
+} '=' cluster_types ';' ;
+
+cluster_types: cluster_types ',' cluster_type_item | cluster_type_item;
+cluster_type_item: KLINE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_conf->flags |= SHARED_KLINE;
+} | UNKLINE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_conf->flags |= SHARED_UNKLINE;
+} | T_DLINE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_conf->flags |= SHARED_DLINE;
+} | T_UNDLINE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_conf->flags |= SHARED_UNDLINE;
+} | XLINE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_conf->flags |= SHARED_XLINE;
+} | T_UNXLINE
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_conf->flags |= SHARED_UNXLINE;
+} | RESV
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_conf->flags |= SHARED_RESV;
+} | T_UNRESV
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_conf->flags |= SHARED_UNRESV;
+} | T_LOCOPS
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_conf->flags |= SHARED_LOCOPS;
+} | T_ALL
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_conf->flags = SHARED_ALL;
+};
+
+/***************************************************************************
+ * section connect
+ ***************************************************************************/
+connect_entry: CONNECT
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ yy_conf = make_conf_item(SERVER_TYPE);
+ yy_aconf = map_to_conf(yy_conf);
+
+ /* defaults */
+ yy_aconf->port = PORTNUM;
+ }
+ else
+ {
+ MyFree(class_name);
+ class_name = NULL;
+ }
+} '{' connect_items '}' ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (yy_aconf->host && yy_aconf->passwd && yy_aconf->spasswd)
+ {
+ if (conf_add_server(yy_conf, class_name) == -1)
+ delete_conf_item(yy_conf);
+ }
+ else
+ {
+ if (yy_conf->name != NULL)
+ {
+ if (yy_aconf->host == NULL)
+ yyerror("Ignoring connect block -- missing host");
+ else if (!yy_aconf->passwd || !yy_aconf->spasswd)
+ yyerror("Ignoring connect block -- missing password");
+ }
+
+ /* XXX
+ * This fixes a try_connections() core (caused by invalid class_ptr
+ * pointers) reported by metalrock. That's an ugly fix, but there
+ * is currently no better way. The entire config subsystem needs an
+ * rewrite ASAP. make_conf_item() shouldn't really add things onto
+ * a doubly linked list immediately without any sanity checks! -Michael
+ */
+ delete_conf_item(yy_conf);
+ }
+
+ MyFree(class_name);
+ class_name = NULL;
+ yy_conf = NULL;
+ yy_aconf = NULL;
+ }
+};
+
+connect_items: connect_items connect_item | connect_item;
+connect_item: connect_name | connect_host | connect_vhost |
+ connect_send_password | connect_accept_password |
+ connect_aftype | connect_port | connect_ssl_cipher_list |
+ connect_flags | connect_hub_mask | connect_leaf_mask |
+ connect_class | connect_encrypted |
+ error ';' ;
+
+connect_name: NAME '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(yy_conf->name);
+ DupString(yy_conf->name, yylval.string);
+ }
+};
+
+connect_host: HOST '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(yy_aconf->host);
+ DupString(yy_aconf->host, yylval.string);
+ }
+};
+
+connect_vhost: VHOST '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ struct addrinfo hints, *res;
+
+ memset(&hints, 0, sizeof(hints));
+
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
+
+ if (getaddrinfo(yylval.string, NULL, &hints, &res))
+ ilog(LOG_TYPE_IRCD, "Invalid netmask for server vhost(%s)", yylval.string);
+ else
+ {
+ assert(res != NULL);
+
+ memcpy(&yy_aconf->bind, res->ai_addr, res->ai_addrlen);
+ yy_aconf->bind.ss.ss_family = res->ai_family;
+ yy_aconf->bind.ss_len = res->ai_addrlen;
+ freeaddrinfo(res);
+ }
+ }
+};
+
+connect_send_password: SEND_PASSWORD '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ if ($3[0] == ':')
+ yyerror("Server passwords cannot begin with a colon");
+ else if (strchr($3, ' ') != NULL)
+ yyerror("Server passwords cannot contain spaces");
+ else {
+ if (yy_aconf->spasswd != NULL)
+ memset(yy_aconf->spasswd, 0, strlen(yy_aconf->spasswd));
+
+ MyFree(yy_aconf->spasswd);
+ DupString(yy_aconf->spasswd, yylval.string);
+ }
+ }
+};
+
+connect_accept_password: ACCEPT_PASSWORD '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ if ($3[0] == ':')
+ yyerror("Server passwords cannot begin with a colon");
+ else if (strchr($3, ' ') != NULL)
+ yyerror("Server passwords cannot contain spaces");
+ else {
+ if (yy_aconf->passwd != NULL)
+ memset(yy_aconf->passwd, 0, strlen(yy_aconf->passwd));
+
+ MyFree(yy_aconf->passwd);
+ DupString(yy_aconf->passwd, yylval.string);
+ }
+ }
+};
+
+connect_port: PORT '=' NUMBER ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->port = $3;
+};
+
+connect_aftype: AFTYPE '=' T_IPV4 ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->aftype = AF_INET;
+} | AFTYPE '=' T_IPV6 ';'
+{
+#ifdef IPV6
+ if (conf_parser_ctx.pass == 2)
+ yy_aconf->aftype = AF_INET6;
+#endif
+};
+
+connect_flags: IRCD_FLAGS
+{
+} '=' connect_flags_items ';';
+
+connect_flags_items: connect_flags_items ',' connect_flags_item | connect_flags_item;
+connect_flags_item: AUTOCONN
+{
+ if (conf_parser_ctx.pass == 2)
+ SetConfAllowAutoConn(yy_aconf);
+} | T_SSL
+{
+ if (conf_parser_ctx.pass == 2)
+ SetConfSSL(yy_aconf);
+};
+
+connect_encrypted: ENCRYPTED '=' TBOOL ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (yylval.number)
+ yy_aconf->flags |= CONF_FLAGS_ENCRYPTED;
+ else
+ yy_aconf->flags &= ~CONF_FLAGS_ENCRYPTED;
+ }
+};
+
+connect_hub_mask: HUB_MASK '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ char *mask;
+
+ DupString(mask, yylval.string);
+ dlinkAdd(mask, make_dlink_node(), &yy_aconf->hub_list);
+ }
+};
+
+connect_leaf_mask: LEAF_MASK '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ char *mask;
+
+ DupString(mask, yylval.string);
+ dlinkAdd(mask, make_dlink_node(), &yy_aconf->leaf_list);
+ }
+};
+
+connect_class: CLASS '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(class_name);
+ DupString(class_name, yylval.string);
+ }
+};
+
+connect_ssl_cipher_list: T_SSL_CIPHER_LIST '=' QSTRING ';'
+{
+#ifdef HAVE_LIBCRYPTO
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(yy_aconf->cipher_list);
+ DupString(yy_aconf->cipher_list, yylval.string);
+ }
+#else
+ if (conf_parser_ctx.pass == 2)
+ yyerror("Ignoring connect::ciphers -- no OpenSSL support");
+#endif
+};
+
+
+/***************************************************************************
+ * section kill
+ ***************************************************************************/
+kill_entry: KILL
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ userbuf[0] = hostbuf[0] = reasonbuf[0] = '\0';
+ regex_ban = 0;
+ }
+} '{' kill_items '}' ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (userbuf[0] && hostbuf[0])
+ {
+ if (regex_ban)
+ {
+#ifdef HAVE_LIBPCRE
+ void *exp_user = NULL;
+ void *exp_host = NULL;
+ const char *errptr = NULL;
+
+ if (!(exp_user = ircd_pcre_compile(userbuf, &errptr)) ||
+ !(exp_host = ircd_pcre_compile(hostbuf, &errptr)))
+ {
+ ilog(LOG_TYPE_IRCD, "Failed to add regular expression based K-Line: %s",
+ errptr);
+ break;
+ }
+
+ yy_aconf = map_to_conf(make_conf_item(RKLINE_TYPE));
+ yy_aconf->regexuser = exp_user;
+ yy_aconf->regexhost = exp_host;
+
+ DupString(yy_aconf->user, userbuf);
+ DupString(yy_aconf->host, hostbuf);
+
+ if (reasonbuf[0])
+ DupString(yy_aconf->reason, reasonbuf);
+ else
+ DupString(yy_aconf->reason, "No reason");
+#else
+ ilog(LOG_TYPE_IRCD, "Failed to add regular expression based K-Line: no PCRE support");
+ break;
+#endif
+ }
+ else
+ {
+ find_and_delete_temporary(userbuf, hostbuf, CONF_KLINE);
+
+ yy_aconf = map_to_conf(make_conf_item(KLINE_TYPE));
+
+ DupString(yy_aconf->user, userbuf);
+ DupString(yy_aconf->host, hostbuf);
+
+ if (reasonbuf[0])
+ DupString(yy_aconf->reason, reasonbuf);
+ else
+ DupString(yy_aconf->reason, "No reason");
+ add_conf_by_address(CONF_KLINE, yy_aconf);
+ }
+ }
+
+ yy_aconf = NULL;
+ }
+};
+
+kill_type: TYPE
+{
+} '=' kill_type_items ';';
+
+kill_type_items: kill_type_items ',' kill_type_item | kill_type_item;
+kill_type_item: REGEX_T
+{
+ if (conf_parser_ctx.pass == 2)
+ regex_ban = 1;
+};
+
+kill_items: kill_items kill_item | kill_item;
+kill_item: kill_user | kill_reason | kill_type | error;
+
+kill_user: USER '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ struct split_nuh_item nuh;
+
+ nuh.nuhmask = yylval.string;
+ nuh.nickptr = NULL;
+ nuh.userptr = userbuf;
+ nuh.hostptr = hostbuf;
+
+ nuh.nicksize = 0;
+ nuh.usersize = sizeof(userbuf);
+ nuh.hostsize = sizeof(hostbuf);
+
+ split_nuh(&nuh);
+ }
+};
+
+kill_reason: REASON '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ strlcpy(reasonbuf, yylval.string, sizeof(reasonbuf));
+};
+
+/***************************************************************************
+ * section deny
+ ***************************************************************************/
+deny_entry: DENY
+{
+ if (conf_parser_ctx.pass == 2)
+ hostbuf[0] = reasonbuf[0] = '\0';
+} '{' deny_items '}' ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (hostbuf[0] && parse_netmask(hostbuf, NULL, NULL) != HM_HOST)
+ {
+ find_and_delete_temporary(NULL, hostbuf, CONF_DLINE);
+
+ yy_aconf = map_to_conf(make_conf_item(DLINE_TYPE));
+ DupString(yy_aconf->host, hostbuf);
+
+ if (reasonbuf[0])
+ DupString(yy_aconf->reason, reasonbuf);
+ else
+ DupString(yy_aconf->reason, "No reason");
+ add_conf_by_address(CONF_DLINE, yy_aconf);
+ yy_aconf = NULL;
+ }
+ }
+};
+
+deny_items: deny_items deny_item | deny_item;
+deny_item: deny_ip | deny_reason | error;
+
+deny_ip: IP '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ strlcpy(hostbuf, yylval.string, sizeof(hostbuf));
+};
+
+deny_reason: REASON '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ strlcpy(reasonbuf, yylval.string, sizeof(reasonbuf));
+};
+
+/***************************************************************************
+ * section exempt
+ ***************************************************************************/
+exempt_entry: EXEMPT '{' exempt_items '}' ';';
+
+exempt_items: exempt_items exempt_item | exempt_item;
+exempt_item: exempt_ip | error;
+
+exempt_ip: IP '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (yylval.string[0] && parse_netmask(yylval.string, NULL, NULL) != HM_HOST)
+ {
+ yy_aconf = map_to_conf(make_conf_item(EXEMPTDLINE_TYPE));
+ DupString(yy_aconf->host, yylval.string);
+
+ add_conf_by_address(CONF_EXEMPTDLINE, yy_aconf);
+ yy_aconf = NULL;
+ }
+ }
+};
+
+/***************************************************************************
+ * section gecos
+ ***************************************************************************/
+gecos_entry: GECOS
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ regex_ban = 0;
+ reasonbuf[0] = gecos_name[0] = '\0';
+ }
+} '{' gecos_items '}' ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (gecos_name[0])
+ {
+ if (regex_ban)
+ {
+#ifdef HAVE_LIBPCRE
+ void *exp_p = NULL;
+ const char *errptr = NULL;
+
+ if (!(exp_p = ircd_pcre_compile(gecos_name, &errptr)))
+ {
+ ilog(LOG_TYPE_IRCD, "Failed to add regular expression based X-Line: %s",
+ errptr);
+ break;
+ }
+
+ yy_conf = make_conf_item(RXLINE_TYPE);
+ yy_conf->regexpname = exp_p;
+#else
+ ilog(LOG_TYPE_IRCD, "Failed to add regular expression based X-Line: no PCRE support");
+ break;
+#endif
+ }
+ else
+ yy_conf = make_conf_item(XLINE_TYPE);
+
+ yy_match_item = map_to_conf(yy_conf);
+ DupString(yy_conf->name, gecos_name);
+
+ if (reasonbuf[0])
+ DupString(yy_match_item->reason, reasonbuf);
+ else
+ DupString(yy_match_item->reason, "No reason");
+ }
+ }
+};
+
+gecos_flags: TYPE
+{
+} '=' gecos_flags_items ';';
+
+gecos_flags_items: gecos_flags_items ',' gecos_flags_item | gecos_flags_item;
+gecos_flags_item: REGEX_T
+{
+ if (conf_parser_ctx.pass == 2)
+ regex_ban = 1;
+};
+
+gecos_items: gecos_items gecos_item | gecos_item;
+gecos_item: gecos_name | gecos_reason | gecos_flags | error;
+
+gecos_name: NAME '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ strlcpy(gecos_name, yylval.string, sizeof(gecos_name));
+};
+
+gecos_reason: REASON '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ strlcpy(reasonbuf, yylval.string, sizeof(reasonbuf));
+};
+
+/***************************************************************************
+ * section general
+ ***************************************************************************/
+general_entry: GENERAL
+ '{' general_items '}' ';';
+
+general_items: general_items general_item | general_item;
+general_item: general_hide_spoof_ips | general_ignore_bogus_ts |
+ general_failed_oper_notice | general_anti_nick_flood |
+ general_max_nick_time | general_max_nick_changes |
+ general_max_accept | general_anti_spam_exit_message_time |
+ general_ts_warn_delta | general_ts_max_delta |
+ general_kill_chase_time_limit |
+ general_invisible_on_connect |
+ general_warn_no_nline | general_dots_in_ident |
+ general_stats_o_oper_only | general_stats_k_oper_only |
+ general_pace_wait | general_stats_i_oper_only |
+ general_pace_wait_simple | general_stats_P_oper_only |
+ general_short_motd | general_no_oper_flood |
+ general_true_no_oper_flood | general_oper_pass_resv |
+ general_message_locale |
+ general_oper_only_umodes | general_max_targets |
+ general_use_egd | general_egdpool_path |
+ general_oper_umodes | general_caller_id_wait |
+ general_opers_bypass_callerid | general_default_floodcount |
+ general_min_nonwildcard | general_min_nonwildcard_simple |
+ general_disable_remote_commands |
+ general_throttle_time | general_havent_read_conf |
+ general_ping_cookie |
+ general_disable_auth |
+ general_tkline_expire_notices | general_gline_enable |
+ general_gline_duration | general_gline_request_duration |
+ general_gline_min_cidr |
+ general_gline_min_cidr6 |
+ general_stats_e_disabled |
+ general_max_watch | general_services_name |
+ error;
+
+
+general_max_watch: MAX_WATCH '=' NUMBER ';'
+{
+ ConfigFileEntry.max_watch = $3;
+};
+
+general_gline_enable: GLINE_ENABLE '=' TBOOL ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ ConfigFileEntry.glines = yylval.number;
+};
+
+general_gline_duration: GLINE_DURATION '=' timespec ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ ConfigFileEntry.gline_time = $3;
+};
+
+general_gline_request_duration: GLINE_REQUEST_DURATION '=' timespec ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ ConfigFileEntry.gline_request_time = $3;
+};
+
+general_gline_min_cidr: GLINE_MIN_CIDR '=' NUMBER ';'
+{
+ ConfigFileEntry.gline_min_cidr = $3;
+};
+
+general_gline_min_cidr6: GLINE_MIN_CIDR6 '=' NUMBER ';'
+{
+ ConfigFileEntry.gline_min_cidr6 = $3;
+};
+
+general_tkline_expire_notices: TKLINE_EXPIRE_NOTICES '=' TBOOL ';'
+{
+ ConfigFileEntry.tkline_expire_notices = yylval.number;
+};
+
+general_kill_chase_time_limit: KILL_CHASE_TIME_LIMIT '=' timespec ';'
+{
+ ConfigFileEntry.kill_chase_time_limit = $3;
+};
+
+general_hide_spoof_ips: HIDE_SPOOF_IPS '=' TBOOL ';'
+{
+ ConfigFileEntry.hide_spoof_ips = yylval.number;
+};
+
+general_ignore_bogus_ts: IGNORE_BOGUS_TS '=' TBOOL ';'
+{
+ ConfigFileEntry.ignore_bogus_ts = yylval.number;
+};
+
+general_disable_remote_commands: DISABLE_REMOTE_COMMANDS '=' TBOOL ';'
+{
+ ConfigFileEntry.disable_remote = yylval.number;
+};
+
+general_failed_oper_notice: FAILED_OPER_NOTICE '=' TBOOL ';'
+{
+ ConfigFileEntry.failed_oper_notice = yylval.number;
+};
+
+general_anti_nick_flood: ANTI_NICK_FLOOD '=' TBOOL ';'
+{
+ ConfigFileEntry.anti_nick_flood = yylval.number;
+};
+
+general_max_nick_time: MAX_NICK_TIME '=' timespec ';'
+{
+ ConfigFileEntry.max_nick_time = $3;
+};
+
+general_max_nick_changes: MAX_NICK_CHANGES '=' NUMBER ';'
+{
+ ConfigFileEntry.max_nick_changes = $3;
+};
+
+general_max_accept: MAX_ACCEPT '=' NUMBER ';'
+{
+ ConfigFileEntry.max_accept = $3;
+};
+
+general_anti_spam_exit_message_time: ANTI_SPAM_EXIT_MESSAGE_TIME '=' timespec ';'
+{
+ ConfigFileEntry.anti_spam_exit_message_time = $3;
+};
+
+general_ts_warn_delta: TS_WARN_DELTA '=' timespec ';'
+{
+ ConfigFileEntry.ts_warn_delta = $3;
+};
+
+general_ts_max_delta: TS_MAX_DELTA '=' timespec ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ ConfigFileEntry.ts_max_delta = $3;
+};
+
+general_havent_read_conf: HAVENT_READ_CONF '=' NUMBER ';'
+{
+ if (($3 > 0) && conf_parser_ctx.pass == 1)
+ {
+ ilog(LOG_TYPE_IRCD, "You haven't read your config file properly.");
+ ilog(LOG_TYPE_IRCD, "There is a line in the example conf that will kill your server if not removed.");
+ ilog(LOG_TYPE_IRCD, "Consider actually reading/editing the conf file, and removing this line.");
+ exit(0);
+ }
+};
+
+general_invisible_on_connect: INVISIBLE_ON_CONNECT '=' TBOOL ';'
+{
+ ConfigFileEntry.invisible_on_connect = yylval.number;
+};
+
+general_warn_no_nline: WARN_NO_NLINE '=' TBOOL ';'
+{
+ ConfigFileEntry.warn_no_nline = yylval.number;
+};
+
+general_stats_e_disabled: STATS_E_DISABLED '=' TBOOL ';'
+{
+ ConfigFileEntry.stats_e_disabled = yylval.number;
+};
+
+general_stats_o_oper_only: STATS_O_OPER_ONLY '=' TBOOL ';'
+{
+ ConfigFileEntry.stats_o_oper_only = yylval.number;
+};
+
+general_stats_P_oper_only: STATS_P_OPER_ONLY '=' TBOOL ';'
+{
+ ConfigFileEntry.stats_P_oper_only = yylval.number;
+};
+
+general_stats_k_oper_only: STATS_K_OPER_ONLY '=' TBOOL ';'
+{
+ ConfigFileEntry.stats_k_oper_only = 2 * yylval.number;
+} | STATS_K_OPER_ONLY '=' TMASKED ';'
+{
+ ConfigFileEntry.stats_k_oper_only = 1;
+};
+
+general_stats_i_oper_only: STATS_I_OPER_ONLY '=' TBOOL ';'
+{
+ ConfigFileEntry.stats_i_oper_only = 2 * yylval.number;
+} | STATS_I_OPER_ONLY '=' TMASKED ';'
+{
+ ConfigFileEntry.stats_i_oper_only = 1;
+};
+
+general_pace_wait: PACE_WAIT '=' timespec ';'
+{
+ ConfigFileEntry.pace_wait = $3;
+};
+
+general_caller_id_wait: CALLER_ID_WAIT '=' timespec ';'
+{
+ ConfigFileEntry.caller_id_wait = $3;
+};
+
+general_opers_bypass_callerid: OPERS_BYPASS_CALLERID '=' TBOOL ';'
+{
+ ConfigFileEntry.opers_bypass_callerid = yylval.number;
+};
+
+general_pace_wait_simple: PACE_WAIT_SIMPLE '=' timespec ';'
+{
+ ConfigFileEntry.pace_wait_simple = $3;
+};
+
+general_short_motd: SHORT_MOTD '=' TBOOL ';'
+{
+ ConfigFileEntry.short_motd = yylval.number;
+};
+
+general_no_oper_flood: NO_OPER_FLOOD '=' TBOOL ';'
+{
+ ConfigFileEntry.no_oper_flood = yylval.number;
+};
+
+general_true_no_oper_flood: TRUE_NO_OPER_FLOOD '=' TBOOL ';'
+{
+ ConfigFileEntry.true_no_oper_flood = yylval.number;
+};
+
+general_oper_pass_resv: OPER_PASS_RESV '=' TBOOL ';'
+{
+ ConfigFileEntry.oper_pass_resv = yylval.number;
+};
+
+general_message_locale: MESSAGE_LOCALE '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (strlen(yylval.string) > LOCALE_LENGTH-2)
+ yylval.string[LOCALE_LENGTH-1] = '\0';
+
+ set_locale(yylval.string);
+ }
+};
+
+general_dots_in_ident: DOTS_IN_IDENT '=' NUMBER ';'
+{
+ ConfigFileEntry.dots_in_ident = $3;
+};
+
+general_max_targets: MAX_TARGETS '=' NUMBER ';'
+{
+ ConfigFileEntry.max_targets = $3;
+};
+
+general_use_egd: USE_EGD '=' TBOOL ';'
+{
+ ConfigFileEntry.use_egd = yylval.number;
+};
+
+general_egdpool_path: EGDPOOL_PATH '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(ConfigFileEntry.egdpool_path);
+ DupString(ConfigFileEntry.egdpool_path, yylval.string);
+ }
+};
+
+general_services_name: T_SERVICES_NAME '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2 && valid_servname(yylval.string))
+ {
+ MyFree(ConfigFileEntry.service_name);
+ DupString(ConfigFileEntry.service_name, yylval.string);
+ }
+};
+
+general_ping_cookie: PING_COOKIE '=' TBOOL ';'
+{
+ ConfigFileEntry.ping_cookie = yylval.number;
+};
+
+general_disable_auth: DISABLE_AUTH '=' TBOOL ';'
+{
+ ConfigFileEntry.disable_auth = yylval.number;
+};
+
+general_throttle_time: THROTTLE_TIME '=' timespec ';'
+{
+ ConfigFileEntry.throttle_time = yylval.number;
+};
+
+general_oper_umodes: OPER_UMODES
+{
+ ConfigFileEntry.oper_umodes = 0;
+} '=' umode_oitems ';' ;
+
+umode_oitems: umode_oitems ',' umode_oitem | umode_oitem;
+umode_oitem: T_BOTS
+{
+ ConfigFileEntry.oper_umodes |= UMODE_BOTS;
+} | T_CCONN
+{
+ ConfigFileEntry.oper_umodes |= UMODE_CCONN;
+} | T_CCONN_FULL
+{
+ ConfigFileEntry.oper_umodes |= UMODE_CCONN_FULL;
+} | T_DEAF
+{
+ ConfigFileEntry.oper_umodes |= UMODE_DEAF;
+} | T_DEBUG
+{
+ ConfigFileEntry.oper_umodes |= UMODE_DEBUG;
+} | T_FULL
+{
+ ConfigFileEntry.oper_umodes |= UMODE_FULL;
+} | HIDDEN
+{
+ ConfigFileEntry.oper_umodes |= UMODE_HIDDEN;
+} | T_SKILL
+{
+ ConfigFileEntry.oper_umodes |= UMODE_SKILL;
+} | T_NCHANGE
+{
+ ConfigFileEntry.oper_umodes |= UMODE_NCHANGE;
+} | T_REJ
+{
+ ConfigFileEntry.oper_umodes |= UMODE_REJ;
+} | T_UNAUTH
+{
+ ConfigFileEntry.oper_umodes |= UMODE_UNAUTH;
+} | T_SPY
+{
+ ConfigFileEntry.oper_umodes |= UMODE_SPY;
+} | T_EXTERNAL
+{
+ ConfigFileEntry.oper_umodes |= UMODE_EXTERNAL;
+} | T_OPERWALL
+{
+ ConfigFileEntry.oper_umodes |= UMODE_OPERWALL;
+} | T_SERVNOTICE
+{
+ ConfigFileEntry.oper_umodes |= UMODE_SERVNOTICE;
+} | T_INVISIBLE
+{
+ ConfigFileEntry.oper_umodes |= UMODE_INVISIBLE;
+} | T_WALLOP
+{
+ ConfigFileEntry.oper_umodes |= UMODE_WALLOP;
+} | T_SOFTCALLERID
+{
+ ConfigFileEntry.oper_umodes |= UMODE_SOFTCALLERID;
+} | T_CALLERID
+{
+ ConfigFileEntry.oper_umodes |= UMODE_CALLERID;
+} | T_LOCOPS
+{
+ ConfigFileEntry.oper_umodes |= UMODE_LOCOPS;
+};
+
+general_oper_only_umodes: OPER_ONLY_UMODES
+{
+ ConfigFileEntry.oper_only_umodes = 0;
+} '=' umode_items ';' ;
+
+umode_items: umode_items ',' umode_item | umode_item;
+umode_item: T_BOTS
+{
+ ConfigFileEntry.oper_only_umodes |= UMODE_BOTS;
+} | T_CCONN
+{
+ ConfigFileEntry.oper_only_umodes |= UMODE_CCONN;
+} | T_CCONN_FULL
+{
+ ConfigFileEntry.oper_only_umodes |= UMODE_CCONN_FULL;
+} | T_DEAF
+{
+ ConfigFileEntry.oper_only_umodes |= UMODE_DEAF;
+} | T_DEBUG
+{
+ ConfigFileEntry.oper_only_umodes |= UMODE_DEBUG;
+} | T_FULL
+{
+ ConfigFileEntry.oper_only_umodes |= UMODE_FULL;
+} | T_SKILL
+{
+ ConfigFileEntry.oper_only_umodes |= UMODE_SKILL;
+} | HIDDEN
+{
+ ConfigFileEntry.oper_only_umodes |= UMODE_HIDDEN;
+} | T_NCHANGE
+{
+ ConfigFileEntry.oper_only_umodes |= UMODE_NCHANGE;
+} | T_REJ
+{
+ ConfigFileEntry.oper_only_umodes |= UMODE_REJ;
+} | T_UNAUTH
+{
+ ConfigFileEntry.oper_only_umodes |= UMODE_UNAUTH;
+} | T_SPY
+{
+ ConfigFileEntry.oper_only_umodes |= UMODE_SPY;
+} | T_EXTERNAL
+{
+ ConfigFileEntry.oper_only_umodes |= UMODE_EXTERNAL;
+} | T_OPERWALL
+{
+ ConfigFileEntry.oper_only_umodes |= UMODE_OPERWALL;
+} | T_SERVNOTICE
+{
+ ConfigFileEntry.oper_only_umodes |= UMODE_SERVNOTICE;
+} | T_INVISIBLE
+{
+ ConfigFileEntry.oper_only_umodes |= UMODE_INVISIBLE;
+} | T_WALLOP
+{
+ ConfigFileEntry.oper_only_umodes |= UMODE_WALLOP;
+} | T_SOFTCALLERID
+{
+ ConfigFileEntry.oper_only_umodes |= UMODE_SOFTCALLERID;
+} | T_CALLERID
+{
+ ConfigFileEntry.oper_only_umodes |= UMODE_CALLERID;
+} | T_LOCOPS
+{
+ ConfigFileEntry.oper_only_umodes |= UMODE_LOCOPS;
+};
+
+general_min_nonwildcard: MIN_NONWILDCARD '=' NUMBER ';'
+{
+ ConfigFileEntry.min_nonwildcard = $3;
+};
+
+general_min_nonwildcard_simple: MIN_NONWILDCARD_SIMPLE '=' NUMBER ';'
+{
+ ConfigFileEntry.min_nonwildcard_simple = $3;
+};
+
+general_default_floodcount: DEFAULT_FLOODCOUNT '=' NUMBER ';'
+{
+ ConfigFileEntry.default_floodcount = $3;
+};
+
+
+/***************************************************************************
+ * section channel
+ ***************************************************************************/
+channel_entry: CHANNEL
+ '{' channel_items '}' ';';
+
+channel_items: channel_items channel_item | channel_item;
+channel_item: channel_max_bans |
+ channel_knock_delay | channel_knock_delay_channel |
+ channel_max_chans_per_user | channel_max_chans_per_oper |
+ channel_quiet_on_ban | channel_default_split_user_count |
+ channel_default_split_server_count |
+ channel_no_create_on_split | channel_restrict_channels |
+ channel_no_join_on_split |
+ channel_jflood_count | channel_jflood_time |
+ channel_disable_fake_channels | error;
+
+channel_disable_fake_channels: DISABLE_FAKE_CHANNELS '=' TBOOL ';'
+{
+ ConfigChannel.disable_fake_channels = yylval.number;
+};
+
+channel_restrict_channels: RESTRICT_CHANNELS '=' TBOOL ';'
+{
+ ConfigChannel.restrict_channels = yylval.number;
+};
+
+channel_knock_delay: KNOCK_DELAY '=' timespec ';'
+{
+ ConfigChannel.knock_delay = $3;
+};
+
+channel_knock_delay_channel: KNOCK_DELAY_CHANNEL '=' timespec ';'
+{
+ ConfigChannel.knock_delay_channel = $3;
+};
+
+channel_max_chans_per_user: MAX_CHANS_PER_USER '=' NUMBER ';'
+{
+ ConfigChannel.max_chans_per_user = $3;
+};
+
+channel_max_chans_per_oper: MAX_CHANS_PER_OPER '=' NUMBER ';'
+{
+ ConfigChannel.max_chans_per_oper = $3;
+};
+
+channel_quiet_on_ban: QUIET_ON_BAN '=' TBOOL ';'
+{
+ ConfigChannel.quiet_on_ban = yylval.number;
+};
+
+channel_max_bans: MAX_BANS '=' NUMBER ';'
+{
+ ConfigChannel.max_bans = $3;
+};
+
+channel_default_split_user_count: DEFAULT_SPLIT_USER_COUNT '=' NUMBER ';'
+{
+ ConfigChannel.default_split_user_count = $3;
+};
+
+channel_default_split_server_count: DEFAULT_SPLIT_SERVER_COUNT '=' NUMBER ';'
+{
+ ConfigChannel.default_split_server_count = $3;
+};
+
+channel_no_create_on_split: NO_CREATE_ON_SPLIT '=' TBOOL ';'
+{
+ ConfigChannel.no_create_on_split = yylval.number;
+};
+
+channel_no_join_on_split: NO_JOIN_ON_SPLIT '=' TBOOL ';'
+{
+ ConfigChannel.no_join_on_split = yylval.number;
+};
+
+channel_jflood_count: JOIN_FLOOD_COUNT '=' NUMBER ';'
+{
+ GlobalSetOptions.joinfloodcount = yylval.number;
+};
+
+channel_jflood_time: JOIN_FLOOD_TIME '=' timespec ';'
+{
+ GlobalSetOptions.joinfloodtime = yylval.number;
+};
+
+/***************************************************************************
+ * section serverhide
+ ***************************************************************************/
+serverhide_entry: SERVERHIDE
+ '{' serverhide_items '}' ';';
+
+serverhide_items: serverhide_items serverhide_item | serverhide_item;
+serverhide_item: serverhide_flatten_links | serverhide_hide_servers |
+ serverhide_links_delay |
+ serverhide_hidden | serverhide_hidden_name |
+ serverhide_hide_server_ips |
+ error;
+
+serverhide_flatten_links: FLATTEN_LINKS '=' TBOOL ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ ConfigServerHide.flatten_links = yylval.number;
+};
+
+serverhide_hide_servers: HIDE_SERVERS '=' TBOOL ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ ConfigServerHide.hide_servers = yylval.number;
+};
+
+serverhide_hidden_name: HIDDEN_NAME '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ MyFree(ConfigServerHide.hidden_name);
+ DupString(ConfigServerHide.hidden_name, yylval.string);
+ }
+};
+
+serverhide_links_delay: LINKS_DELAY '=' timespec ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ if (($3 > 0) && ConfigServerHide.links_disabled == 1)
+ {
+ eventAddIsh("write_links_file", write_links_file, NULL, $3);
+ ConfigServerHide.links_disabled = 0;
+ }
+
+ ConfigServerHide.links_delay = $3;
+ }
+};
+
+serverhide_hidden: HIDDEN '=' TBOOL ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ ConfigServerHide.hidden = yylval.number;
+};
+
+serverhide_hide_server_ips: HIDE_SERVER_IPS '=' TBOOL ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ ConfigServerHide.hide_server_ips = yylval.number;
+};
diff --git a/src/csvlib.c b/src/csvlib.c
new file mode 100644
index 0000000..0b6034d
--- /dev/null
+++ b/src/csvlib.c
@@ -0,0 +1,671 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * csvlib.c - set of functions to deal with csv type of conf files
+ *
+ * Copyright (C) 2003 by Diane Bruce, Stuart Walsh
+ * Use it anywhere you like, if you like it buy us a beer.
+ * If it's broken, don't bother us with the lawyers.
+ *
+ * $Id$
+ */
+
+#include "config.h"
+#include "stdinc.h"
+#include "list.h"
+#include "log.h"
+#include "conf.h"
+#include "hostmask.h"
+#include "client.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "memory.h"
+#include "send.h"
+#include "resv.h"
+#include "s_serv.h"
+
+/* Fix "statement not reached" warnings on Sun WorkShop C */
+#ifdef __SUNPRO_C
+# pragma error_messages(off, E_STATEMENT_NOT_REACHED)
+#endif
+
+
+static void parse_csv_line(char *, ...);
+static int write_csv_line(FILE *, const char *, ...);
+static int flush_write(struct Client *, FILE *, FILE *,
+ const char *, const char *);
+static char *getfield(char *);
+
+int
+find_and_delete_temporary(const char *user, const char *host, int type)
+{
+ struct irc_ssaddr iphost, *piphost;
+ struct AccessItem *aconf;
+ int t;
+
+ if ((t = parse_netmask(host, &iphost, NULL)) != HM_HOST)
+ {
+#ifdef IPV6
+ if (t == HM_IPV6)
+ t = AF_INET6;
+ else
+#endif
+ t = AF_INET;
+ piphost = &iphost;
+ }
+ else
+ {
+ t = 0;
+ piphost = NULL;
+ }
+
+ if ((aconf = find_conf_by_address(host, piphost, type, t, user, NULL, 0)))
+ {
+ if (IsConfTemporary(aconf))
+ {
+ delete_one_address_conf(host, aconf);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* parse_csv_file()
+ *
+ * inputs - FILE pointer
+ * - type of conf to parse
+ * output - none
+ * side effects -
+ */
+void
+parse_csv_file(FILE *file, ConfType conf_type)
+{
+ struct ConfItem *conf;
+ struct AccessItem *aconf;
+ struct MatchItem *match_item;
+ char *name_field=NULL;
+ char *user_field=NULL;
+ char *reason_field=NULL;
+ char *oper_reason=NULL;
+ char *host_field=NULL;
+ char line[IRCD_BUFSIZE];
+ char *p;
+
+ while (fgets(line, sizeof(line), file) != NULL)
+ {
+ if ((p = strchr(line, '\n')) != NULL)
+ *p = '\0';
+
+ if ((line[0] == '\0') || (line[0] == '#'))
+ continue;
+
+ switch(conf_type)
+ {
+ case KLINE_TYPE:
+ parse_csv_line(line, &user_field, &host_field, &reason_field, NULL);
+
+ find_and_delete_temporary(user_field, host_field, CONF_KLINE);
+
+ conf = make_conf_item(KLINE_TYPE);
+ aconf = map_to_conf(conf);
+
+ if (host_field != NULL)
+ DupString(aconf->host, host_field);
+ if (reason_field != NULL)
+ DupString(aconf->reason, reason_field);
+ if (user_field != NULL)
+ DupString(aconf->user, user_field);
+ if (aconf->host != NULL)
+ add_conf_by_address(CONF_KLINE, aconf);
+ break;
+ case DLINE_TYPE:
+ parse_csv_line(line, &host_field, &reason_field, NULL);
+
+ if (host_field && parse_netmask(host_field, NULL, NULL) != HM_HOST)
+ {
+ find_and_delete_temporary(NULL, host_field, CONF_DLINE);
+
+ aconf = map_to_conf(make_conf_item(DLINE_TYPE));
+ DupString(aconf->host, host_field);
+
+ if (reason_field != NULL)
+ DupString(aconf->reason, reason_field);
+ else
+ DupString(aconf->reason, "No reason");
+ add_conf_by_address(CONF_DLINE, aconf);
+ }
+
+ break;
+
+ case XLINE_TYPE:
+ parse_csv_line(line, &name_field, &reason_field, &oper_reason, NULL);
+ conf = make_conf_item(XLINE_TYPE);
+ match_item = (struct MatchItem *)map_to_conf(conf);
+ if (name_field != NULL)
+ DupString(conf->name, name_field);
+ if (reason_field != NULL)
+ DupString(match_item->reason, reason_field);
+ break;
+ case CRESV_TYPE:
+ parse_csv_line(line, &name_field, &reason_field, NULL);
+ (void)create_channel_resv(name_field, reason_field, 0);
+ break;
+
+ case NRESV_TYPE:
+ parse_csv_line(line, &name_field, &reason_field, NULL);
+ (void)create_nick_resv(name_field, reason_field, 0);
+ break;
+
+ case GLINE_TYPE:
+ case CONF_TYPE:
+ case OPER_TYPE:
+ case CLIENT_TYPE:
+ case SERVER_TYPE:
+ case CLUSTER_TYPE:
+ case HUB_TYPE:
+ case LEAF_TYPE:
+ case ULINE_TYPE:
+ case EXEMPTDLINE_TYPE:
+ case CLASS_TYPE:
+ default:
+ break;
+ }
+ }
+}
+
+/*
+ * parse_csv_line()
+ *
+ * inputs - pointer to line to parse
+ * output -
+ * side effects -
+ */
+
+static void
+parse_csv_line(char *line, ...)
+{
+ va_list args;
+ char **dest;
+ char *field = NULL;
+
+ va_start(args, line);
+
+ for (; ;)
+ {
+ dest = va_arg(args, char **);
+ if ((dest == NULL) || ((field = getfield(field ? NULL : line)) == NULL))
+ {
+ va_end(args);
+ return;
+ }
+ *dest = field;
+ }
+}
+
+/* write_conf_line()
+ *
+ * inputs - pointer to struct AccessItem
+ * - string current_date (small date)
+ * - time_t cur_time
+ * output - NONE
+ * side effects - This function takes care of
+ * finding right conf file, writing
+ * the right lines to this file,
+ * notifying the oper that their kline/dline etc. is in place
+ * notifying the opers on the server about the k/d etc. line
+ *
+ * - Dianora
+ */
+void
+write_conf_line(struct Client *source_p, struct ConfItem *conf,
+ const char *current_date, time_t cur_time)
+{
+ FILE *out;
+ const char *filename, *from, *to;
+ struct AccessItem *aconf;
+ struct MatchItem *xconf;
+ struct ResvChannel *cresv_p=NULL;
+ struct MatchItem *nresv_p=NULL;
+ ConfType type;
+
+ type = conf->type;
+ filename = get_conf_name(type);
+
+ if (!MyConnect(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
+ {
+ from = me.id;
+ to = source_p->id;
+ }
+ else
+ {
+ from = me.name;
+ to = source_p->name;
+ }
+
+ if ((out = fopen(filename, "a")) == NULL)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "*** Problem opening %s ", filename);
+ return;
+ }
+
+ switch(type)
+ {
+ case KLINE_TYPE:
+ aconf = (struct AccessItem *)map_to_conf(conf);
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s added K-Line for [%s@%s] [%s]",
+ get_oper_name(source_p),
+ aconf->user, aconf->host, aconf->reason);
+ sendto_one(source_p, ":%s NOTICE %s :Added K-Line [%s@%s]",
+ from, to, aconf->user, aconf->host);
+ ilog(LOG_TYPE_KLINE, "%s added K-Line for [%s@%s] [%s]",
+ source_p->name, aconf->user, aconf->host, aconf->reason);
+ write_csv_line(out, "%s%s%s%s%s%s%d",
+ aconf->user, aconf->host,
+ aconf->reason, aconf->oper_reason, current_date,
+ get_oper_name(source_p), cur_time);
+ break;
+ case DLINE_TYPE:
+ aconf = (struct AccessItem *)map_to_conf(conf);
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s added D-Line for [%s] [%s]",
+ get_oper_name(source_p), aconf->host, aconf->reason);
+ sendto_one(source_p, ":%s NOTICE %s :Added D-Line [%s] to %s",
+ from, to, aconf->host, filename);
+ ilog(LOG_TYPE_DLINE, "%s added D-Line for [%s] [%s]",
+ get_oper_name(source_p), aconf->host, aconf->reason);
+ write_csv_line(out, "%s%s%s%s%s%d",
+ aconf->host, aconf->reason, aconf->oper_reason,
+ current_date,
+ get_oper_name(source_p), cur_time);
+ break;
+
+ case XLINE_TYPE:
+ xconf = (struct MatchItem *)map_to_conf(conf);
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s added X-Line for [%s] [%s]",
+ get_oper_name(source_p), conf->name,
+ xconf->reason);
+ sendto_one(source_p,
+ ":%s NOTICE %s :Added X-Line [%s] [%d] [%s] to %s",
+ from, to, conf->name,
+ xconf->action, xconf->reason, filename);
+ ilog(LOG_TYPE_IRCD, "%s added X-Line for [%s] [%s]",
+ get_oper_name(source_p), conf->name, xconf->reason);
+ write_csv_line(out, "%s%s%s%s%s%d",
+ conf->name, xconf->reason, xconf->oper_reason,
+ current_date, get_oper_name(source_p), cur_time);
+ break;
+ case CRESV_TYPE:
+ cresv_p = (struct ResvChannel *)map_to_conf(conf);
+
+ write_csv_line(out, "%s%s",
+ cresv_p->name, cresv_p->reason);
+ break;
+
+ case NRESV_TYPE:
+ nresv_p = (struct MatchItem *)map_to_conf(conf);
+
+ write_csv_line(out, "%s%s",
+ conf->name, nresv_p->reason);
+ break;
+
+ default:
+ fclose(out);
+ return;
+ }
+
+ fclose(out);
+}
+
+/*
+ * write_csv_line()
+ *
+ * inputs - pointer to FILE *
+ * - formatted string
+ * output -
+ * side effects - single line is written to csv conf file
+ */
+static int
+write_csv_line(FILE *out, const char *format, ...)
+{
+ char c;
+ size_t bytes = 0;
+ va_list args;
+ char tmp[1024];
+ char *str = tmp;
+ const char *null_string = "";
+
+ if (out == NULL)
+ return(0);
+
+ va_start(args, format);
+
+ while ((c = *format++))
+ {
+ if (c == '%')
+ {
+ c = *format++;
+ if (c == 's')
+ {
+ const char *p1 = va_arg(args, const char *);
+ if (p1 == NULL)
+ p1 = null_string;
+ *str++ = '\"';
+ ++bytes;
+ while (*p1 != '\0')
+ {
+ *str++ = *p1++;
+ ++bytes;
+ }
+ *str++ = '\"';
+ *str++ = ',';
+
+ bytes += 2;
+ continue;
+ }
+ if (c == 'c')
+ {
+ *str++ = '\"';
+ ++bytes;
+ *str++ = (char) va_arg(args, int);
+ ++bytes;
+ *str++ = '\"';
+ *str++ = ',';
+
+ bytes += 2;
+ continue;
+ }
+
+ if (c == 'd')
+ {
+ int v = va_arg(args, int);
+ char t[40];
+ char *p=t;
+
+ while (v > 10)
+ {
+ *p++ = (v % 10) + '0';
+ v = v/10;
+ }
+ *p++ = (v % 10) + '0';
+
+ *str++ = '\"';
+ ++bytes;
+ while (p != t)
+ {
+ *str++ = *--p;
+ ++bytes;
+ }
+
+ *str++ = '\"';
+ *str++ = ',';
+ bytes += 2;
+ continue;
+ }
+ if (c != '%')
+ {
+ int ret;
+
+ format -= 2;
+ ret = vsprintf(str, format, args);
+ str += ret;
+ bytes += ret;
+ *str++ = ',';
+
+ ++bytes;
+ break;
+ }
+ }
+ *str++ = c;
+ ++bytes;
+ }
+
+ if (*(str-1) == ',')
+ {
+ *(str-1) = '\n';
+ *str = '\0';
+ }
+ else
+ {
+ *str++ = '\n';
+ ++bytes;
+ *str = '\0';
+ }
+
+ va_end(args);
+ str = tmp;
+ fputs(str, out);
+
+ return(bytes);
+}
+
+/*
+ * getfield
+ *
+ * inputs - input buffer
+ * output - next field
+ * side effects - field breakup for ircd.conf file.
+ */
+static char *
+getfield(char *newline)
+{
+ static char *line = NULL;
+ char *end, *field;
+
+ if (newline != NULL)
+ line = newline;
+
+ if (line == NULL)
+ return(NULL);
+
+ field = line;
+
+ /* skip everything that's not a starting quote */
+ for(;;)
+ {
+ if (*field == '\0')
+ return(NULL);
+ else if (*field == '"')
+ break;
+ ++field;
+ }
+
+ /* skip over the beginning " */
+ end = ++field;
+
+ for (;;)
+ {
+ /* At end of string, mark it as end and return */
+ if ((*end == '\0') || (*end == '\n'))
+ {
+ line = NULL;
+ return(NULL);
+ }
+ else if (*end == '\\') /* found escape character ? */
+ {
+ end++;
+ }
+ else if (*end == '"') /* found terminating " */
+ {
+ *end++ = '\0';
+ line = end;
+ return(field);
+ }
+
+ end++;
+ }
+
+ return (NULL);
+}
+
+/* remove_conf_line()
+ *
+ * inputs - type of kline to remove
+ * - pointer to oper removing
+ * - pat1 pat2 patterns to match
+ * output - -1 if unsuccessful 0 if no change 1 if change
+ * side effects -
+ */
+int
+remove_conf_line(ConfType type, struct Client *source_p, const char *pat1, const char *pat2)
+{
+ const char *filename;
+ FILE *in, *out;
+ int pairme=0;
+ char buf[IRCD_BUFSIZE], buff[IRCD_BUFSIZE], temppath[IRCD_BUFSIZE];
+ char *found1;
+ char *found2;
+ int oldumask;
+
+ filename = get_conf_name(type);
+
+ if ((in = fopen(filename, "r")) == NULL)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :Cannot open %s", me.name,
+ source_p->name, filename);
+ return -1;
+ }
+
+ ircsprintf(temppath, "%s.tmp", filename);
+ oldumask = umask(0);
+
+ if ((out = fopen(temppath, "w")) == NULL)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :Cannot open %s", me.name,
+ source_p->name, temppath);
+ fclose(in);
+ umask(oldumask);
+ return -1;
+ }
+
+ umask(oldumask);
+ oldumask = umask(0);
+
+ while (fgets(buf, sizeof(buf), in) != NULL)
+ {
+ if ((*buf == '\0') || (*buf == '#'))
+ {
+ if (flush_write(source_p, in, out, buf, temppath) < 0)
+ return -1;
+ }
+
+ /* Keep copy of original line, getfield trashes line as it goes */
+ strlcpy(buff, buf, sizeof(buff));
+
+ if ((found1 = getfield(buff)) == NULL)
+ {
+ if (flush_write(source_p, in, out, buf, temppath) < 0)
+ return -1;
+ continue;
+ }
+
+ if (pat2 != NULL)
+ {
+ if ((found2 = getfield(NULL)) == NULL)
+ {
+ if (flush_write(source_p, in, out, buf, temppath) < 0)
+ return -1;
+ continue;
+ }
+
+ if (!irccmp(pat1, found1) && !irccmp(pat2, found2))
+ {
+ pairme = 1;
+ continue;
+ }
+ else
+ {
+ if(flush_write(source_p, in, out, buf, temppath) < 0)
+ return -1;
+ continue;
+ }
+ }
+ else
+ {
+ if (!irccmp(pat1, found1))
+ {
+ pairme = 1;
+ continue;
+ }
+ else
+ {
+ if(flush_write(source_p, in, out, buf, temppath) < 0)
+ return -1;
+ continue;
+ }
+ }
+ }
+
+ fclose(in);
+ fclose(out);
+
+/* 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 (pairme == 0)
+ {
+ if(temppath != NULL)
+ (void)unlink(temppath);
+ return 0;
+ }
+ else
+ {
+ (void)rename(temppath, filename);
+
+ /* XXX
+ * This is a very inefficient way of removing a kline/xline etc.
+ * This next function call forces a complete re-read of all conf
+ * files, instead of a re-read of the kline/dline etc. files modified
+ * But, consider how often an /quote unkline etc. is done compared
+ * to how often a /quote kline is done. Its not a biggie in
+ * the grand scheme of things. If it does become a biggie,
+ * we will rewrite it - Dianora
+ */
+
+ rehash(0);
+ return 1;
+ }
+}
+
+/*
+ * flush_write()
+ *
+ * inputs - pointer to client structure of oper requesting unkline
+ * - in is the input file descriptor
+ * - out is the output 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 - -1 for error on write
+ * - 0 for ok
+ * 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 *in, FILE* out,
+ const char *buf, const char *temppath)
+{
+ int error_on_write = fputs(buf, out) < 0 ? (-1) : (0);
+
+ if (error_on_write)
+ {
+ sendto_one(source_p,":%s NOTICE %s :Unable to write to %s aborting",
+ me.name, source_p->name, temppath);
+ if(temppath != NULL)
+ (void)unlink(temppath);
+ fclose(in);
+ fclose(out);
+ }
+
+ return (error_on_write);
+}
diff --git a/src/dbuf.c b/src/dbuf.c
new file mode 100644
index 0000000..1271b86
--- /dev/null
+++ b/src/dbuf.c
@@ -0,0 +1,112 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * dbuf.c: Supports dynamic data buffers.
+ *
+ * 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$
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "balloc.h"
+#include "dbuf.h"
+#include "memory.h"
+
+static BlockHeap *dbuf_heap;
+
+void
+dbuf_init(void)
+{
+ dbuf_heap = BlockHeapCreate("dbuf", sizeof(struct dbuf_block), DBUF_HEAP_SIZE);
+}
+
+static struct dbuf_block *
+dbuf_alloc(struct dbuf_queue *qptr)
+{
+ struct dbuf_block *block = BlockHeapAlloc(dbuf_heap);
+
+ dlinkAddTail(block, make_dlink_node(), &qptr->blocks);
+ return block;
+}
+
+void
+dbuf_put(struct dbuf_queue *qptr, char *data, size_t count)
+{
+ struct dbuf_block *last;
+ size_t amount;
+
+ assert(count > 0);
+ if (qptr->blocks.tail == NULL)
+ dbuf_alloc(qptr);
+
+ do {
+ last = qptr->blocks.tail->data;
+
+ amount = DBUF_BLOCK_SIZE - last->size;
+ if (!amount)
+ {
+ last = dbuf_alloc(qptr);
+ amount = DBUF_BLOCK_SIZE;
+ }
+ if (amount > count)
+ amount = count;
+
+ memcpy((void *) &last->data[last->size], data, amount);
+ count -= amount;
+ last->size += amount;
+ qptr->total_size += amount;
+
+ data += amount;
+
+ } while (count > 0);
+}
+
+void
+dbuf_delete(struct dbuf_queue *qptr, size_t count)
+{
+ dlink_node *ptr;
+ struct dbuf_block *first;
+
+ assert(qptr->total_size >= count);
+ if (count == 0)
+ return;
+
+ /* free whole blocks first.. */
+ while (1)
+ {
+ if (!count)
+ return;
+ ptr = qptr->blocks.head;
+ first = ptr->data;
+ if (count < first->size)
+ break;
+
+ qptr->total_size -= first->size;
+ count -= first->size;
+ dlinkDelete(ptr, &qptr->blocks);
+ free_dlink_node(ptr);
+ BlockHeapFree(dbuf_heap, first);
+ }
+
+ /* ..then remove data from the beginning of the queue */
+ first->size -= count;
+ qptr->total_size -= count;
+ memmove((void *) &first->data, (void *) &first->data[count], first->size);
+}
+
diff --git a/src/event.c b/src/event.c
new file mode 100644
index 0000000..2ddc75d
--- /dev/null
+++ b/src/event.c
@@ -0,0 +1,292 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * event.c: Event functions.
+ *
+ * Copyright (C) 1998-2000 Regents of the University of California
+ * Copyright (C) 2001-2002 Hybrid 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$
+ */
+
+/*
+ * How it's 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 "list.h"
+#include "ircd.h"
+#include "event.h"
+#include "client.h"
+#include "send.h"
+#include "memory.h"
+#include "log.h"
+#include "numeric.h"
+
+static const char *last_event_ran = NULL;
+static struct ev_entry event_table[MAX_EVENTS];
+static time_t event_time_min = -1;
+static int eventFind(EVH *func, void *arg);
+
+/*
+ * 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, or use next 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;
+ }
+ }
+ /* XXX if reach here, its an error */
+ ilog(LOG_TYPE_IRCD, "Event table is full! (%d)", i);
+}
+
+/*
+ * 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 = 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_table[i].when = CurrentTime + event_table[i].frequency;
+ event_time_min = -1;
+ }
+ }
+}
+
+/*
+ * 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(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
+ */
+static 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(source_p, ":%s %d %s :Last event to run: %s",
+ me.name, RPL_STATSDEBUG, source_p->name, last_event_ran);
+ sendto_one(source_p, ":%s %d %s : ",
+ me.name, RPL_STATSDEBUG, source_p->name);
+ }
+
+ sendto_one(source_p,
+ ":%s %d %s : Operation Next Execution",
+ me.name, RPL_STATSDEBUG, source_p->name);
+ sendto_one(source_p,
+ ":%s %d %s : -------------------------------------------",
+ me.name, RPL_STATSDEBUG, source_p->name);
+
+ for (i = 0; i < MAX_EVENTS; i++)
+ if (event_table[i].active)
+ {
+ sendto_one(source_p, ":%s %d %s : %-28s %-4d seconds",
+ me.name, RPL_STATSDEBUG, source_p->name,
+ event_table[i].name,
+ (int)(event_table[i].when - CurrentTime));
+ }
+
+ sendto_one(source_p, ":%s %d %s : ",
+ me.name, RPL_STATSDEBUG, source_p->name);
+}
+
+/*
+ * 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;
+ }
+}
+
diff --git a/src/fdlist.c b/src/fdlist.c
new file mode 100644
index 0000000..5400ad3
--- /dev/null
+++ b/src/fdlist.c
@@ -0,0 +1,243 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * fdlist.c: Maintains a list of file descriptors.
+ *
+ * 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$
+ */
+
+#include "stdinc.h"
+#include "fdlist.h"
+#include "client.h" /* struct Client */
+#include "event.h"
+#include "ircd.h" /* GlobalSetOptions */
+#include "irc_string.h"
+#include "s_bsd.h" /* comm_setselect */
+#include "conf.h" /* ServerInfo */
+#include "send.h"
+#include "memory.h"
+#include "numeric.h"
+#include "s_misc.h"
+#include "irc_res.h"
+
+fde_t *fd_hash[FD_HASH_SIZE];
+fde_t *fd_next_in_loop = NULL;
+int number_fd = LEAKED_FDS;
+int hard_fdlimit = 0;
+struct Callback *fdlimit_cb = NULL;
+
+static void *
+changing_fdlimit(va_list args)
+{
+ int old_fdlimit = hard_fdlimit;
+
+ hard_fdlimit = va_arg(args, int);
+
+ if (ServerInfo.max_clients > (unsigned int)MAXCLIENTS_MAX)
+ {
+ if (old_fdlimit != 0)
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "HARD_FDLIMIT changed to %d, adjusting MAXCLIENTS to %d",
+ hard_fdlimit, MAXCLIENTS_MAX);
+
+ ServerInfo.max_clients = MAXCLIENTS_MAX;
+ }
+
+ return NULL;
+}
+
+void
+fdlist_init(void)
+{
+ memset(&fd_hash, 0, sizeof(fd_hash));
+
+ fdlimit_cb = register_callback("changing_fdlimit", changing_fdlimit);
+ eventAddIsh("recalc_fdlimit", recalc_fdlimit, NULL, 58);
+ recalc_fdlimit(NULL);
+}
+
+void
+recalc_fdlimit(void *unused)
+{
+ int fdmax;
+ struct rlimit limit;
+
+ if (!getrlimit(RLIMIT_NOFILE, &limit))
+ {
+ limit.rlim_cur = limit.rlim_max;
+ setrlimit(RLIMIT_NOFILE, &limit);
+ }
+
+ fdmax = getdtablesize();
+
+ /* allow MAXCLIENTS_MIN clients even at the cost of MAX_BUFFER and
+ * some not really LEAKED_FDS */
+ fdmax = IRCD_MAX(fdmax, LEAKED_FDS + MAX_BUFFER + MAXCLIENTS_MIN);
+
+ /* under no condition shall this raise over 65536
+ * for example user ip heap is sized 2*hard_fdlimit */
+ fdmax = IRCD_MIN(fdmax, 65536);
+
+ if (fdmax != hard_fdlimit)
+ execute_callback(fdlimit_cb, fdmax);
+}
+
+static inline unsigned int
+hash_fd(int fd)
+{
+ return (((unsigned) fd) % FD_HASH_SIZE);
+}
+
+fde_t *
+lookup_fd(int fd)
+{
+ fde_t *F = fd_hash[hash_fd(fd)];
+
+ while (F)
+ {
+ if (F->fd == fd)
+ return (F);
+ F = F->hnext;
+ }
+
+ return (NULL);
+}
+
+/* Called to open a given filedescriptor */
+void
+fd_open(fde_t *F, int fd, int is_socket, const char *desc)
+{
+ unsigned int hashv = hash_fd(fd);
+ assert(fd >= 0);
+
+ F->fd = fd;
+ F->comm_index = -1;
+ if (desc)
+ strlcpy(F->desc, desc, sizeof(F->desc));
+ /* Note: normally we'd have to clear the other flags,
+ * but currently F is always cleared before calling us.. */
+ F->flags.open = 1;
+ F->flags.is_socket = is_socket;
+ F->hnext = fd_hash[hashv];
+ fd_hash[hashv] = F;
+
+ number_fd++;
+}
+
+/* Called to close a given filedescriptor */
+void
+fd_close(fde_t *F)
+{
+ unsigned int hashv = hash_fd(F->fd);
+
+ if (F == fd_next_in_loop)
+ fd_next_in_loop = F->hnext;
+
+ if (F->flags.is_socket)
+ comm_setselect(F, COMM_SELECT_WRITE | COMM_SELECT_READ, NULL, NULL, 0);
+
+ delete_resolver_queries(F);
+
+#ifdef HAVE_LIBCRYPTO
+ if (F->ssl)
+ SSL_free(F->ssl);
+#endif
+
+ if (fd_hash[hashv] == F)
+ fd_hash[hashv] = F->hnext;
+ else {
+ fde_t *prev;
+
+ /* let it core if not found */
+ for (prev = fd_hash[hashv]; prev->hnext != F; prev = prev->hnext)
+ ;
+ prev->hnext = F->hnext;
+ }
+
+ /* Unlike squid, we're actually closing the FD here! -- adrian */
+ close(F->fd);
+ number_fd--;
+
+ memset(F, 0, sizeof(fde_t));
+}
+
+/*
+ * fd_dump() - dump the list of active filedescriptors
+ */
+void
+fd_dump(struct Client *source_p)
+{
+ int i;
+ fde_t *F;
+
+ for (i = 0; i < FD_HASH_SIZE; i++)
+ for (F = fd_hash[i]; F != NULL; F = F->hnext)
+ sendto_one(source_p, ":%s %d %s :fd %-5d desc '%s'",
+ me.name, RPL_STATSDEBUG, source_p->name,
+ F->fd, F->desc);
+}
+
+/*
+ * fd_note() - set the fd note
+ *
+ * Note: must be careful not to overflow fd_table[fd].desc when
+ * calling.
+ */
+void
+fd_note(fde_t *F, const char *format, ...)
+{
+ va_list args;
+
+ if (format != NULL)
+ {
+ va_start(args, format);
+ vsnprintf(F->desc, sizeof(F->desc), format, args);
+ va_end(args);
+ }
+ else
+ F->desc[0] = '\0';
+}
+
+/* Make sure stdio descriptors (0-2) and profiler descriptor (3)
+ * always go somewhere harmless. Use -foreground for profiling
+ * or executing from gdb */
+void
+close_standard_fds(void)
+{
+ int i;
+
+ for (i = 0; i < LOWEST_SAFE_FD; i++)
+ {
+ close(i);
+ if (open("/dev/null", O_RDWR) < 0)
+ exit(-1); /* we're hosed if we can't even open /dev/null */
+ }
+}
+
+void
+close_fds(fde_t *one)
+{
+ int i;
+ fde_t *F;
+
+ for (i = 0; i < FD_HASH_SIZE; i++)
+ for (F = fd_hash[i]; F != NULL; F = F->hnext)
+ if (F != one)
+ close(F->fd);
+}
diff --git a/src/getopt.c b/src/getopt.c
new file mode 100644
index 0000000..5b863d3
--- /dev/null
+++ b/src/getopt.c
@@ -0,0 +1,127 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * getopt.c: Uses getopt to fetch the command line options.
+ *
+ * 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$
+ */
+
+#include "stdinc.h"
+#include "ircd_getopt.h"
+
+#define OPTCHAR '-'
+
+
+static void
+usage(const char *name, const struct lgetopt *opts)
+{
+ unsigned int i;
+
+ fprintf(stderr, "Usage: %s [options]\n", name);
+ fprintf(stderr, "Where valid options are:\n");
+
+ for (i = 0; opts[i].opt; ++i)
+ fprintf(stderr, "\t%c%-10s %-20s%s\n", OPTCHAR, opts[i].opt,
+ (opts[i].argtype == YESNO || opts[i].argtype == USAGE) ? "" :
+ opts[i].argtype == INTEGER ? "<number>" : "<string>",
+ opts[i].desc);
+
+ exit(EXIT_FAILURE);
+}
+
+void
+parseargs(int *argc, char ***argv, struct lgetopt *opts)
+{
+ unsigned int i;
+ const char *progname = (*argv)[0];
+
+ /* loop through each argument */
+ while (1)
+ {
+ int found = 0;
+
+ (*argc)--;
+ (*argv)++;
+
+ if (*argc < 1 || (*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], opts);
+ }
+
+ *((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, opts);
+ }
+
+ *((char**)opts[i].argloc) = malloc(strlen((*argv)[1]) + 1);
+ strcpy(*((char**)opts[i].argloc), (*argv)[1]);
+ (*argc)--;
+ (*argv)++;
+ break;
+
+ case USAGE:
+ usage(progname, opts);
+ /* 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, opts);
+ }
+ }
+}
diff --git a/src/hash.c b/src/hash.c
new file mode 100644
index 0000000..d0b0a55
--- /dev/null
+++ b/src/hash.c
@@ -0,0 +1,907 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * hash.c: Maintains hashtables.
+ *
+ * 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$
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "balloc.h"
+#include "conf.h"
+#include "channel.h"
+#include "channel_mode.h"
+#include "client.h"
+#include "modules.h"
+#include "hash.h"
+#include "resv.h"
+#include "rng_mt.h"
+#include "userhost.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "memory.h"
+#include "dbuf.h"
+#include "s_user.h"
+
+
+static BlockHeap *userhost_heap = NULL;
+static BlockHeap *namehost_heap = NULL;
+
+static unsigned int hashf_xor_key = 0;
+
+/* The actual hash tables, They MUST be of the same HASHSIZE, variable
+ * size tables could be supported but the rehash routine should also
+ * rebuild the transformation maps, I kept the tables of equal size
+ * so that I can use one hash function.
+ */
+static struct Client *idTable[HASHSIZE];
+static struct Client *clientTable[HASHSIZE];
+static struct Channel *channelTable[HASHSIZE];
+static struct UserHost *userhostTable[HASHSIZE];
+static struct ResvChannel *resvchannelTable[HASHSIZE];
+
+
+/* init_hash()
+ *
+ * inputs - NONE
+ * output - NONE
+ * side effects - Initialize the maps used by hash
+ * functions and clear the tables
+ */
+void
+init_hash(void)
+{
+ /* Default the userhost/namehost sizes to CLIENT_HEAP_SIZE for now,
+ * should be a good close approximation anyway
+ * - Dianora
+ */
+ userhost_heap = BlockHeapCreate("userhost", sizeof(struct UserHost), CLIENT_HEAP_SIZE);
+ namehost_heap = BlockHeapCreate("namehost", sizeof(struct NameHost), CLIENT_HEAP_SIZE);
+
+ hashf_xor_key = genrand_int32() % 256; /* better than nothing --adx */
+}
+
+/*
+ * New hash function based on the Fowler/Noll/Vo (FNV) algorithm from
+ * http://www.isthe.com/chongo/tech/comp/fnv/
+ *
+ * Here, we use the FNV-1 method, which gives slightly better results
+ * than FNV-1a. -Michael
+ */
+unsigned int
+strhash(const char *name)
+{
+ const unsigned char *p = (const unsigned char *)name;
+ unsigned int hval = FNV1_32_INIT;
+
+ if (*p == '\0')
+ return 0;
+ for (; *p != '\0'; ++p)
+ {
+ hval += (hval << 1) + (hval << 4) + (hval << 7) +
+ (hval << 8) + (hval << 24);
+ hval ^= (ToLower(*p) ^ hashf_xor_key);
+ }
+
+ return (hval >> FNV1_32_BITS) ^ (hval & ((1 << FNV1_32_BITS) - 1));
+}
+
+/************************** Externally visible functions ********************/
+
+/* Optimization note: in these functions I supposed that the CSE optimization
+ * (Common Subexpression Elimination) does its work decently, this means that
+ * I avoided introducing new variables to do the work myself and I did let
+ * the optimizer play with more free registers, actual tests proved this
+ * solution to be faster than doing things like tmp2=tmp->hnext... and then
+ * use tmp2 myself which would have given less freedom to the optimizer.
+ */
+
+/* hash_add_client()
+ *
+ * inputs - pointer to client
+ * output - NONE
+ * side effects - Adds a client's name in the proper hash linked
+ * list, can't fail, client_p must have a non-null
+ * name or expect a coredump, the name is infact
+ * taken from client_p->name
+ */
+void
+hash_add_client(struct Client *client_p)
+{
+ unsigned int hashv = strhash(client_p->name);
+
+ client_p->hnext = clientTable[hashv];
+ clientTable[hashv] = client_p;
+}
+
+/* hash_add_channel()
+ *
+ * inputs - pointer to channel
+ * output - NONE
+ * side effects - Adds a channel's name in the proper hash linked
+ * list, can't fail. chptr must have a non-null name
+ * or expect a coredump. As before the name is taken
+ * from chptr->name, we do hash its entire lenght
+ * since this proved to be statistically faster
+ */
+void
+hash_add_channel(struct Channel *chptr)
+{
+ unsigned int hashv = strhash(chptr->chname);
+
+ chptr->hnextch = channelTable[hashv];
+ channelTable[hashv] = chptr;
+}
+
+void
+hash_add_resv(struct ResvChannel *chptr)
+{
+ unsigned int hashv = strhash(chptr->name);
+
+ chptr->hnext = resvchannelTable[hashv];
+ resvchannelTable[hashv] = chptr;
+}
+
+void
+hash_add_userhost(struct UserHost *userhost)
+{
+ unsigned int hashv = strhash(userhost->host);
+
+ userhost->next = userhostTable[hashv];
+ userhostTable[hashv] = userhost;
+}
+
+void
+hash_add_id(struct Client *client_p)
+{
+ unsigned int hashv = strhash(client_p->id);
+
+ client_p->idhnext = idTable[hashv];
+ idTable[hashv] = client_p;
+}
+
+/* hash_del_id()
+ *
+ * inputs - pointer to client
+ * output - NONE
+ * side effects - Removes an ID from the hash linked list
+ */
+void
+hash_del_id(struct Client *client_p)
+{
+ unsigned int hashv = strhash(client_p->id);
+ struct Client *tmp = idTable[hashv];
+
+ if (tmp != NULL)
+ {
+ if (tmp == client_p)
+ {
+ idTable[hashv] = client_p->idhnext;
+ client_p->idhnext = client_p;
+ }
+ else
+ {
+ while (tmp->idhnext != client_p)
+ if ((tmp = tmp->idhnext) == NULL)
+ return;
+
+ tmp->idhnext = tmp->idhnext->idhnext;
+ client_p->idhnext = client_p;
+ }
+ }
+}
+
+/* hash_del_client()
+ *
+ * inputs - pointer to client
+ * output - NONE
+ * side effects - Removes a Client's name from the hash linked list
+ */
+void
+hash_del_client(struct Client *client_p)
+{
+ unsigned int hashv = strhash(client_p->name);
+ struct Client *tmp = clientTable[hashv];
+
+ if (tmp != NULL)
+ {
+ if (tmp == client_p)
+ {
+ clientTable[hashv] = client_p->hnext;
+ client_p->hnext = client_p;
+ }
+ else
+ {
+ while (tmp->hnext != client_p)
+ if ((tmp = tmp->hnext) == NULL)
+ return;
+
+ tmp->hnext = tmp->hnext->hnext;
+ client_p->hnext = client_p;
+ }
+ }
+}
+
+/* hash_del_userhost()
+ *
+ * inputs - pointer to userhost
+ * output - NONE
+ * side effects - Removes a userhost from the hash linked list
+ */
+void
+hash_del_userhost(struct UserHost *userhost)
+{
+ unsigned int hashv = strhash(userhost->host);
+ struct UserHost *tmp = userhostTable[hashv];
+
+ if (tmp != NULL)
+ {
+ if (tmp == userhost)
+ {
+ userhostTable[hashv] = userhost->next;
+ userhost->next = userhost;
+ }
+ else
+ {
+ while (tmp->next != userhost)
+ if ((tmp = tmp->next) == NULL)
+ return;
+
+ tmp->next = tmp->next->next;
+ userhost->next = userhost;
+ }
+ }
+}
+
+/* hash_del_channel()
+ *
+ * inputs - pointer to client
+ * output - NONE
+ * side effects - Removes the channel's name from the corresponding
+ * hash linked list
+ */
+void
+hash_del_channel(struct Channel *chptr)
+{
+ unsigned int hashv = strhash(chptr->chname);
+ struct Channel *tmp = channelTable[hashv];
+
+ if (tmp != NULL)
+ {
+ if (tmp == chptr)
+ {
+ channelTable[hashv] = chptr->hnextch;
+ chptr->hnextch = chptr;
+ }
+ else
+ {
+ while (tmp->hnextch != chptr)
+ if ((tmp = tmp->hnextch) == NULL)
+ return;
+
+ tmp->hnextch = tmp->hnextch->hnextch;
+ chptr->hnextch = chptr;
+ }
+ }
+}
+
+void
+hash_del_resv(struct ResvChannel *chptr)
+{
+ unsigned int hashv = strhash(chptr->name);
+ struct ResvChannel *tmp = resvchannelTable[hashv];
+
+ if (tmp != NULL)
+ {
+ if (tmp == chptr)
+ {
+ resvchannelTable[hashv] = chptr->hnext;
+ chptr->hnext = chptr;
+ }
+ else
+ {
+ while (tmp->hnext != chptr)
+ if ((tmp = tmp->hnext) == NULL)
+ return;
+
+ tmp->hnext = tmp->hnext->hnext;
+ chptr->hnext = chptr;
+ }
+ }
+}
+
+/* hash_find_client()
+ *
+ * inputs - pointer to name
+ * output - NONE
+ * side effects - New semantics: finds a client whose name is 'name'
+ * if can't find one returns NULL. If it finds one moves
+ * it to the top of the list and returns it.
+ */
+struct Client *
+hash_find_client(const char *name)
+{
+ unsigned int hashv = strhash(name);
+ struct Client *client_p;
+
+ if ((client_p = clientTable[hashv]) != NULL)
+ {
+ if (irccmp(name, client_p->name))
+ {
+ struct Client *prev;
+
+ while (prev = client_p, (client_p = client_p->hnext) != NULL)
+ {
+ if (!irccmp(name, client_p->name))
+ {
+ prev->hnext = client_p->hnext;
+ client_p->hnext = clientTable[hashv];
+ clientTable[hashv] = client_p;
+ break;
+ }
+ }
+ }
+ }
+
+ return client_p;
+}
+
+struct Client *
+hash_find_id(const char *name)
+{
+ unsigned int hashv = strhash(name);
+ struct Client *client_p;
+
+ if ((client_p = idTable[hashv]) != NULL)
+ {
+ if (strcmp(name, client_p->id))
+ {
+ struct Client *prev;
+
+ while (prev = client_p, (client_p = client_p->idhnext) != NULL)
+ {
+ if (!strcmp(name, client_p->id))
+ {
+ prev->idhnext = client_p->idhnext;
+ client_p->idhnext = idTable[hashv];
+ idTable[hashv] = client_p;
+ break;
+ }
+ }
+ }
+ }
+
+ return client_p;
+}
+
+struct Client *
+hash_find_server(const char *name)
+{
+ unsigned int hashv = strhash(name);
+ struct Client *client_p = NULL;
+
+ if (IsDigit(*name) && strlen(name) == IRC_MAXSID)
+ return hash_find_id(name);
+
+ if ((client_p = clientTable[hashv]) != NULL)
+ {
+ if ((!IsServer(client_p) && !IsMe(client_p)) ||
+ irccmp(name, client_p->name))
+ {
+ struct Client *prev;
+
+ while (prev = client_p, (client_p = client_p->hnext) != NULL)
+ {
+ if ((IsServer(client_p) || IsMe(client_p)) &&
+ !irccmp(name, client_p->name))
+ {
+ prev->hnext = client_p->hnext;
+ client_p->hnext = clientTable[hashv];
+ clientTable[hashv] = client_p;
+ break;
+ }
+ }
+ }
+ }
+
+ return client_p;
+}
+
+/* hash_find_channel()
+ *
+ * inputs - pointer to name
+ * output - NONE
+ * side effects - New semantics: finds a channel whose name is 'name',
+ * if can't find one returns NULL, if can find it moves
+ * it to the top of the list and returns it.
+ */
+struct Channel *
+hash_find_channel(const char *name)
+{
+ unsigned int hashv = strhash(name);
+ struct Channel *chptr = NULL;
+
+ if ((chptr = channelTable[hashv]) != NULL)
+ {
+ if (irccmp(name, chptr->chname))
+ {
+ struct Channel *prev;
+
+ while (prev = chptr, (chptr = chptr->hnextch) != NULL)
+ {
+ if (!irccmp(name, chptr->chname))
+ {
+ prev->hnextch = chptr->hnextch;
+ chptr->hnextch = channelTable[hashv];
+ channelTable[hashv] = chptr;
+ break;
+ }
+ }
+ }
+ }
+
+ return chptr;
+}
+
+/* hash_get_bucket(int type, unsigned int hashv)
+ *
+ * inputs - hash value (must be between 0 and HASHSIZE - 1)
+ * output - NONE
+ * returns - pointer to first channel in channelTable[hashv]
+ * if that exists;
+ * NULL if there is no channel in that place;
+ * NULL if hashv is an invalid number.
+ * side effects - NONE
+ */
+void *
+hash_get_bucket(int type, unsigned int hashv)
+{
+ assert(hashv < HASHSIZE);
+ if (hashv >= HASHSIZE)
+ return NULL;
+
+ switch (type)
+ {
+ case HASH_TYPE_ID:
+ return idTable[hashv];
+ break;
+ case HASH_TYPE_CHANNEL:
+ return channelTable[hashv];
+ break;
+ case HASH_TYPE_CLIENT:
+ return clientTable[hashv];
+ break;
+ case HASH_TYPE_USERHOST:
+ return userhostTable[hashv];
+ break;
+ case HASH_TYPE_RESERVED:
+ return resvchannelTable[hashv];
+ break;
+ default:
+ assert(0);
+ }
+
+ return NULL;
+}
+
+/* hash_find_resv()
+ *
+ * inputs - pointer to name
+ * output - NONE
+ * side effects - New semantics: finds a reserved channel whose name is 'name',
+ * if can't find one returns NULL, if can find it moves
+ * it to the top of the list and returns it.
+ */
+struct ResvChannel *
+hash_find_resv(const char *name)
+{
+ unsigned int hashv = strhash(name);
+ struct ResvChannel *chptr;
+
+ if ((chptr = resvchannelTable[hashv]) != NULL)
+ {
+ if (irccmp(name, chptr->name))
+ {
+ struct ResvChannel *prev;
+
+ while (prev = chptr, (chptr = chptr->hnext) != NULL)
+ {
+ if (!irccmp(name, chptr->name))
+ {
+ prev->hnext = chptr->hnext;
+ chptr->hnext = resvchannelTable[hashv];
+ resvchannelTable[hashv] = chptr;
+ break;
+ }
+ }
+ }
+ }
+
+ return chptr;
+}
+
+struct UserHost *
+hash_find_userhost(const char *host)
+{
+ unsigned int hashv = strhash(host);
+ struct UserHost *userhost;
+
+ if ((userhost = userhostTable[hashv]))
+ {
+ if (irccmp(host, userhost->host))
+ {
+ struct UserHost *prev;
+
+ while (prev = userhost, (userhost = userhost->next) != NULL)
+ {
+ if (!irccmp(host, userhost->host))
+ {
+ prev->next = userhost->next;
+ userhost->next = userhostTable[hashv];
+ userhostTable[hashv] = userhost;
+ break;
+ }
+ }
+ }
+ }
+
+ return userhost;
+}
+
+/* count_user_host()
+ *
+ * inputs - user name
+ * - hostname
+ * - int flag 1 if global, 0 if local
+ * - pointer to where global count should go
+ * - pointer to where local count should go
+ * - pointer to where identd count should go (local clients only)
+ * output - none
+ * side effects -
+ */
+void
+count_user_host(const char *user, const char *host, int *global_p,
+ int *local_p, int *icount_p)
+{
+ dlink_node *ptr;
+ struct UserHost *found_userhost;
+ struct NameHost *nameh;
+
+ if ((found_userhost = hash_find_userhost(host)) == NULL)
+ return;
+
+ DLINK_FOREACH(ptr, found_userhost->list.head)
+ {
+ nameh = ptr->data;
+
+ if (!irccmp(user, nameh->name))
+ {
+ if (global_p != NULL)
+ *global_p = nameh->gcount;
+ if (local_p != NULL)
+ *local_p = nameh->lcount;
+ if (icount_p != NULL)
+ *icount_p = nameh->icount;
+ return;
+ }
+ }
+}
+
+/* find_or_add_userhost()
+ *
+ * inputs - host name
+ * output - none
+ * side effects - find UserHost * for given host name
+ */
+static struct UserHost *
+find_or_add_userhost(const char *host)
+{
+ struct UserHost *userhost;
+
+ if ((userhost = hash_find_userhost(host)) != NULL)
+ return userhost;
+
+ userhost = BlockHeapAlloc(userhost_heap);
+ strlcpy(userhost->host, host, sizeof(userhost->host));
+ hash_add_userhost(userhost);
+
+ return userhost;
+}
+
+/* add_user_host()
+ *
+ * inputs - user name
+ * - hostname
+ * - int flag 1 if global, 0 if local
+ * output - none
+ * side effects - add given user@host to hash tables
+ */
+void
+add_user_host(const char *user, const char *host, int global)
+{
+ dlink_node *ptr;
+ struct UserHost *found_userhost;
+ struct NameHost *nameh;
+ int hasident = 1;
+
+ if (*user == '~')
+ {
+ hasident = 0;
+ ++user;
+ }
+
+ if ((found_userhost = find_or_add_userhost(host)) == NULL)
+ return;
+
+ DLINK_FOREACH(ptr, found_userhost->list.head)
+ {
+ nameh = ptr->data;
+
+ if (!irccmp(user, nameh->name))
+ {
+ nameh->gcount++;
+
+ if (!global)
+ {
+ if (hasident)
+ nameh->icount++;
+ nameh->lcount++;
+ }
+
+ return;
+ }
+ }
+
+ nameh = BlockHeapAlloc(namehost_heap);
+ strlcpy(nameh->name, user, sizeof(nameh->name));
+
+ nameh->gcount = 1;
+
+ if (!global)
+ {
+ if (hasident)
+ nameh->icount = 1;
+ nameh->lcount = 1;
+ }
+
+ dlinkAdd(nameh, &nameh->node, &found_userhost->list);
+}
+
+/* delete_user_host()
+ *
+ * inputs - user name
+ * - hostname
+ * - int flag 1 if global, 0 if local
+ * output - none
+ * side effects - delete given user@host to hash tables
+ */
+void
+delete_user_host(const char *user, const char *host, int global)
+{
+ dlink_node *ptr = NULL, *next_ptr = NULL;
+ struct UserHost *found_userhost;
+ struct NameHost *nameh;
+ int hasident = 1;
+
+ if (*user == '~')
+ {
+ hasident = 0;
+ ++user;
+ }
+
+ if ((found_userhost = hash_find_userhost(host)) == NULL)
+ return;
+
+ DLINK_FOREACH_SAFE(ptr, next_ptr, found_userhost->list.head)
+ {
+ nameh = ptr->data;
+
+ if (!irccmp(user, nameh->name))
+ {
+ if (nameh->gcount > 0)
+ nameh->gcount--;
+ if (!global)
+ {
+ if (nameh->lcount > 0)
+ nameh->lcount--;
+ if (hasident && nameh->icount > 0)
+ nameh->icount--;
+ }
+
+ if (nameh->gcount == 0 && nameh->lcount == 0)
+ {
+ dlinkDelete(&nameh->node, &found_userhost->list);
+ BlockHeapFree(namehost_heap, nameh);
+ }
+
+ if (dlink_list_length(&found_userhost->list) == 0)
+ {
+ hash_del_userhost(found_userhost);
+ BlockHeapFree(userhost_heap, found_userhost);
+ }
+
+ return;
+ }
+ }
+}
+
+/*
+ * Safe list code.
+ *
+ * The idea is really quite simple. As the link lists pointed to in
+ * each "bucket" of the channel hash table are traversed atomically
+ * there is no locking needed. Overall, yes, inconsistent reported
+ * state can still happen, but normally this isn't a big deal.
+ * I don't like sticking the code into hash.c but oh well. Moreover,
+ * if a hash isn't used in future, oops.
+ *
+ * - Dianora
+ */
+
+/* exceeding_sendq()
+ *
+ * inputs - pointer to client to check
+ * output - 1 if client is in danger of blowing its sendq
+ * 0 if it is not.
+ * side effects -
+ *
+ * Sendq limit is fairly conservative at 1/2 (In original anyway)
+ */
+static int
+exceeding_sendq(struct Client *to)
+{
+ if (dbuf_length(&to->localClient->buf_sendq) > (get_sendq(to) / 2))
+ return 1;
+ else
+ return 0;
+}
+
+void
+free_list_task(struct ListTask *lt, struct Client *source_p)
+{
+ dlink_node *dl, *dln;
+
+ if ((dl = dlinkFindDelete(&listing_client_list, source_p)) != NULL)
+ free_dlink_node(dl);
+
+ DLINK_FOREACH_SAFE(dl, dln, lt->show_mask.head)
+ {
+ MyFree(dl->data);
+ free_dlink_node(dl);
+ }
+
+ DLINK_FOREACH_SAFE(dl, dln, lt->hide_mask.head)
+ {
+ MyFree(dl->data);
+ free_dlink_node(dl);
+ }
+
+ MyFree(lt);
+
+ if (MyConnect(source_p))
+ source_p->localClient->list_task = NULL;
+}
+
+/* list_allow_channel()
+ *
+ * inputs - channel name
+ * - pointer to a list task
+ * output - 1 if the channel is to be displayed
+ * 0 otherwise
+ * side effects -
+ */
+static int
+list_allow_channel(const char *chname, struct ListTask *lt)
+{
+ dlink_node *dl = NULL;
+
+ DLINK_FOREACH(dl, lt->show_mask.head)
+ if (!match_chan(dl->data, chname))
+ return 0;
+
+ DLINK_FOREACH(dl, lt->hide_mask.head)
+ if (match_chan(dl->data, chname))
+ return 0;
+
+ return 1;
+}
+
+/* list_one_channel()
+ *
+ * inputs - client pointer to return result to
+ * - pointer to channel to list
+ * - pointer to ListTask structure
+ * output - none
+ * side effects -
+ */
+static void
+list_one_channel(struct Client *source_p, struct Channel *chptr,
+ struct ListTask *list_task)
+{
+ if (SecretChannel(chptr) && !IsMember(source_p, chptr))
+ return;
+ if (dlink_list_length(&chptr->members) < list_task->users_min ||
+ dlink_list_length(&chptr->members) > list_task->users_max ||
+ (chptr->channelts != 0 &&
+ ((unsigned int)chptr->channelts < list_task->created_min ||
+ (unsigned int)chptr->channelts > list_task->created_max)) ||
+ (unsigned int)chptr->topic_time < list_task->topicts_min ||
+ (chptr->topic_time ? (unsigned int)chptr->topic_time : UINT_MAX) >
+ list_task->topicts_max)
+ return;
+
+ if (!list_allow_channel(chptr->chname, list_task))
+ return;
+ sendto_one(source_p, form_str(RPL_LIST), me.name, source_p->name,
+ chptr->chname, dlink_list_length(&chptr->members),
+ chptr->topic);
+}
+
+/* safe_list_channels()
+ *
+ * inputs - pointer to client requesting list
+ * output - 0/1
+ * side effects - safely list all channels to source_p
+ *
+ * Walk the channel buckets, ensure all pointers in a bucket are
+ * traversed before blocking on a sendq. This means, no locking is needed.
+ *
+ * N.B. This code is "remote" safe, but is not currently used for
+ * remote clients.
+ *
+ * - Dianora
+ */
+void
+safe_list_channels(struct Client *source_p, struct ListTask *list_task,
+ int only_unmasked_channels)
+{
+ struct Channel *chptr = NULL;
+
+ if (!only_unmasked_channels)
+ {
+ unsigned int i;
+
+ for (i = list_task->hash_index; i < HASHSIZE; ++i)
+ {
+ if (exceeding_sendq(source_p->from))
+ {
+ list_task->hash_index = i;
+ return; /* still more to do */
+ }
+
+ for (chptr = channelTable[i]; chptr; chptr = chptr->hnextch)
+ list_one_channel(source_p, chptr, list_task);
+ }
+ }
+ else
+ {
+ dlink_node *dl;
+
+ DLINK_FOREACH(dl, list_task->show_mask.head)
+ if ((chptr = hash_find_channel(dl->data)) != NULL)
+ list_one_channel(source_p, chptr, list_task);
+ }
+
+ free_list_task(list_task, source_p);
+ sendto_one(source_p, form_str(RPL_LISTEND),
+ me.name, source_p->name);
+}
diff --git a/src/hook.c b/src/hook.c
new file mode 100644
index 0000000..9b4b1c5
--- /dev/null
+++ b/src/hook.c
@@ -0,0 +1,216 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ *
+ * Copyright (C) 2003 Piotr Nizynski, Advanced IRC Services Project Team
+ * Copyright (C) 2005 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$
+ */
+
+/*! \file hook.c
+ * \brief Provides a generic event hooking interface.
+ * \version $Id$
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "hook.h"
+#include "ircd.h"
+#include "memory.h"
+#include "numeric.h"
+#include "irc_string.h"
+#include "send.h"
+#include "client.h"
+
+static dlink_list callback_list = { NULL, NULL, 0} ;
+
+/*! \brief Creates a new callback.
+ * \param name name used to identify the callback
+ * (can be NULL for anonymous callbacks)
+ * \param func initial function attached to the chain
+ * (can be NULL to create an empty chain)
+ * \return pointer to Callback structure or NULL if already exists
+ * \note Once registered, a callback should never be freed!
+ * That's because there may be modules which depend on it
+ * (even if no functions are attached). That's also why
+ * we dynamically allocate the struct here -- we don't want
+ * to allow anyone to place it in module data, which can be
+ * unloaded at any time.
+ */
+struct Callback *
+register_callback(const char *name, CBFUNC *func)
+{
+ struct Callback *cb = NULL;
+
+ if (name != NULL)
+ {
+ if ((cb = find_callback(name)) != NULL)
+ {
+ if (func != NULL)
+ dlinkAddTail(func, MyMalloc(sizeof(dlink_node)), &cb->chain);
+
+ return cb;
+ }
+ }
+
+ cb = MyMalloc(sizeof(struct Callback));
+ if (func != NULL)
+ dlinkAdd(func, MyMalloc(sizeof(dlink_node)), &cb->chain);
+
+ if (name != NULL)
+ {
+ DupString(cb->name, name);
+ dlinkAdd(cb, &cb->node, &callback_list);
+ }
+
+ return cb;
+}
+
+/*! \brief Passes control down the callback hook chain.
+ * \param cb pointer to Callback structure
+ * \param ... argument to pass
+ * \return function return value
+ */
+void *
+execute_callback(struct Callback *cb, ...)
+{
+ void *res;
+ va_list args;
+
+ cb->called++;
+ cb->last = CurrentTime;
+
+ if (!is_callback_present(cb))
+ return NULL;
+
+ va_start(args, cb);
+ res = ((CBFUNC *) cb->chain.head->data)(args);
+ va_end(args);
+
+ return res;
+}
+
+/*! \brief Called by a hook function to pass code flow further
+ * in the hook chain.
+ * \param this_hook pointer to dlink_node of the current hook function
+ * \param ... (original or modified) arguments to be passed
+ * \return callback return value
+ */
+void *
+pass_callback(dlink_node *this_hook, ...)
+{
+ void *res;
+ va_list args;
+
+ if (this_hook->next == NULL)
+ return NULL; /* reached the last one */
+
+ va_start(args, this_hook);
+ res = ((CBFUNC *) this_hook->next->data)(args);
+ va_end(args);
+
+ return res;
+}
+
+/*! \brief Finds a named callback.
+ * \param name name of the callback
+ * \return pointer to Callback structure or NULL if not found
+ */
+struct Callback *
+find_callback(const char *name)
+{
+ dlink_node *ptr;
+
+ DLINK_FOREACH(ptr, callback_list.head)
+ {
+ struct Callback *cb = ptr->data;
+
+ if (!irccmp(cb->name, name))
+ return cb;
+ }
+
+ return NULL;
+}
+
+/*! \brief Installs a hook for the given callback.
+ *
+ * The new hook is installed at the beginning of the chain,
+ * so it has full control over functions installed earlier.
+ *
+ * \param cb pointer to Callback structure
+ * \param hook address of hook function
+ * \return pointer to dlink_node of the hook (used when passing
+ * control to the next hook in the chain);
+ * valid till uninstall_hook() is called
+ */
+dlink_node *
+install_hook(struct Callback *cb, CBFUNC *hook)
+{
+ dlink_node *node = MyMalloc(sizeof(dlink_node));
+
+ dlinkAdd(hook, node, &cb->chain);
+ return node;
+}
+
+/*! \brief Removes a specific hook for the given callback.
+ * \param cb pointer to Callback structure
+ * \param hook address of hook function
+ */
+void
+uninstall_hook(struct Callback *cb, CBFUNC *hook)
+{
+ /* let it core if not found */
+ dlink_node *ptr = dlinkFind(&cb->chain, hook);
+
+ dlinkDelete(ptr, &cb->chain);
+ MyFree(ptr);
+}
+
+/*! \brief Displays registered callbacks and lengths of their hook chains.
+ * (This is the handler of /stats h)
+ * \param source_p pointer to struct Client
+ */
+void
+stats_hooks(struct Client *source_p)
+{
+ dlink_node *ptr;
+ char lastused[32];
+
+ sendto_one(source_p, ":%s %d %s : %-20s %-20s Used Hooks", me.name,
+ RPL_STATSDEBUG, source_p->name, "Callback", "Last Execution");
+ sendto_one(source_p, ":%s %d %s : ------------------------------------"
+ "--------------------", me.name, RPL_STATSDEBUG, source_p->name);
+
+ DLINK_FOREACH(ptr, callback_list.head)
+ {
+ struct Callback *cb = ptr->data;
+
+ if (cb->last != 0)
+ snprintf(lastused, sizeof(lastused), "%d seconds ago",
+ (int) (CurrentTime - cb->last));
+ else
+ strcpy(lastused, "NEVER");
+
+ sendto_one(source_p, ":%s %d %s : %-20s %-20s %-8u %d", me.name,
+ RPL_STATSDEBUG, source_p->name, cb->name, lastused, cb->called,
+ dlink_list_length(&cb->chain));
+ }
+
+ sendto_one(source_p, ":%s %d %s : ", me.name, RPL_STATSDEBUG,
+ source_p->name);
+}
diff --git a/src/hostmask.c b/src/hostmask.c
new file mode 100644
index 0000000..f7cca41
--- /dev/null
+++ b/src/hostmask.c
@@ -0,0 +1,820 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * hostmask.c: Code to efficiently find IP & hostmask based configs.
+ *
+ * Copyright (C) 2005 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$
+ */
+
+#include "stdinc.h"
+#include "memory.h"
+#include "ircd_defs.h"
+#include "list.h"
+#include "conf.h"
+#include "hostmask.h"
+#include "send.h"
+#include "irc_string.h"
+#include "ircd.h"
+
+
+#define DigitParse(ch) do { \
+ if (ch >= '0' && ch <= '9') \
+ ch = ch - '0'; \
+ else if (ch >= 'A' && ch <= 'F') \
+ ch = ch - 'A' + 10; \
+ else if (ch >= 'a' && ch <= 'f') \
+ ch = ch - 'a' + 10; \
+ } while (0);
+
+/* The mask parser/type determination code... */
+
+/* int try_parse_v6_netmask(const char *, struct irc_ssaddr *, int *);
+ * Input: A possible IPV6 address as a string.
+ * Output: An integer describing whether it is an IPV6 or hostmask,
+ * an address(if it is IPV6), a bitlength(if it is IPV6).
+ * Side effects: None
+ * Comments: Called from parse_netmask
+ */
+/* Fixed so ::/0 (any IPv6 address) is valid
+ Also a bug in DigitParse above.
+ -Gozem 2002-07-19 gozem@linux.nu
+*/
+#ifdef IPV6
+static int
+try_parse_v6_netmask(const char *text, struct irc_ssaddr *addr, int *b)
+{
+ const char *p;
+ char c;
+ int d[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ int dp = 0;
+ int nyble = 4;
+ int finsert = -1;
+ int bits = 128;
+ int deficit = 0;
+ short dc[8];
+ struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)addr;
+
+ for (p = text; (c = *p); p++)
+ if (IsXDigit(c))
+ {
+ if (nyble == 0)
+ return HM_HOST;
+ DigitParse(c);
+ d[dp] |= c << (4 * --nyble);
+ }
+ else if (c == ':')
+ {
+ if (p > text && *(p - 1) == ':')
+ {
+ if (finsert >= 0)
+ return HM_HOST;
+ finsert = dp;
+ }
+ else
+ {
+ /* If there were less than 4 hex digits, e.g. :ABC: shift right
+ * so we don't interpret it as ABC0 -A1kmm */
+ d[dp] = d[dp] >> 4 * nyble;
+ nyble = 4;
+ if (++dp >= 8)
+ return HM_HOST;
+ }
+ }
+ else if (c == '*')
+ {
+ /* * must be last, and * is ambiguous if there is a ::... -A1kmm */
+ if (finsert >= 0 || *(p + 1) || dp == 0 || *(p - 1) != ':')
+ return HM_HOST;
+ bits = dp * 16;
+ }
+ else if (c == '/')
+ {
+ char *after;
+
+ d[dp] = d[dp] >> 4 * nyble;
+ dp++;
+ bits = strtoul(p + 1, &after, 10);
+
+ if (bits < 0 || *after)
+ return HM_HOST;
+ if (bits > dp * 4 && !(finsert >= 0 && bits <= 128))
+ return HM_HOST;
+ break;
+ }
+ else
+ return HM_HOST;
+
+ d[dp] = d[dp] >> 4 * nyble;
+
+ if (c == 0)
+ dp++;
+ if (finsert < 0 && bits == 0)
+ bits = dp * 16;
+
+ /* How many words are missing? -A1kmm */
+ deficit = bits / 16 + ((bits % 16) ? 1 : 0) - dp;
+
+ /* Now fill in the gaps(from ::) in the copied table... -A1kmm */
+ for (dp = 0, nyble = 0; dp < 8; dp++)
+ {
+ if (nyble == finsert && deficit)
+ {
+ dc[dp] = 0;
+ deficit--;
+ }
+ else
+ dc[dp] = d[nyble++];
+ }
+
+ /* Set unused bits to 0... -A1kmm */
+ if (bits < 128 && (bits % 16 != 0))
+ dc[bits / 16] &= ~((1 << (15 - bits % 16)) - 1);
+ for (dp = bits / 16 + (bits % 16 ? 1 : 0); dp < 8; dp++)
+ dc[dp] = 0;
+
+ /* And assign... -A1kmm */
+ if (addr)
+ for (dp = 0; dp < 8; dp++)
+ /* The cast is a kludge to make netbsd work. */
+ ((unsigned short *)&v6->sin6_addr)[dp] = htons(dc[dp]);
+
+ if (b != NULL)
+ *b = bits;
+ return HM_IPV6;
+}
+#endif
+
+/* int try_parse_v4_netmask(const char *, struct irc_ssaddr *, int *);
+ * Input: A possible IPV4 address as a string.
+ * Output: An integer describing whether it is an IPV4 or hostmask,
+ * an address(if it is IPV4), a bitlength(if it is IPV4).
+ * Side effects: None
+ * Comments: Called from parse_netmask
+ */
+static int
+try_parse_v4_netmask(const char *text, struct irc_ssaddr *addr, int *b)
+{
+ const char *p;
+ const char *digits[4];
+ unsigned char addb[4];
+ int n = 0, bits = 0;
+ char c;
+ struct sockaddr_in *v4 = (struct sockaddr_in *)addr;
+
+ digits[n++] = text;
+
+ for (p = text; (c = *p); p++)
+ if (c >= '0' && c <= '9') /* empty */
+ ;
+ else if (c == '.')
+ {
+ if (n >= 4)
+ return HM_HOST;
+
+ digits[n++] = p + 1;
+ }
+ else if (c == '*')
+ {
+ if (*(p + 1) || n == 0 || *(p - 1) != '.')
+ return HM_HOST;
+
+ bits = (n - 1) * 8;
+ break;
+ }
+ else if (c == '/')
+ {
+ char *after;
+ bits = strtoul(p + 1, &after, 10);
+
+ if (!bits || *after)
+ return HM_HOST;
+ if (bits > n * 8)
+ return HM_HOST;
+
+ break;
+ }
+ else
+ return HM_HOST;
+
+ if (n < 4 && bits == 0)
+ bits = n * 8;
+ if (bits)
+ while (n < 4)
+ digits[n++] = "0";
+
+ for (n = 0; n < 4; n++)
+ addb[n] = strtoul(digits[n], NULL, 10);
+
+ if (bits == 0)
+ bits = 32;
+
+ /* Set unused bits to 0... -A1kmm */
+ if (bits < 32 && bits % 8)
+ addb[bits / 8] &= ~((1 << (8 - bits % 8)) - 1);
+ for (n = bits / 8 + (bits % 8 ? 1 : 0); n < 4; n++)
+ addb[n] = 0;
+ if (addr)
+ v4->sin_addr.s_addr =
+ htonl(addb[0] << 24 | addb[1] << 16 | addb[2] << 8 | addb[3]);
+ if (b != NULL)
+ *b = bits;
+ return HM_IPV4;
+}
+
+/* int parse_netmask(const char *, struct irc_ssaddr *, 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 irc_ssaddr *addr, int *b)
+{
+#ifdef IPV6
+ if (strchr(text, ':'))
+ return try_parse_v6_netmask(text, addr, b);
+#endif
+ if (strchr(text, '.'))
+ return try_parse_v4_netmask(text, addr, b);
+ return HM_HOST;
+}
+
+/* The address matching stuff... */
+/* int match_ipv6(struct irc_ssaddr *, struct irc_ssaddr *, int)
+ * Input: An IP address, an IP mask, the number of bits in the mask.
+ * Output: if match, -1 else 0
+ * Side effects: None
+ */
+#ifdef IPV6
+int
+match_ipv6(const struct irc_ssaddr *addr, const struct irc_ssaddr *mask, int bits)
+{
+ int i, m, n = bits / 8;
+ const struct sockaddr_in6 *v6 = (const struct sockaddr_in6 *)addr;
+ const struct sockaddr_in6 *v6mask = (const struct sockaddr_in6 *)mask;
+
+ for (i = 0; i < n; i++)
+ if (v6->sin6_addr.s6_addr[i] != v6mask->sin6_addr.s6_addr[i])
+ return 0;
+ if ((m = bits % 8) == 0)
+ return -1;
+ if ((v6->sin6_addr.s6_addr[n] & ~((1 << (8 - m)) - 1)) ==
+ v6mask->sin6_addr.s6_addr[n])
+ return -1;
+ return 0;
+}
+#endif
+
+/* int match_ipv4(struct irc_ssaddr *, struct irc_ssaddr *, int)
+ * Input: An IP address, an IP mask, the number of bits in the mask.
+ * Output: if match, -1 else 0
+ * Side Effects: None
+ */
+int
+match_ipv4(const struct irc_ssaddr *addr, const struct irc_ssaddr *mask, int bits)
+{
+ const struct sockaddr_in *v4 = (const struct sockaddr_in *)addr;
+ const struct sockaddr_in *v4mask = (const struct sockaddr_in *)mask;
+
+ if ((ntohl(v4->sin_addr.s_addr) & ~((1 << (32 - bits)) - 1)) !=
+ ntohl(v4mask->sin_addr.s_addr))
+ return 0;
+ return -1;
+}
+
+/*
+ * mask_addr
+ *
+ * inputs - pointer to the ip to mask
+ * - bitlen
+ * output - NONE
+ * side effects -
+ */
+void
+mask_addr(struct irc_ssaddr *ip, int bits)
+{
+ int mask;
+#ifdef IPV6
+ struct sockaddr_in6 *v6_base_ip;
+ int i, m, n;
+#endif
+ struct sockaddr_in *v4_base_ip;
+
+#ifdef IPV6
+ if (ip->ss.ss_family != AF_INET6)
+#endif
+ {
+ v4_base_ip = (struct sockaddr_in *)ip;
+
+ mask = ~((1 << (32 - bits)) - 1);
+ v4_base_ip->sin_addr.s_addr = htonl(ntohl(v4_base_ip->sin_addr.s_addr) & mask);
+ }
+#ifdef IPV6
+ else
+ {
+ n = bits / 8;
+ m = bits % 8;
+ v6_base_ip = (struct sockaddr_in6 *)ip;
+
+ mask = ~((1 << (8 - m)) -1 );
+ v6_base_ip->sin6_addr.s6_addr[n] = v6_base_ip->sin6_addr.s6_addr[n] & mask;
+
+ for (i = n + 1; i < 16; i++)
+ v6_base_ip->sin6_addr.s6_addr[i] = 0;
+ }
+#endif
+}
+
+/* Hashtable stuff...now external as its used in m_stats.c */
+dlink_list atable[ATABLE_SIZE];
+
+void
+init_host_hash(void)
+{
+ memset(&atable, 0, sizeof(atable));
+}
+
+/* unsigned long hash_ipv4(struct irc_ssaddr*)
+ * Input: An IP address.
+ * Output: A hash value of the IP address.
+ * Side effects: None
+ */
+static uint32_t
+hash_ipv4(struct irc_ssaddr *addr, int bits)
+{
+ if (bits != 0)
+ {
+ struct sockaddr_in *v4 = (struct sockaddr_in *)addr;
+ uint32_t av = ntohl(v4->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_ssaddr*)
+ * Input: An IP address.
+ * Output: A hash value of the IP address.
+ * Side effects: None
+ */
+#ifdef IPV6
+static uint32_t
+hash_ipv6(struct irc_ssaddr *addr, int bits)
+{
+ uint32_t v = 0, n;
+ struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)addr;
+
+ for (n = 0; n < 16; n++)
+ {
+ if (bits >= 8)
+ {
+ v ^= v6->sin6_addr.s6_addr[n];
+ bits -= 8;
+ }
+ else if (bits)
+ {
+ v ^= v6->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 uint32_t
+hash_text(const char *start)
+{
+ const char *p = start;
+ uint32_t h = 0;
+
+ for (; *p; ++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 uint32_t
+get_mask_hash(const char *text)
+{
+ const char *hp = "", *p;
+
+ for (p = text + strlen(text) - 1; p >= text; p--)
+ if (IsMWildChar(*p))
+ return hash_text(hp);
+ else if (*p == '.')
+ hp = p + 1;
+ return hash_text(text);
+}
+
+/* struct AccessItem *find_conf_by_address(const char *, struct irc_ssaddr *,
+ * 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.
+ * Warning: IsNeedPassword for everything that is not an auth{} entry
+ * should always be true (i.e. aconf->flags & CONF_FLAGS_NEED_PASSWORD == 0)
+ */
+struct AccessItem *
+find_conf_by_address(const char *name, struct irc_ssaddr *addr, unsigned int type,
+ int fam, const char *username, const char *password, int do_match)
+{
+ unsigned int hprecv = 0;
+ dlink_node *ptr = NULL;
+ struct AccessItem *hprec = NULL;
+ struct AddressRec *arec;
+ int b;
+ int (*cmpfunc)(const char *, const char *) = do_match ? match : irccmp;
+
+ if (username == NULL)
+ username = "";
+ if (password == NULL)
+ password = "";
+
+ if (addr)
+ {
+ /* Check for IPV6 matches... */
+#ifdef IPV6
+ if (fam == AF_INET6)
+ {
+ for (b = 128; b >= 0; b -= 16)
+ {
+ DLINK_FOREACH(ptr, atable[hash_ipv6(addr, b)].head)
+ {
+ arec = ptr->data;
+
+ if (arec->type == (type & ~0x1) &&
+ arec->precedence > hprecv &&
+ arec->masktype == HM_IPV6 &&
+ match_ipv6(addr, &arec->Mask.ipa.addr,
+ arec->Mask.ipa.bits) &&
+ (type & 0x1 || cmpfunc(arec->username, username) == do_match) &&
+ (IsNeedPassword(arec->aconf) || arec->aconf->passwd == NULL ||
+ match_conf_password(password, arec->aconf)))
+ {
+ hprecv = arec->precedence;
+ hprec = arec->aconf;
+ }
+ }
+ }
+ }
+ else
+#endif
+ if (fam == AF_INET)
+ {
+ for (b = 32; b >= 0; b -= 8)
+ {
+ DLINK_FOREACH(ptr, atable[hash_ipv4(addr, b)].head)
+ {
+ arec = ptr->data;
+
+ if (arec->type == (type & ~0x1) &&
+ arec->precedence > hprecv &&
+ arec->masktype == HM_IPV4 &&
+ match_ipv4(addr, &arec->Mask.ipa.addr,
+ arec->Mask.ipa.bits) &&
+ (type & 0x1 || cmpfunc(arec->username, username) == do_match) &&
+ (IsNeedPassword(arec->aconf) || arec->aconf->passwd == NULL ||
+ match_conf_password(password, arec->aconf)))
+ {
+ hprecv = arec->precedence;
+ hprec = arec->aconf;
+ }
+ }
+ }
+ }
+ }
+
+ if (name != NULL)
+ {
+ const char *p = name;
+
+ while (1)
+ {
+ DLINK_FOREACH(ptr, atable[hash_text(p)].head)
+ {
+ arec = ptr->data;
+ if ((arec->type == (type & ~0x1)) &&
+ arec->precedence > hprecv &&
+ (arec->masktype == HM_HOST) &&
+ cmpfunc(arec->Mask.hostname, name) == do_match &&
+ (type & 0x1 || cmpfunc(arec->username, username) == do_match) &&
+ (IsNeedPassword(arec->aconf) || arec->aconf->passwd == NULL ||
+ match_conf_password(password, arec->aconf)))
+ {
+ hprecv = arec->precedence;
+ hprec = arec->aconf;
+ }
+ }
+ p = strchr(p, '.');
+ if (p == NULL)
+ break;
+ p++;
+ }
+
+ DLINK_FOREACH(ptr, atable[0].head)
+ {
+ arec = ptr->data;
+
+ if (arec->type == (type & ~0x1) &&
+ arec->precedence > hprecv &&
+ arec->masktype == HM_HOST &&
+ cmpfunc(arec->Mask.hostname, name) == do_match &&
+ (type & 0x1 || cmpfunc(arec->username, username) == do_match) &&
+ (IsNeedPassword(arec->aconf) || arec->aconf->passwd == NULL ||
+ match_conf_password(password, arec->aconf)))
+ {
+ hprecv = arec->precedence;
+ hprec = arec->aconf;
+ }
+ }
+ }
+
+ return hprec;
+}
+
+/* struct AccessItem* find_address_conf(const char*, const char*,
+ * struct irc_ssaddr*, int, char *);
+ * Input: The hostname, username, address, address family.
+ * Output: The applicable AccessItem.
+ * Side-effects: None
+ */
+struct AccessItem *
+find_address_conf(const char *host, const char *user,
+ struct irc_ssaddr *ip, int aftype, char *password)
+{
+ struct AccessItem *iconf, *kconf;
+
+ /* Find the best auth{} block... If none, return NULL -A1kmm */
+ if ((iconf = find_conf_by_address(host, ip, CONF_CLIENT, aftype, user,
+ password, 1)) == NULL)
+ return NULL;
+
+ /* If they are exempt from K-lines, return the best auth{} block. -A1kmm */
+ if (IsConfExemptKline(iconf))
+ return iconf;
+
+ /* Find the best K-line... -A1kmm */
+ kconf = find_conf_by_address(host, ip, CONF_KLINE, aftype, user, NULL, 1);
+
+ /*
+ * If they are K-lined, return the K-line. Otherwise, return the
+ * auth{} block. -A1kmm
+ */
+ if (kconf != NULL)
+ return kconf;
+
+ kconf = find_conf_by_address(host, ip, CONF_GLINE, aftype, user, NULL, 1);
+ if (kconf != NULL && !IsConfExemptGline(iconf))
+ return kconf;
+
+ return iconf;
+}
+
+/* struct AccessItem* find_dline_conf(struct irc_ssaddr*, int)
+ *
+ * Input: An address, an address family.
+ * Output: The best matching D-line or exempt line.
+ * Side effects: None.
+ */
+struct AccessItem *
+find_dline_conf(struct irc_ssaddr *addr, int aftype)
+{
+ struct AccessItem *eline;
+
+ eline = find_conf_by_address(NULL, addr, CONF_EXEMPTDLINE | 1, aftype,
+ NULL, NULL, 1);
+ if (eline != NULL)
+ return eline;
+
+ return find_conf_by_address(NULL, addr, CONF_DLINE | 1, aftype, NULL, NULL, 1);
+}
+
+/* void add_conf_by_address(int, struct AccessItem *aconf)
+ * Input:
+ * Output: None
+ * Side-effects: Adds this entry to the hash table.
+ */
+void
+add_conf_by_address(const unsigned int type, struct AccessItem *aconf)
+{
+ const char *address;
+ const char *username;
+ static unsigned int prec_value = 0xFFFFFFFF;
+ int bits = 0;
+ struct AddressRec *arec;
+
+ address = aconf->host;
+ username = aconf->user;
+
+ assert(type != 0);
+ assert(aconf != NULL);
+
+ if (EmptyString(address))
+ address = "/NOMATCH!/";
+
+ arec = MyMalloc(sizeof(struct AddressRec));
+ arec->masktype = parse_netmask(address, &arec->Mask.ipa.addr, &bits);
+ arec->Mask.ipa.bits = bits;
+ arec->username = username;
+ arec->aconf = aconf;
+ arec->precedence = prec_value--;
+ arec->type = type;
+
+ switch (arec->masktype)
+ {
+ case HM_IPV4:
+ /* We have to do this, since we do not re-hash for every bit -A1kmm. */
+ bits -= bits % 8;
+ dlinkAdd(arec, &arec->node, &atable[hash_ipv4(&arec->Mask.ipa.addr, bits)]);
+ break;
+#ifdef IPV6
+ case HM_IPV6:
+ /* We have to do this, since we do not re-hash for every bit -A1kmm. */
+ bits -= bits % 16;
+ dlinkAdd(arec, &arec->node, &atable[hash_ipv6(&arec->Mask.ipa.addr, bits)]);
+ break;
+#endif
+ default: /* HM_HOST */
+ arec->Mask.hostname = address;
+ dlinkAdd(arec, &arec->node, &atable[get_mask_hash(address)]);
+ break;
+ }
+}
+
+/* void delete_one_address(const char*, struct AccessItem*)
+ * Input: An address string, the associated AccessItem.
+ * Output: None
+ * Side effects: Deletes an address record. Frees the AccessItem if there
+ * is nothing referencing it, sets it as illegal otherwise.
+ */
+void
+delete_one_address_conf(const char *address, struct AccessItem *aconf)
+{
+ int bits = 0;
+ uint32_t hv = 0;
+ dlink_node *ptr = NULL, *ptr_next = NULL;
+ struct irc_ssaddr addr;
+
+ switch (parse_netmask(address, &addr, &bits))
+ {
+ case HM_IPV4:
+ /* We have to do this, since we do not re-hash for every bit -A1kmm. */
+ bits -= bits % 8;
+ hv = hash_ipv4(&addr, bits);
+ break;
+#ifdef IPV6
+ case HM_IPV6:
+ /* We have to do this, since we do not re-hash for every bit -A1kmm. */
+ bits -= bits % 16;
+ hv = hash_ipv6(&addr, bits);
+ break;
+#endif
+ default: /* HM_HOST */
+ hv = get_mask_hash(address);
+ break;
+ }
+
+ DLINK_FOREACH_SAFE(ptr, ptr_next, atable[hv].head)
+ {
+ struct AddressRec *arec = ptr->data;
+
+ if (arec->aconf == aconf)
+ {
+ dlinkDelete(&arec->node, &atable[hv]);
+ aconf->status |= CONF_ILLEGAL;
+
+ if (!aconf->clients)
+ free_access_item(aconf);
+
+ MyFree(arec);
+ return;
+ }
+ }
+}
+
+/* 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 AccessItems if nothing references
+ * them, otherwise sets them as illegal.
+ */
+void
+clear_out_address_conf(void)
+{
+ unsigned int i = 0;
+ dlink_node *ptr = NULL, *ptr_next = NULL;
+
+ for (i = 0; i < ATABLE_SIZE; ++i)
+ {
+ DLINK_FOREACH_SAFE(ptr, ptr_next, atable[i].head)
+ {
+ struct AddressRec *arec = ptr->data;
+
+ /* We keep the temporary K-lines and destroy the
+ * permanent ones, just to be confusing :) -A1kmm
+ */
+ if (!(arec->aconf->flags & CONF_FLAGS_TEMPORARY))
+ {
+ dlinkDelete(&arec->node, &atable[i]);
+ /* unlink it from link list - Dianora */
+ arec->aconf->status |= CONF_ILLEGAL;
+
+ if (!arec->aconf->clients)
+ free_access_item(arec->aconf);
+ MyFree(arec);
+ }
+ }
+ }
+}
+
+static void
+hostmask_send_expiration(struct AddressRec *arec)
+{
+ char ban_type = '\0';
+
+ if (!ConfigFileEntry.tkline_expire_notices)
+ return;
+
+ switch (arec->type)
+ {
+ case CONF_KLINE:
+ ban_type = 'K';
+ break;
+ case CONF_DLINE:
+ ban_type = 'D';
+ break;
+ case CONF_GLINE:
+ ban_type = 'G';
+ break;
+ }
+
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Temporary %c-line for [%s@%s] expired", ban_type,
+ (arec->aconf->user) ? arec->aconf->user : "*",
+ (arec->aconf->host) ? arec->aconf->host : "*");
+}
+
+void
+hostmask_expire_temporary(void)
+{
+ unsigned int i = 0;
+ dlink_node *ptr = NULL, *ptr_next = NULL;
+
+ for (i = 0; i < ATABLE_SIZE; ++i)
+ {
+ DLINK_FOREACH_SAFE(ptr, ptr_next, atable[i].head)
+ {
+ struct AddressRec *arec = ptr->data;
+
+ if (!IsConfTemporary(arec->aconf) || arec->aconf->hold > CurrentTime)
+ continue;
+
+ switch (arec->type)
+ {
+ case CONF_KLINE:
+ case CONF_DLINE:
+ case CONF_GLINE:
+ hostmask_send_expiration(arec);
+
+ dlinkDelete(&arec->node, &atable[i]);
+ free_access_item(arec->aconf);
+ MyFree(arec);
+ break;
+ }
+ }
+ }
+}
diff --git a/src/irc_res.c b/src/irc_res.c
new file mode 100644
index 0000000..200b68d
--- /dev/null
+++ b/src/irc_res.c
@@ -0,0 +1,836 @@
+/*
+ * 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$
+ *
+ * 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
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "balloc.h"
+#include "client.h"
+#include "event.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "rng_mt.h"
+#include "fdlist.h"
+#include "s_bsd.h"
+#include "log.h"
+#include "s_misc.h"
+#include "send.h"
+#include "memory.h"
+#include "irc_res.h"
+#include "irc_reslib.h"
+
+#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, possibly because AAAA failed */
+#ifdef IPV6
+ REQ_AAAA, /* Looking up an AAAA */
+#endif
+ 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 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_ssaddr addr;
+ char *name;
+ dns_callback_fnc callback;
+ void *callback_ctx;
+};
+
+static fde_t ResolverFileDescriptor;
+static dlink_list request_list = { NULL, NULL, 0 };
+static BlockHeap *dns_heap = NULL;
+
+static void rem_request(struct reslist *);
+static struct reslist *make_request(dns_callback_fnc, void *);
+static void do_query_name(dns_callback_fnc, void *,
+ const char *, struct reslist *, int);
+static void do_query_number(dns_callback_fnc, void *,
+ const struct irc_ssaddr *,
+ struct reslist *);
+static void query_name(const char *, int, int, struct reslist *);
+static int send_res_msg(const char *, int, int);
+static void resend_query(struct reslist *);
+static int proc_answer(struct reslist *, HEADER *, char *, char *);
+static struct reslist *find_id(int);
+
+
+/*
+ * 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_ssaddr *inp)
+{
+#ifdef IPV6
+ const struct sockaddr_in6 *v6;
+ const struct sockaddr_in6 *v6in = (const struct sockaddr_in6 *)inp;
+#endif
+ const struct sockaddr_in *v4;
+ const struct sockaddr_in *v4in = (const struct sockaddr_in *)inp;
+ int ns;
+
+ for (ns = 0; ns < irc_nscount; ++ns)
+ {
+ const struct irc_ssaddr *srv = &irc_nsaddr_list[ns];
+#ifdef IPV6
+ v6 = (const struct sockaddr_in6 *)srv;
+#endif
+ v4 = (const 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.ss_family)
+ {
+#ifdef IPV6
+ case AF_INET6:
+ if (srv->ss.ss_family == inp->ss.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)))
+ return 1;
+ break;
+#endif
+ case AF_INET:
+ if (srv->ss.ss_family == inp->ss.ss_family)
+ if (v4->sin_port == v4in->sin_port)
+ if (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->callback)(request->callback_ctx, NULL, 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 (!ResolverFileDescriptor.flags.open)
+ {
+ if (comm_open(&ResolverFileDescriptor, irc_nsaddr_list[0].ss.ss_family,
+ SOCK_DGRAM, 0, "Resolver socket") == -1)
+ return;
+
+ /* At the moment, the resolver FD data is global .. */
+ comm_setselect(&ResolverFileDescriptor, 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)
+{
+ dns_heap = BlockHeapCreate("dns", sizeof(struct reslist), DNS_HEAP_SIZE);
+ memset(&ResolverFileDescriptor, 0, sizeof(fde_t));
+ start_resolver();
+}
+
+/*
+ * restart_resolver - reread resolv.conf, reopen socket
+ */
+void
+restart_resolver(void)
+{
+ fd_close(&ResolverFileDescriptor);
+ eventDelete(timeout_resolver, NULL); /* -ddosen */
+ start_resolver();
+}
+
+/*
+ * 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);
+ BlockHeapFree(dns_heap, request);
+}
+
+/*
+ * make_request - Create a DNS request record for the server.
+ */
+static struct reslist *
+make_request(dns_callback_fnc callback, void *ctx)
+{
+ struct reslist *request = BlockHeapAlloc(dns_heap);
+
+ request->sentat = CurrentTime;
+ request->retries = 3;
+ request->resend = 1;
+ request->timeout = 4; /* start at 4 and exponential inc. */
+ request->state = REQ_IDLE;
+ request->callback = callback;
+ request->callback_ctx = ctx;
+
+ 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 void *vptr)
+{
+ dlink_node *ptr = NULL, *next_ptr = NULL;
+
+ DLINK_FOREACH_SAFE(ptr, next_ptr, request_list.head)
+ {
+ struct reslist *request = ptr->data;
+
+ if (request->callback_ctx == vptr)
+ 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(ResolverFileDescriptor.fd, msg, len, 0,
+ (struct sockaddr*)&(irc_nsaddr_list[i]),
+ irc_nsaddr_list[i].ss_len) == 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 = NULL;
+
+ DLINK_FOREACH(ptr, request_list.head)
+ {
+ struct reslist *request = ptr->data;
+
+ if (request->id == id)
+ return request;
+ }
+
+ return NULL;
+}
+
+/*
+ * gethost_byname_type - get host address from name
+ *
+ */
+void
+gethost_byname_type(dns_callback_fnc callback, void *ctx, const char *name, int type)
+{
+ assert(name != NULL);
+ do_query_name(callback, ctx, name, NULL, type);
+}
+
+/*
+ * gethost_byname - wrapper for _type - send T_AAAA first if IPV6 supported
+ */
+void
+gethost_byname(dns_callback_fnc callback, void *ctx, const char *name)
+{
+#ifdef IPV6
+ gethost_byname_type(callback, ctx, name, T_AAAA);
+#else
+ gethost_byname_type(callback, ctx, name, T_A);
+#endif
+}
+
+/*
+ * gethost_byaddr - get host name from address
+ */
+void
+gethost_byaddr(dns_callback_fnc callback, void *ctx, const struct irc_ssaddr *addr)
+{
+ do_query_number(callback, ctx, addr, NULL);
+}
+
+/*
+ * do_query_name - nameserver lookup name
+ */
+static void
+do_query_name(dns_callback_fnc callback, void *ctx, const char *name,
+ struct reslist *request, int type)
+{
+ char host_name[HOSTLEN + 1];
+
+ strlcpy(host_name, name, sizeof(host_name));
+
+ if (request == NULL)
+ {
+ request = make_request(callback, ctx);
+ request->name = MyMalloc(strlen(host_name) + 1);
+ request->type = type;
+ strcpy(request->name, host_name);
+#ifdef IPV6
+ if (type != T_A)
+ request->state = REQ_AAAA;
+ else
+#endif
+ request->state = REQ_A;
+ }
+
+ request->type = type;
+ query_name(host_name, C_IN, type, request);
+}
+
+/*
+ * do_query_number - Use this to do reverse IP# lookups.
+ */
+static void
+do_query_number(dns_callback_fnc callback, void *ctx,
+ const struct irc_ssaddr *addr,
+ struct reslist *request)
+{
+ char ipbuf[128];
+ const unsigned char *cp;
+
+ if (addr->ss.ss_family == AF_INET)
+ {
+ const struct sockaddr_in *v4 = (const struct sockaddr_in *)addr;
+ cp = (const unsigned char *)&v4->sin_addr.s_addr;
+
+ snprintf(ipbuf, sizeof(ipbuf), "%u.%u.%u.%u.in-addr.arpa.",
+ (unsigned int)(cp[3]), (unsigned int)(cp[2]),
+ (unsigned int)(cp[1]), (unsigned int)(cp[0]));
+ }
+#ifdef IPV6
+ else if (addr->ss.ss_family == AF_INET6)
+ {
+ const struct sockaddr_in6 *v6 = (const struct sockaddr_in6 *)addr;
+ cp = (const unsigned char *)&v6->sin6_addr.s6_addr;
+
+ snprintf(ipbuf, sizeof(ipbuf),
+ "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
+ "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.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
+ if (request == NULL)
+ {
+ request = make_request(callback, ctx);
+ request->type = T_PTR;
+ memcpy(&request->addr, addr, sizeof(struct irc_ssaddr));
+ request->name = MyMalloc(HOSTLEN + 1);
+ }
+
+ query_name(ipbuf, C_IN, T_PTR, request);
+}
+
+/*
+ * query_name - generate a query based on class, type and name.
+ */
+static void
+query_name(const char *name, int query_class, int type,
+ struct reslist *request)
+{
+ char buf[MAXPACKET];
+ int request_len = 0;
+
+ memset(buf, 0, sizeof(buf));
+
+ if ((request_len = irc_res_mkquery(name, query_class, type,
+ (unsigned char *)buf, sizeof(buf))) > 0)
+ {
+ HEADER *header = (HEADER *)buf;
+
+ /*
+ * generate an unique id
+ * NOTE: we don't have to worry about converting this to and from
+ * network byte order, the nameserver does not interpret this value
+ * and returns it unchanged
+ */
+ do
+ header->id = (header->id + genrand_int32()) & 0xffff;
+ while (find_id(header->id));
+
+ 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, NULL, &request->addr, request);
+ break;
+ case T_A:
+ do_query_name(NULL, NULL, request->name, request, request->type);
+ break;
+#ifdef IPV6
+ case T_AAAA:
+ /* didnt work, try A */
+ if (request->state == REQ_AAAA)
+ do_query_name(NULL, NULL, request->name, request, T_A);
+#endif
+ default:
+ break;
+ }
+}
+
+/*
+ * 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)
+ break;
+
+ current += (size_t)n + QFIXEDSZ;
+ }
+
+ /*
+ * process each answer sent to us blech.
+ */
+ while (header->ancount > 0 && (char *)current < eob)
+ {
+ header->ancount--;
+
+ n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob, current,
+ hostbuf, sizeof(hostbuf));
+
+ if (n < 0 /* broken message */ || 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;
+ request->addr.ss_len = 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;
+
+ request->addr.ss_len = 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 /* broken message */ || n == 0 /* no more answers left */)
+ return 0;
+
+ strlcpy(request->name, hostbuf, HOSTLEN + 1);
+ 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(LOG_TYPE_IRCD, "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(fde_t *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;
+ int rc;
+ socklen_t len = sizeof(struct irc_ssaddr);
+ struct irc_ssaddr lsin;
+
+ rc = recvfrom(fd->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, 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);
+
+ /*
+ * check against possibly fake replies
+ */
+ if (!res_ourserver(&lsin))
+ return;
+
+ /*
+ * response for an id which we have already received an answer for
+ * just ignore this response.
+ */
+ if (!(request = find_id(header->id)))
+ return;
+
+ if ((header->rcode != NO_ERRORS) || (header->ancount == 0))
+ {
+ if (header->rcode == SERVFAIL || header->rcode == NXDOMAIN)
+ {
+ /*
+ * If a bad error was returned, stop here and don't
+ * send any more (no retries granted).
+ */
+ (*request->callback)(request->callback_ctx, NULL, NULL);
+ rem_request(request);
+ }
+#ifdef IPV6
+ else
+ {
+ /*
+ * If we havent already tried this, and we're looking up AAAA, try A
+ * now
+ */
+ if (request->state == REQ_AAAA && request->type == T_AAAA)
+ {
+ request->timeout += 4;
+ resend_query(request);
+ }
+ }
+#endif
+
+ return;
+ }
+
+ /*
+ * If this fails there was an error decoding the received packet,
+ * try it again and hope it works the next time.
+ */
+ if (proc_answer(request, header, buf, buf + rc))
+ {
+ 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->callback)(request->callback_ctx, NULL, NULL);
+ rem_request(request);
+ return;
+ }
+
+ /*
+ * Lookup the 'authoritative' name that we were given for the
+ * ip#.
+ *
+ */
+#ifdef IPV6
+ if (request->addr.ss.ss_family == AF_INET6)
+ gethost_byname_type(request->callback, request->callback_ctx, request->name, T_AAAA);
+ else
+#endif
+ gethost_byname_type(request->callback, request->callback_ctx, request->name, T_A);
+ rem_request(request);
+ }
+ else
+ {
+ /*
+ * got a name and address response, client resolved
+ */
+ (*request->callback)(request->callback_ctx, &request->addr, request->name);
+ rem_request(request);
+ }
+ }
+ else if (!request->sent)
+ {
+ /* XXX - we got a response for a query we didn't send with a valid id?
+ * this should never happen, bail here and leave the client unresolved
+ */
+ assert(0);
+
+ /* XXX don't leak it */
+ rem_request(request);
+ }
+}
+
+void
+report_dns_servers(struct Client *source_p)
+{
+ int i;
+ char ipaddr[HOSTIPLEN + 1];
+
+ for (i = 0; i < irc_nscount; i++)
+ {
+ getnameinfo((struct sockaddr *)&(irc_nsaddr_list[i]),
+ irc_nsaddr_list[i].ss_len, ipaddr,
+ sizeof(ipaddr), NULL, 0, NI_NUMERICHOST);
+ sendto_one(source_p, form_str(RPL_STATSALINE),
+ me.name, source_p->name, ipaddr);
+ }
+}
diff --git a/src/irc_reslib.c b/src/irc_reslib.c
new file mode 100644
index 0000000..42bf2c2
--- /dev/null
+++ b/src/irc_reslib.c
@@ -0,0 +1,1168 @@
+/*
+ * 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 "irc_res.h"
+#include "irc_reslib.h"
+#include "irc_string.h"
+
+#define NS_TYPE_ELT 0x40 /* EDNS0 extended label type */
+#define DNS_LABELTYPE_BITSTRING 0x41
+#define MAXLINE 128
+
+/* $Id$ */
+
+struct irc_ssaddr irc_nsaddr_list[IRCD_MAXNS];
+int irc_nscount = 0;
+
+static const char digits[] = "0123456789";
+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 labellen(const unsigned char *lp);
+static int special(int ch);
+static int printable(int ch);
+static int irc_decode_bitstring(const unsigned 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 unsigned 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 unsigned char *, char *, size_t);
+static int irc_ns_name_skip(const unsigned char **, const unsigned char *);
+static int mklower(int ch);
+
+
+/* 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)
+ 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].ss, res->ai_addr, res->ai_addrlen);
+ irc_nsaddr_list[irc_nscount++].ss_len = res->ai_addrlen;
+ freeaddrinfo(res);
+}
+
+/* parse_resvconf()
+ *
+ * inputs - NONE
+ * output - -1 if failure 0 if success
+ * side effects - fills in irc_nsaddr_list
+ */
+static void
+parse_resvconf(void)
+{
+ char *p;
+ char *opt;
+ char *arg;
+ char input[MAXLINE];
+ FILE *file;
+
+ /* XXX "/etc/resolv.conf" should be from a define in config.h perhaps
+ * for cygwin support etc. this hardcodes it to unix for now -db
+ */
+ if ((file = fopen("/etc/resolv.conf", "r")) == NULL)
+ return;
+
+ 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)
+ ++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, "nameserver"))
+ add_nameserver(arg);
+ }
+
+ fclose(file);
+}
+
+void
+irc_res_init(void)
+{
+ irc_nscount = 0;
+ memset(irc_nsaddr_list, 0, sizeof(irc_nsaddr_list));
+
+ parse_resvconf();
+
+ if (!irc_nscount)
+ add_nameserver("127.0.0.1");
+}
+
+/*
+ * 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);
+} /*2*/
+
+/*
+ * 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(tmp, dst, dstsiz) == -1)
+ return(-1);
+ return(n);
+} /*2*/
+
+/*
+ * 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);
+} /*2*/
+
+/*
+ * 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 unsigned char *src, char *dst, size_t dstsiz)
+{
+ const unsigned 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((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);
+} /*2*/
+
+/*
+ * 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);
+} /*2*/
+
+/*
+ * 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);
+} /*2*/
+
+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);
+ }
+} /*2*/
+
+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);
+} /*2*/
+
+
+/*
+ * 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);
+} /*2*/
+
+static int
+irc_decode_bitstring(const unsigned char **cpp, char *dn, const char *eom)
+{
+ const unsigned 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);
+} /*2*/
+
+/*
+ * 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,
+ 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);
+} /*2*/
+
+/*
+ * 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);
+} /*2*/
+
+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 unsigned char *eom)
+{
+ int afterslash = 0;
+ const char *cp = *bp;
+ unsigned char *tp;
+ char 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 = *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 = tp;
+
+ return(0);
+} /*2*/
+
+/*
+ * 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);
+} /*2*/
+
+/*
+ * * 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);
+} /*2*/
+
+/* 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;
+ const 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_ns_name_compress(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/irc_string.c b/src/irc_string.c
new file mode 100644
index 0000000..08b4321
--- /dev/null
+++ b/src/irc_string.c
@@ -0,0 +1,263 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * irc_string.c: IRC string functions.
+ *
+ * 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$
+ */
+
+#include "config.h"
+#ifdef HAVE_LIBPCRE
+#include <pcre.h>
+#endif
+
+#include "stdinc.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+
+
+int
+has_wildcards(const char *s)
+{
+ char c;
+
+ while ((c = *s++))
+ if (IsMWildChar(c))
+ return 1;
+
+ return 0;
+}
+
+/*
+ * 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;
+}
+
+/*
+ * strip_tabs(dst, src, length)
+ *
+ * Copies src to dst, while converting all \t (tabs) into spaces.
+ */
+void
+strip_tabs(char *dest, const char *src, size_t len)
+{
+ char *d = dest;
+
+ /* Sanity check; we don't want anything nasty... */
+ assert(dest != NULL);
+ assert(src != NULL);
+ assert(len > 0);
+
+ for (; --len && *src; ++src)
+ *d++ = *src == '\t' ? ' ' : *src;
+
+ *d = '\0'; /* NUL terminate, thanks and goodbye */
+}
+
+/*
+ * strtoken - walk through a string of tokens, using a set of separators
+ * argv 9/90
+ *
+ */
+#ifndef HAVE_STRTOK_R
+
+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;
+}
+#endif /* !HAVE_STRTOK_R */
+
+/* libio_basename()
+ *
+ * input - i.e. "/usr/local/ircd/modules/m_whois.so"
+ * output - i.e. "m_whois.so"
+ * side effects - this will be overwritten on subsequent calls
+ */
+const char *
+libio_basename(const char *path)
+{
+ const char *s;
+
+ if ((s = strrchr(path, '/')) == NULL)
+ s = path;
+ else
+ s++;
+
+ return s;
+}
+
+/*
+ * 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
+
+#ifdef HAVE_LIBPCRE
+void *
+ircd_pcre_compile(const char *pattern, const char **errptr)
+{
+ int erroroffset = 0;
+ int options = PCRE_EXTRA;
+
+ assert(pattern);
+
+ return pcre_compile(pattern, options, errptr, &erroroffset, NULL);
+}
+
+int
+ircd_pcre_exec(const void *code, const char *subject)
+{
+ assert(code && subject);
+
+ return pcre_exec(code, NULL, subject, strlen(subject), 0, 0, NULL, 0) < 0;
+}
+#endif
diff --git a/src/ircd.c b/src/ircd.c
new file mode 100644
index 0000000..ee02bcd
--- /dev/null
+++ b/src/ircd.c
@@ -0,0 +1,658 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * ircd.c: Starts up and runs the ircd.
+ *
+ * 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$
+ */
+
+#include "stdinc.h"
+#include "s_user.h"
+#include "list.h"
+#include "ircd.h"
+#include "channel.h"
+#include "channel_mode.h"
+#include "client.h"
+#include "event.h"
+#include "fdlist.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd_signal.h"
+#include "s_gline.h"
+#include "motd.h"
+#include "hostmask.h"
+#include "numeric.h"
+#include "packet.h"
+#include "parse.h"
+#include "irc_res.h"
+#include "restart.h"
+#include "rng_mt.h"
+#include "s_auth.h"
+#include "s_bsd.h"
+#include "conf.h"
+#include "log.h"
+#include "s_misc.h"
+#include "s_serv.h" /* try_connections */
+#include "send.h"
+#include "whowas.h"
+#include "modules.h"
+#include "memory.h"
+#include "hook.h"
+#include "ircd_getopt.h"
+#include "balloc.h"
+#include "motd.h"
+#include "supported.h"
+#include "watch.h"
+
+
+/* /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 = { NULL, NULL, NULL };
+struct Counter Count = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+struct ServerState_t server_state = { 0 };
+struct logging_entry ConfigLoggingEntry = { .use_logging = 1 };
+struct ServerStatistics ServerStats;
+struct timeval SystemTime;
+struct Client me; /* That's me */
+struct LocalUser meLocalUser; /* That's also part of me */
+
+const char *logFileName = LPATH;
+const char *pidFileName = PPATH;
+
+char **myargv;
+
+int dorehash = 0;
+int doremotd = 0;
+
+/* Set to zero because it should be initialized later using
+ * initialize_server_capabs
+ */
+int default_server_capabs = 0;
+unsigned int splitmode;
+unsigned int splitchecking;
+unsigned int split_users;
+unsigned int split_servers;
+
+/* Do klines the same way hybrid-6 did them, i.e. at the
+ * top of the next io_loop instead of in the same loop as
+ * the klines are being applied.
+ *
+ * This should fix strange CPU starvation as very indirectly reported.
+ * (Why do you people not email bug reports? WHY? WHY?)
+ *
+ * - Dianora
+ */
+
+int rehashed_klines = 0;
+
+
+/*
+ * print_startup - print startup information
+ */
+static void
+print_startup(int pid)
+{
+ printf("ircd: version %s\n", ircd_version);
+ printf("ircd: pid %d\n", pid);
+ printf("ircd: running in %s mode from %s\n", !server_state.foreground ? "background"
+ : "foreground", ConfigFileEntry.dpath);
+}
+
+static void
+make_daemon(void)
+{
+ int pid;
+
+ if ((pid = fork()) < 0)
+ {
+ perror("fork");
+ exit(EXIT_FAILURE);
+ }
+ else if (pid > 0)
+ {
+ print_startup(pid);
+ exit(EXIT_SUCCESS);
+ }
+
+ setsid();
+}
+
+static int printVersion = 0;
+
+static struct lgetopt myopts[] = {
+ {"dlinefile", &ConfigFileEntry.dlinefile,
+ STRING, "File to use for dline.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"},
+ {"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"},
+ {"help", NULL, USAGE, "Print this text"},
+ {NULL, NULL, STRING, NULL},
+};
+
+void
+set_time(void)
+{
+ static char to_send[200];
+ struct timeval newtime;
+ newtime.tv_sec = 0;
+ newtime.tv_usec = 0;
+
+ if (gettimeofday(&newtime, NULL) == -1)
+ {
+ ilog(LOG_TYPE_IRCD, "Clock Failure (%s), TS can be corrupted",
+ strerror(errno));
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Clock Failure (%s), TS can be corrupted",
+ strerror(errno));
+ restart("Clock Failure");
+ }
+
+ if (newtime.tv_sec < CurrentTime)
+ {
+ snprintf(to_send, sizeof(to_send),
+ "System clock is running backwards - (%lu < %lu)",
+ (unsigned long)newtime.tv_sec, (unsigned long)CurrentTime);
+ report_error(L_ALL, to_send, me.name, 0);
+ set_back_events(CurrentTime - newtime.tv_sec);
+ }
+
+ SystemTime.tv_sec = newtime.tv_sec;
+ SystemTime.tv_usec = newtime.tv_usec;
+}
+
+static void
+io_loop(void)
+{
+ while (1 == 1)
+ {
+ /*
+ * Maybe we want a flags word?
+ * ie. if (REHASHED_KLINES(global_flags))
+ * SET_REHASHED_KLINES(global_flags)
+ * CLEAR_REHASHED_KLINES(global_flags)
+ *
+ * - Dianora
+ */
+ if (rehashed_klines)
+ {
+ check_conf_klines();
+ rehashed_klines = 0;
+ }
+
+ if (listing_client_list.head)
+ {
+ dlink_node *ptr = NULL, *ptr_next = NULL;
+ DLINK_FOREACH_SAFE(ptr, ptr_next, listing_client_list.head)
+ {
+ struct Client *client_p = ptr->data;
+ assert(client_p->localClient->list_task);
+ safe_list_channels(client_p, client_p->localClient->list_task, 0);
+ }
+ }
+
+ /* Run pending events, then get the number of seconds to the next
+ * event
+ */
+ while (eventNextTime() <= CurrentTime)
+ eventRun();
+
+ comm_select();
+ exit_aborted_clients();
+ free_exited_clients();
+ send_queued_all();
+
+ /* Check to see whether we have to rehash the configuration .. */
+ if (dorehash)
+ {
+ rehash(1);
+ dorehash = 0;
+ }
+ if (doremotd)
+ {
+ read_message_file(&ConfigFileEntry.motd);
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Got signal SIGUSR1, reloading ircd motd file");
+ doremotd = 0;
+ }
+ }
+}
+
+/* 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));
+
+ 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;
+
+ /* XXX I have no idea what to try here - Dianora */
+ GlobalSetOptions.joinfloodcount = 16;
+ GlobalSetOptions.joinfloodtime = 8;
+
+ 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;
+ /* End of global set options */
+}
+
+/* initialize_message_files()
+ *
+ * inputs - none
+ * output - none
+ * side effects - Set up all message files needed, motd etc.
+ */
+static void
+initialize_message_files(void)
+{
+ init_message_file(USER_MOTD, MPATH, &ConfigFileEntry.motd);
+ init_message_file(USER_LINKS, LIPATH, &ConfigFileEntry.linksfile);
+
+ read_message_file(&ConfigFileEntry.motd);
+ read_message_file(&ConfigFileEntry.linksfile);
+
+ init_isupport();
+}
+
+/* initialize_server_capabs()
+ *
+ * inputs - none
+ * output - none
+ */
+static void
+initialize_server_capabs(void)
+{
+ add_capability("QS", CAP_QS, 1);
+ add_capability("EOB", CAP_EOB, 1);
+ add_capability("TS6", CAP_TS6, 0);
+ add_capability("CLUSTER", CAP_CLUSTER, 1);
+ add_capability("SVS", CAP_SVS, 1);
+#ifdef HALFOPS
+ add_capability("HOPS", CAP_HOPS, 1);
+#endif
+}
+
+/* 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;
+
+ if ((fb = fopen(filename, "w")))
+ {
+ char buff[32];
+ unsigned int pid = (unsigned int)getpid();
+
+ snprintf(buff, sizeof(buff), "%u\n", pid);
+
+ if ((fputs(buff, fb) == -1))
+ ilog(LOG_TYPE_IRCD, "Error writing %u to pid file %s (%s)",
+ pid, filename, strerror(errno));
+
+ fclose(fb);
+ }
+ else
+ {
+ ilog(LOG_TYPE_IRCD, "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)
+ {
+ /* log(L_ERROR, "Error reading from pid file %s (%s)", filename,
+ * strerror(errno));
+ */
+ }
+ else
+ {
+ pidfromfile = atoi(buff);
+
+ if (!kill(pidfromfile, 0))
+ {
+ /* log(L_ERROR, "Server is already running"); */
+ printf("ircd: daemon is already running\n");
+ exit(-1);
+ }
+ }
+
+ fclose(fb);
+ }
+ else if (errno != ENOENT)
+ {
+ /* log(L_ERROR, "Error opening pid file %s", filename); */
+ }
+}
+
+/* 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
+}
+
+/* init_ssl()
+ *
+ * inputs - nothing
+ * output - nothing
+ * side effects - setups SSL context.
+ */
+static void
+init_ssl(void)
+{
+#ifdef HAVE_LIBCRYPTO
+ SSL_load_error_strings();
+ SSLeay_add_ssl_algorithms();
+
+ if ((ServerInfo.server_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL)
+ {
+ const char *s;
+
+ fprintf(stderr, "ERROR: Could not initialize the SSL Server context -- %s\n",
+ s = ERR_lib_error_string(ERR_get_error()));
+ ilog(LOG_TYPE_IRCD, "ERROR: Could not initialize the SSL Server context -- %s\n", s);
+ }
+
+ SSL_CTX_set_options(ServerInfo.server_ctx, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1);
+ SSL_CTX_set_options(ServerInfo.server_ctx, SSL_OP_TLS_ROLLBACK_BUG|SSL_OP_ALL);
+ SSL_CTX_set_verify(ServerInfo.server_ctx, SSL_VERIFY_NONE, NULL);
+
+ if ((ServerInfo.client_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL)
+ {
+ const char *s;
+
+ fprintf(stderr, "ERROR: Could not initialize the SSL Client context -- %s\n",
+ s = ERR_lib_error_string(ERR_get_error()));
+ ilog(LOG_TYPE_IRCD, "ERROR: Could not initialize the SSL Client context -- %s\n", s);
+ }
+
+ SSL_CTX_set_options(ServerInfo.client_ctx, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1);
+ SSL_CTX_set_options(ServerInfo.client_ctx, SSL_OP_TLS_ROLLBACK_BUG|SSL_OP_ALL);
+ SSL_CTX_set_verify(ServerInfo.client_ctx, SSL_VERIFY_NONE, NULL);
+#endif /* HAVE_LIBCRYPTO */
+}
+
+/* init_callbacks()
+ *
+ * inputs - nothing
+ * output - nothing
+ * side effects - setups standard hook points
+ */
+static void
+init_callbacks(void)
+{
+ iorecv_cb = register_callback("iorecv", iorecv_default);
+ iosend_cb = register_callback("iosend", iosend_default);
+}
+
+int
+main(int argc, char *argv[])
+{
+ /* 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;
+ }
+
+ /* Setup corefile size immediately after boot -kre */
+ setup_corefile();
+
+ /* save server boot time right away, so getrusage works correctly */
+ set_time();
+
+ /* It ain't random, but it ought to be a little harder to guess */
+ init_genrand(SystemTime.tv_sec ^ (SystemTime.tv_usec | (getpid() << 20)));
+
+ me.localClient = &meLocalUser;
+ dlinkAdd(&me, &me.node, &global_client_list); /* Pointer to beginning
+ of Client list */
+ /* 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.xlinefile = XPATH; /* Server xline file */
+ ConfigFileEntry.dlinefile = DLPATH; /* dline file */
+ ConfigFileEntry.cresvfile = CRESVPATH; /* channel resv file */
+ ConfigFileEntry.nresvfile = NRESVPATH; /* nick resv file */
+ 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))
+ {
+ perror("chdir");
+ exit(EXIT_FAILURE);
+ }
+
+ init_ssl();
+
+ if (!server_state.foreground)
+ {
+ make_daemon();
+ close_standard_fds(); /* this needs to be before init_netio()! */
+ }
+ else
+ print_startup(getpid());
+
+ setup_signals();
+
+ /* Init the event subsystem */
+ eventInit();
+ /* We need this to initialise the fd array before anything else */
+ fdlist_init();
+ log_add_file(LOG_TYPE_IRCD, 0, logFileName);
+ check_can_use_v6();
+ init_comm(); /* This needs to be setup early ! -- adrian */
+ /* Check if there is pidfile and daemon already running */
+ check_pidfile(pidFileName);
+
+ initBlockHeap();
+ init_dlink_nodes();
+ init_callbacks();
+ initialize_message_files();
+ dbuf_init();
+ init_hash();
+ init_ip_hash_table(); /* client host ip hash table */
+ init_host_hash(); /* Host-hashtable. */
+ init_client();
+ init_class();
+ whowas_init();
+ watch_init();
+ init_auth(); /* Initialise the auth code */
+ init_resolver(); /* Needs to be setup before the io loop */
+ modules_init();
+ read_conf_files(1); /* cold start init conf files */
+ init_uid();
+ initialize_server_capabs(); /* Set up default_server_capabs */
+ initialize_global_set_options();
+ init_channels();
+
+ if (EmptyString(ServerInfo.sid))
+ {
+ ilog(LOG_TYPE_IRCD, "ERROR: No server id specified in serverinfo block.");
+ exit(EXIT_FAILURE);
+ }
+
+ strlcpy(me.id, ServerInfo.sid, sizeof(me.id));
+
+ if (EmptyString(ServerInfo.name))
+ {
+ ilog(LOG_TYPE_IRCD, "ERROR: No server name specified in serverinfo block.");
+ exit(EXIT_FAILURE);
+ }
+
+ strlcpy(me.name, ServerInfo.name, sizeof(me.name));
+
+ /* serverinfo{} description must exist. If not, error out.*/
+ if (EmptyString(ServerInfo.description))
+ {
+ ilog(LOG_TYPE_IRCD, "ERROR: No server description specified in serverinfo block.");
+ exit(EXIT_FAILURE);
+ }
+
+ strlcpy(me.info, ServerInfo.description, sizeof(me.info));
+
+ me.from = &me;
+ me.servptr = &me;
+ me.localClient->lasttime = CurrentTime;
+ me.localClient->since = CurrentTime;
+ me.localClient->firsttime = CurrentTime;
+
+ SetMe(&me);
+ make_server(&me);
+
+ hash_add_id(&me);
+ hash_add_client(&me);
+
+ /* add ourselves to global_serv_list */
+ dlinkAdd(&me, make_dlink_node(), &global_serv_list);
+
+ if (chdir(MODPATH))
+ {
+ ilog(LOG_TYPE_IRCD, "Could not load core modules. Terminating!");
+ exit(EXIT_FAILURE);
+ }
+
+ load_all_modules(1);
+ load_conf_modules();
+ load_core_modules(1);
+
+ /* Go back to DPATH after checking to see if we can chdir to MODPATH */
+ if (chdir(ConfigFileEntry.dpath))
+ {
+ perror("chdir");
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * assemble_umode_buffer() has to be called after
+ * reading conf/loading modules.
+ */
+ assemble_umode_buffer();
+
+ write_pidfile(pidFileName);
+
+ ilog(LOG_TYPE_IRCD, "Server Ready");
+
+ eventAddIsh("cleanup_glines", cleanup_glines, NULL, CLEANUP_GLINES_TIME);
+ eventAddIsh("cleanup_tklines", cleanup_tklines, NULL, CLEANUP_TKLINES_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 */
+ eventAddIsh("try_connections", try_connections, NULL, STARTUP_CONNECTIONS_TIME);
+
+ /* Setup the timeout check. I'll shift it later :) -- adrian */
+ eventAddIsh("comm_checktimeouts", comm_checktimeouts, NULL, 1);
+
+ if (ConfigServerHide.links_delay > 0)
+ eventAddIsh("write_links_file", write_links_file, NULL, ConfigServerHide.links_delay);
+ else
+ ConfigServerHide.links_disabled = 1;
+
+ if (splitmode)
+ eventAddIsh("check_splitmode", check_splitmode, NULL, 60);
+
+ io_loop();
+ return 0;
+}
diff --git a/src/ircd_signal.c b/src/ircd_signal.c
new file mode 100644
index 0000000..b76e542
--- /dev/null
+++ b/src/ircd_signal.c
@@ -0,0 +1,135 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * ircd_signal.c: responsible for ircd's signal handling
+ *
+ * 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$
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "ircd_signal.h"
+#include "ircd.h" /* dorehash */
+#include "restart.h" /* server_die */
+#include "memory.h"
+#include "s_bsd.h"
+
+/*
+ * sigterm_handler - exit the server
+ */
+static void
+sigterm_handler(int sig)
+{
+ server_die("received signal SIGTERM", 0);
+}
+
+/*
+ * 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;
+}
+
+/*
+ *
+ * inputs - nothing
+ * output - nothing
+ * side effects - Reaps zombies periodically
+ * -AndroSyn
+ */
+static void
+sigchld_handler(int sig)
+{
+ int status;
+ waitpid(-1, &status, WNOHANG);
+}
+
+/*
+ * sigint_handler - restart the server
+ */
+static void
+sigint_handler(int sig)
+{
+ server_die("SIGINT received", !server_state.foreground);
+}
+
+/*
+ * setup_signals - initialize signal handlers for server
+ */
+void
+setup_signals(void)
+{
+ 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);
+ sigaction(SIGALRM, &act, 0);
+#ifdef SIGTRAP
+ sigaddset(&act.sa_mask, SIGTRAP);
+#endif
+#ifdef SIGXFSZ
+ sigaddset(&act.sa_mask, SIGXFSZ);
+ sigaction(SIGXFSZ, &act, 0);
+#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 = 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 = sigchld_handler;
+ sigaddset(&act.sa_mask, SIGCHLD);
+ sigaction(SIGCHLD, &act, 0);
+}
diff --git a/src/list.c b/src/list.c
new file mode 100644
index 0000000..2850d46
--- /dev/null
+++ b/src/list.c
@@ -0,0 +1,277 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * list.c: Various assorted functions for various structures.
+ *
+ * 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$
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "balloc.h"
+
+static BlockHeap *dnode_heap;
+
+
+/* init_dlink_nodes()
+ *
+ * inputs - NONE
+ * output - NONE
+ * side effects - initializes the dnode BlockHeap
+ */
+void
+init_dlink_nodes(void)
+{
+ dnode_heap = BlockHeapCreate("dlink node", sizeof(dlink_node), DNODE_HEAP_SIZE);
+}
+
+/* make_dlink_node()
+ *
+ * inputs - NONE
+ * output - pointer to new dlink_node
+ * side effects - NONE
+ */
+dlink_node *
+make_dlink_node(void)
+{
+ dlink_node *lp = BlockHeapAlloc(dnode_heap);
+
+ return lp;
+}
+
+/* free_dlink_node()
+ *
+ * inputs - pointer to dlink_node
+ * output - NONE
+ * side effects - free given dlink_node
+ */
+void
+free_dlink_node(dlink_node *ptr)
+{
+ BlockHeapFree(dnode_heap, ptr);
+}
+
+/*
+ * dlink_ routines are stolen from squid, except for dlinkAddBefore,
+ * which is mine.
+ * -- adrian
+ */
+void
+dlinkAdd(void *data, dlink_node *m, dlink_list *list)
+{
+ 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++;
+}
+
+void
+dlinkAddBefore(dlink_node *b, void *data, dlink_node *m, dlink_list *list)
+{
+ /* 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++;
+ }
+}
+
+void
+dlinkAddTail(void *data, dlink_node *m, dlink_list *list)
+{
+ 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. */
+void
+dlinkDelete(dlink_node *m, dlink_list *list)
+{
+ /* 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
+ {
+ assert(list->tail == m);
+ list->tail = m->prev;
+ }
+
+ if (m->prev)
+ m->prev->next = m->next;
+ else
+ {
+ assert(list->head == m);
+ list->head = m->next;
+ }
+
+ /* Set this to NULL does matter */
+ m->next = m->prev = NULL;
+ list->length--;
+}
+
+/*
+ * 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.
+ */
+dlink_node *
+dlinkFind(dlink_list *list, void *data)
+{
+ dlink_node *ptr;
+
+ DLINK_FOREACH(ptr, list->head)
+ if (ptr->data == data)
+ return ptr;
+
+ return NULL;
+}
+
+void
+dlinkMoveList(dlink_list *from, dlink_list *to)
+{
+ /* There are three cases */
+ /* case one, nothing in from list */
+ if (from->head == NULL)
+ return;
+
+ /* case two, nothing in to list */
+ /* actually if to->head is NULL and to->tail isn't, thats a bug */
+ 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;
+ from->head->prev = to->head->prev;
+ to->head->prev = from->tail;
+ to->head = from->head;
+ from->head = from->tail = NULL;
+ to->length += from->length;
+ from->length = 0;
+ /* I think I got that right */
+}
+
+void
+dlink_move_node(dlink_node *m, dlink_list *list_del, dlink_list *list_add)
+{
+ /* Assumption: If m->next == NULL, then list_del->tail == m
+ * and: If m->prev == NULL, then list_del->head == m
+ */
+ if (m->next)
+ m->next->prev = m->prev;
+ else
+ {
+ assert(list->tail == m);
+ list_del->tail = m->prev;
+ }
+
+ if (m->prev)
+ m->prev->next = m->next;
+ else
+ {
+ assert(list->head == m);
+ list_del->head = m->next;
+ }
+
+ /* Set this to NULL does matter */
+ m->prev = NULL;
+ m->next = list_add->head;
+
+ /* Assumption: If list_add->tail != NULL, list_add->head != NULL */
+ if (list_add->head != NULL)
+ list_add->head->prev = m;
+ else if (list_add->tail == NULL)
+ list_add->tail = m;
+
+ list_add->head = m;
+ list_add->length++;
+ list_del->length--;
+}
+
+dlink_node *
+dlinkFindDelete(dlink_list *list, void *data)
+{
+ dlink_node *m;
+
+ DLINK_FOREACH(m, list->head)
+ {
+ if (m->data == data)
+ {
+ if (m->next)
+ m->next->prev = m->prev;
+ else
+ {
+ assert(list->tail == m);
+ list->tail = m->prev;
+ }
+ if (m->prev)
+ m->prev->next = m->next;
+ else
+ {
+ assert(list->head == m);
+ list->head = m->next;
+ }
+ /* Set this to NULL does matter */
+ m->next = m->prev = NULL;
+ list->length--;
+
+ return m;
+ }
+ }
+
+ return NULL;
+}
+
+
diff --git a/src/listener.c b/src/listener.c
new file mode 100644
index 0000000..3572570
--- /dev/null
+++ b/src/listener.c
@@ -0,0 +1,429 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * listener.c: Listens on a port.
+ *
+ * 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$
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "listener.h"
+#include "client.h"
+#include "fdlist.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "ircd_defs.h"
+#include "s_bsd.h"
+#include "numeric.h"
+#include "conf.h"
+#include "send.h"
+#include "memory.h"
+
+static PF accept_connection;
+
+static dlink_list ListenerPollList = { NULL, NULL, 0 };
+static void close_listener(struct Listener *listener);
+
+static struct Listener *
+make_listener(int port, struct irc_ssaddr *addr)
+{
+ struct Listener *listener = MyMalloc(sizeof(struct Listener));
+
+ listener->port = port;
+ memcpy(&listener->addr, addr, sizeof(struct irc_ssaddr));
+
+ return listener;
+}
+
+void
+free_listener(struct Listener *listener)
+{
+ assert(listener != NULL);
+
+ dlinkDelete(&listener->listener_node, &ListenerPollList);
+ MyFree(listener);
+}
+
+/*
+ * get_listener_name - return displayable listener name and port
+ * returns "host.foo.org/6667" for a given listener
+ */
+const char *
+get_listener_name(const struct Listener *const listener)
+{
+ static char buf[HOSTLEN + HOSTLEN + PORTNAMELEN + 4];
+
+ snprintf(buf, sizeof(buf), "%s[%s/%u]", me.name,
+ listener->name, listener->port);
+ return buf;
+}
+
+/* show_ports()
+ *
+ * inputs - pointer to client to show ports to
+ * output - none
+ * side effects - send port listing to a client
+ */
+void
+show_ports(struct Client *source_p)
+{
+ char buf[6];
+ char *p = NULL;
+ dlink_node *ptr;
+
+ DLINK_FOREACH(ptr, ListenerPollList.head)
+ {
+ const struct Listener *listener = ptr->data;
+ p = buf;
+
+ if (listener->flags & LISTENER_HIDDEN) {
+ if (!HasUMode(source_p, UMODE_ADMIN))
+ continue;
+ *p++ = 'H';
+ }
+
+ if (listener->flags & LISTENER_SERVER)
+ *p++ = 'S';
+ if (listener->flags & LISTENER_SSL)
+ *p++ = 's';
+ *p = '\0';
+ sendto_one(source_p, form_str(RPL_STATSPLINE),
+ me.name, source_p->name, 'P', listener->port,
+ HasUMode(source_p, UMODE_ADMIN) ? listener->name : me.name,
+ listener->ref_count, buf,
+ 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 HYBRID_SOMAXCONN
+ */
+#ifdef SOMAXCONN
+#undef HYBRID_SOMAXCONN
+#define HYBRID_SOMAXCONN SOMAXCONN
+#endif
+
+static int
+inetport(struct Listener *listener)
+{
+ struct irc_ssaddr lsin;
+ socklen_t opt = 1;
+
+ memset(&lsin, 0, sizeof(lsin));
+ memcpy(&lsin, &listener->addr, sizeof(lsin));
+
+ getnameinfo((struct sockaddr *)&lsin, lsin.ss_len, listener->name,
+ sizeof(listener->name), NULL, 0, NI_NUMERICHOST);
+
+ /*
+ * At first, open a new socket
+ */
+ if (comm_open(&listener->fd, listener->addr.ss.ss_family, SOCK_STREAM, 0,
+ "Listener socket") == -1)
+ {
+ report_error(L_ALL, "opening listener socket %s:%s",
+ get_listener_name(listener), errno);
+ return 0;
+ }
+
+ if (setsockopt(listener->fd.fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)))
+ {
+ report_error(L_ALL, "setting SO_REUSEADDR for listener %s:%s",
+ get_listener_name(listener), errno);
+ fd_close(&listener->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.
+ */
+ lsin.ss_port = htons(listener->port);
+
+ if (bind(listener->fd.fd, (struct sockaddr *)&lsin, lsin.ss_len))
+ {
+ report_error(L_ALL, "binding listener socket %s:%s",
+ get_listener_name(listener), errno);
+ fd_close(&listener->fd);
+ return 0;
+ }
+
+ if (listen(listener->fd.fd, HYBRID_SOMAXCONN))
+ {
+ report_error(L_ALL, "listen failed for %s:%s",
+ get_listener_name(listener), errno);
+ fd_close(&listener->fd);
+ return 0;
+ }
+
+ /* Listen completion events are READ events .. */
+
+ accept_connection(&listener->fd, listener);
+ return 1;
+}
+
+static struct Listener *
+find_listener(int port, struct irc_ssaddr *addr)
+{
+ dlink_node *ptr;
+ struct Listener *listener = NULL;
+ struct Listener *last_closed = NULL;
+
+ DLINK_FOREACH(ptr, ListenerPollList.head)
+ {
+ listener = ptr->data;
+
+ if ((port == listener->port) &&
+ (!memcmp(addr, &listener->addr, sizeof(struct irc_ssaddr))))
+ {
+ /* Try to return an open listener, otherwise reuse a closed one */
+ if (!listener->fd.flags.open)
+ last_closed = listener;
+ else
+ return (listener);
+ }
+ }
+
+ 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, unsigned int flags)
+{
+ struct Listener *listener;
+ struct irc_ssaddr vaddr;
+ struct addrinfo hints, *res;
+ char portname[PORTNAMELEN + 1];
+#ifdef IPV6
+ static short int pass = 0; /* if ipv6 and no address specified we need to
+ have two listeners; one for each protocol. */
+#endif
+
+ /*
+ * if no or invalid port in conf line, don't bother
+ */
+ if (!(port > 0 && port <= 0xFFFF))
+ return;
+
+ memset(&vaddr, 0, sizeof(vaddr));
+
+ /* Set up the hints structure */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ /* Get us ready for a bind() and don't bother doing dns lookup */
+ hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
+
+#ifdef IPV6
+ if (ServerInfo.can_use_v6)
+ {
+ snprintf(portname, sizeof(portname), "%d", port);
+ getaddrinfo("::", portname, &hints, &res);
+ vaddr.ss.ss_family = AF_INET6;
+ assert(res != NULL);
+
+ memcpy((struct sockaddr*)&vaddr, res->ai_addr, res->ai_addrlen);
+ vaddr.ss_port = port;
+ vaddr.ss_len = res->ai_addrlen;
+ freeaddrinfo(res);
+ }
+ else
+#endif
+ {
+ struct sockaddr_in *v4 = (struct sockaddr_in*) &vaddr;
+ v4->sin_addr.s_addr = INADDR_ANY;
+ vaddr.ss.ss_family = AF_INET;
+ vaddr.ss_len = sizeof(struct sockaddr_in);
+ v4->sin_port = htons(port);
+ }
+
+ snprintf(portname, PORTNAMELEN, "%d", port);
+
+ if (vhost_ip)
+ {
+ if (getaddrinfo(vhost_ip, portname, &hints, &res))
+ return;
+
+ assert(res != NULL);
+
+ memcpy((struct sockaddr*)&vaddr, res->ai_addr, res->ai_addrlen);
+ vaddr.ss_port = port;
+ vaddr.ss_len = res->ai_addrlen;
+ freeaddrinfo(res);
+ }
+#ifdef IPV6
+ else if (pass == 0 && ServerInfo.can_use_v6)
+ {
+ /* add the ipv4 listener if we havent already */
+ pass = 1;
+ add_listener(port, "0.0.0.0", flags);
+ }
+ pass = 0;
+#endif
+
+ if ((listener = find_listener(port, &vaddr)))
+ {
+ listener->flags = flags;
+ if (listener->fd.flags.open)
+ return;
+ }
+ else
+ {
+ listener = make_listener(port, &vaddr);
+ dlinkAdd(listener, &listener->listener_node, &ListenerPollList);
+ listener->flags = flags;
+ }
+
+ if (inetport(listener))
+ listener->active = 1;
+ else
+ close_listener(listener);
+}
+
+/*
+ * close_listener - close a single listener
+ */
+static void
+close_listener(struct Listener *listener)
+{
+ assert(listener != NULL);
+
+ if (listener == NULL)
+ return;
+
+ if (listener->fd.flags.open)
+ fd_close(&listener->fd);
+
+ 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(void)
+{
+ dlink_node *ptr = NULL, *next_ptr = NULL;
+
+ /* close all 'extra' listening ports we have */
+ DLINK_FOREACH_SAFE(ptr, next_ptr, ListenerPollList.head)
+ close_listener(ptr->data);
+}
+
+#define TOOFAST_WARNING "ERROR :Trying to reconnect too fast.\r\n"
+#define DLINE_WARNING "ERROR :You have been D-lined.\r\n"
+
+static void
+accept_connection(fde_t *pfd, void *data)
+{
+ static time_t last_oper_notice = 0;
+ struct irc_ssaddr addr;
+ int fd;
+ int pe;
+ struct Listener *listener = data;
+
+ memset(&addr, 0, sizeof(addr));
+
+ assert(listener != NULL);
+
+ /* 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.
+ */
+ while ((fd = comm_accept(listener, &addr)) != -1)
+ {
+ /*
+ * check for connection limit
+ */
+ if (number_fd > hard_fdlimit - 10)
+ {
+ ++ServerStats.is_ref;
+
+ /*
+ * slow down the whining to opers bit
+ */
+ if ((last_oper_notice + 20) <= CurrentTime)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL, "All connections in use. (%s)",
+ get_listener_name(listener));
+ last_oper_notice = CurrentTime;
+ }
+
+ if (!(listener->flags & LISTENER_SSL))
+ send(fd, "ERROR :All connections in use\r\n", 32, 0);
+
+ close(fd);
+ break; /* jump out and re-register a new io request */
+ }
+
+ /*
+ * Do an initial check we aren't connecting too fast or with too many
+ * from this IP...
+ */
+ if ((pe = conf_connect_allowed(&addr, addr.ss.ss_family)) != 0)
+ {
+ ++ServerStats.is_ref;
+
+ if (!(listener->flags & LISTENER_SSL))
+ switch (pe)
+ {
+ case BANNED_CLIENT:
+ send(fd, DLINE_WARNING, sizeof(DLINE_WARNING)-1, 0);
+ break;
+ case TOO_FAST:
+ send(fd, TOOFAST_WARNING, sizeof(TOOFAST_WARNING)-1, 0);
+ break;
+ }
+
+ close(fd);
+ continue; /* drop the one and keep on clearing the queue */
+ }
+
+ ++ServerStats.is_ac;
+ add_connection(listener, &addr, fd);
+ }
+
+ /* Re-register a new IO request for the next accept .. */
+ comm_setselect(&listener->fd, COMM_SELECT_READ, accept_connection,
+ listener, 0);
+}
diff --git a/src/log.c b/src/log.c
new file mode 100644
index 0000000..e81257b
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,123 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * log.c: Logger functions.
+ *
+ * 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$
+ */
+
+#include "stdinc.h"
+
+#include "log.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "conf.h"
+#include "s_misc.h"
+
+
+static struct {
+ char path[PATH_MAX + 1];
+ size_t size;
+ FILE *file;
+} log_type_table[LOG_TYPE_LAST];
+
+
+int
+log_add_file(enum log_type type, size_t size, const char *path)
+{
+ if (log_type_table[type].file)
+ fclose(log_type_table[type].file);
+
+ strlcpy(log_type_table[type].path, path, sizeof(log_type_table[type].path));
+ log_type_table[type].size = size;
+
+ return (log_type_table[type].file = fopen(path, "a")) != NULL;
+}
+
+void
+log_close_all(void)
+{
+ unsigned int type = 0;
+
+ while (++type < LOG_TYPE_LAST)
+ {
+ if (log_type_table[type].file == NULL)
+ continue;
+
+ fclose(log_type_table[type].file);
+ log_type_table[type].file = NULL;
+ }
+}
+
+static int
+log_exceed_size(unsigned int type)
+{
+ struct stat sb;
+
+ if (!log_type_table[type].size)
+ return 0;
+
+ if (stat(log_type_table[type].path, &sb) < 0)
+ return -1;
+
+ return (size_t)sb.st_size > log_type_table[type].size;
+}
+
+static void
+log_write(enum log_type type, const char *message)
+{
+ char buf[IRCD_BUFSIZE];
+
+ strftime(buf, sizeof(buf), "[%FT%H:%M:%S%z]", localtime(&CurrentTime));
+
+ fprintf(log_type_table[type].file, "%s %s\n", buf, message);
+ fflush(log_type_table[type].file);
+}
+
+void
+ilog(enum log_type type, const char *fmt, ...)
+{
+ char buf[LOG_BUFSIZE];
+ va_list args;
+
+ if (!log_type_table[type].file || !ConfigLoggingEntry.use_logging)
+ return;
+
+ va_start(args, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+
+ log_write(type, buf);
+
+ if (log_exceed_size(type) <= 0)
+ return;
+
+ snprintf(buf, sizeof(buf), "Rotating logfile %s",
+ log_type_table[type].path);
+ log_write(type, buf);
+
+ fclose(log_type_table[type].file);
+ log_type_table[type].file = NULL;
+
+ snprintf(buf, sizeof(buf), "%s.old", log_type_table[type].path);
+ unlink(buf);
+ rename(log_type_table[type].path, buf);
+
+ log_add_file(type, log_type_table[type].size, log_type_table[type].path);
+}
diff --git a/src/match.c b/src/match.c
new file mode 100644
index 0000000..4c4513e
--- /dev/null
+++ b/src/match.c
@@ -0,0 +1,616 @@
+/************************************************************************
+ * 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$
+ *
+ */
+
+#include "stdinc.h"
+#include "irc_string.h"
+#include "client.h"
+#include "ircd.h"
+
+/* Fix "statement not reached" warnings on Sun WorkShop C */
+#ifdef __SUNPRO_C
+# pragma error_messages(off, E_STATEMENT_NOT_REACHED)
+#endif
+
+/* match()
+ *
+ * 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)
+ */
+int
+match(const char *mask, const char *name)
+{
+ const unsigned char *m = (const unsigned char *)mask;
+ const unsigned char *n = (const unsigned char *)name;
+ const unsigned char *ma = NULL;
+ const unsigned char *na = (const unsigned char *)name;
+
+ assert(mask != NULL);
+ assert(name != NULL);
+
+ while (1)
+ {
+ if (*m == '*')
+ {
+ while (*m == '*')
+ m++;
+ ma = m;
+ na = n;
+ }
+
+ if (!*m)
+ {
+ if (!*n)
+ return 1;
+ if (!ma)
+ return 0;
+ for (m--; (m > (const unsigned char *)mask) && (*m == '?'); m--)
+ ;
+ if (*m == '*')
+ return 1;
+ m = ma;
+ n = ++na;
+ }
+ else if (!*n)
+ {
+ while (*m == '*')
+ m++;
+ return *m == 0;
+ }
+
+ if (ToLower(*m) != ToLower(*n) && *m != '?' && (*m != '#' || !IsDigit(*n)))
+ {
+ if (!ma)
+ return 0;
+ m = ma;
+ n = ++na;
+ }
+ else
+ m++, n++;
+ }
+
+ return 0;
+}
+
+/* match_esc()
+ *
+ * The match() function with support for escaping characters such
+ * as '*' and '?'
+ */
+int
+match_esc(const char *mask, const char *name)
+{
+ const unsigned char *m = (const unsigned char *)mask;
+ const unsigned char *n = (const unsigned char *)name;
+ const unsigned char *ma = NULL;
+ const unsigned char *na = (const unsigned char *)name;
+
+ assert(mask != NULL);
+ assert(name != NULL);
+
+ while (1)
+ {
+ if (*m == '*')
+ {
+ while (*m == '*')
+ m++;
+ ma = m;
+ na = n;
+ }
+
+ if (!*m)
+ {
+ if (!*n)
+ return 1;
+ if (!ma)
+ return 0;
+ for (m--; (m > (const unsigned char *)mask) && (*m == '?'); m--)
+ ;
+ if (*m == '*')
+ return 1;
+ m = ma;
+ n = ++na;
+ }
+ else if (!*n)
+ {
+ while (*m == '*')
+ m++;
+ return *m == 0;
+ }
+
+ if (*m != '?' && (*m != '#' || IsDigit(*n)))
+ {
+ if (*m == '\\')
+ if (!*++m)
+ return 0;
+ if (ToLower(*m) != ToLower(*n))
+ {
+ if (!ma)
+ return 0;
+ m = ma;
+ n = ++na;
+ }
+ else
+ m++, n++;
+ }
+ else
+ m++, n++;
+ }
+
+ return 0;
+}
+
+/* match_chan()
+ *
+ * The match_esc() function doing channel prefix auto-escape,
+ * ie. mask: #blah*blah is seen like \#blah*blah
+ */
+int
+match_chan(const char *mask, const char *name)
+{
+ if (*mask == '#')
+ {
+ if (*name != '#')
+ return 0;
+ ++name, ++mask;
+ }
+
+ return match_esc(mask, name);
+}
+
+/* collapse()
+ *
+ * collapses a string containing multiple *'s.
+ */
+char *
+collapse(char *pattern)
+{
+ char *p = pattern, *po = pattern;
+ char c;
+
+ if (p == NULL)
+ return NULL;
+
+ while ((c = *p++))
+ {
+ if (c != '*')
+ *po++ = c;
+ else if (*p != '*')
+ *po++ = '*';
+ }
+
+ *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;
+
+ if (p == NULL)
+ return NULL;
+
+ while ((c = *p++))
+ {
+ if (c != '*')
+ {
+ *po++ = c;
+ if (c == '\\' && *p)
+ *po++ = *p++;
+ }
+ else if (*p != '*')
+ *po++ = '*';
+ }
+
+ *po = 0;
+
+ return pattern;
+}
+
+/*
+ * irccmp - case insensitive comparison of two 0 terminated strings.
+ *
+ * returns 0, if s1 equal to s2
+ * 1, if not
+ */
+int
+irccmp(const char *s1, const char *s2)
+{
+ const unsigned char *str1 = (const unsigned char *)s1;
+ const unsigned char *str2 = (const unsigned char *)s2;
+
+ assert(s1 != NULL);
+ assert(s2 != NULL);
+
+ for (; ToUpper(*str1) == ToUpper(*str2); ++str1, ++str2)
+ if (*str1 == '\0')
+ return 0;
+
+ return 1;
+}
+
+int
+ircncmp(const char *s1, const char *s2, size_t n)
+{
+ const unsigned char *str1 = (const unsigned char *)s1;
+ const unsigned char *str2 = (const unsigned char *)s2;
+
+ assert(s1 != NULL);
+ assert(s2 != NULL);
+ assert(n > 0);
+
+ if (n == 0)
+ return 0;
+
+ for (; ToUpper(*str1) == ToUpper(*str2); ++str1, ++str2)
+ if (--n == 0 || *str1 == '\0')
+ return 0;
+
+ return 1;
+}
+
+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|VCHAN_C|NONEOS_C,
+/* 2 */ CNTRL_C|CHAN_C|NONEOS_C,
+/* 3 */ CNTRL_C|CHAN_C|NONEOS_C,
+/* 4 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* 5 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* 6 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* 7 BEL */ CNTRL_C|NONEOS_C,
+/* 8 \b */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* 9 \t */ CNTRL_C|SPACE_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* 10 \n */ CNTRL_C|SPACE_C|CHAN_C|VCHAN_C|NONEOS_C|EOL_C,
+/* 11 \v */ CNTRL_C|SPACE_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* 12 \f */ CNTRL_C|SPACE_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* 13 \r */ CNTRL_C|SPACE_C|CHAN_C|VCHAN_C|NONEOS_C|EOL_C,
+/* 14 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* 15 */ CNTRL_C|CHAN_C|NONEOS_C,
+/* 16 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* 17 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* 18 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* 19 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* 20 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* 21 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* 22 */ CNTRL_C|CHAN_C|NONEOS_C,
+/* 23 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* 24 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* 25 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* 26 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* 27 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* 28 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* 29 */ CNTRL_C|CHAN_C|NONEOS_C,
+/* 30 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* 31 */ CNTRL_C|CHAN_C|NONEOS_C,
+/* SP */ PRINT_C|SPACE_C,
+/* ! */ PRINT_C|KWILD_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* " */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* # */ PRINT_C|KWILD_C|MWILD_C|CHANPFX_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* $ */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C,
+/* % */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* & */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* ' */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* ( */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* ) */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* * */ PRINT_C|KWILD_C|MWILD_C|CHAN_C|VCHAN_C|NONEOS_C|SERV_C,
+/* + */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* , */ PRINT_C|NONEOS_C,
+/* - */ PRINT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* . */ PRINT_C|KWILD_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C|SERV_C,
+/* / */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* 0 */ PRINT_C|DIGIT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* 1 */ PRINT_C|DIGIT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* 2 */ PRINT_C|DIGIT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* 3 */ PRINT_C|DIGIT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* 4 */ PRINT_C|DIGIT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* 5 */ PRINT_C|DIGIT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* 6 */ PRINT_C|DIGIT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* 7 */ PRINT_C|DIGIT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* 8 */ PRINT_C|DIGIT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* 9 */ PRINT_C|DIGIT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* : */ PRINT_C|KWILD_C|CHAN_C|VCHAN_C|NONEOS_C|HOST_C,
+/* ; */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* < */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* = */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* > */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* ? */ PRINT_C|KWILD_C|MWILD_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* @ */ PRINT_C|KWILD_C|CHAN_C|VCHAN_C|NONEOS_C,
+/* A */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* B */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* C */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* D */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* E */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* F */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* G */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* H */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* I */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* J */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* K */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* L */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* M */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* N */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* O */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* P */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* Q */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* R */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* S */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* T */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* U */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* V */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* W */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* X */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* Y */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* Z */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* [ */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C,
+/* \ */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C,
+/* ] */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C,
+/* ^ */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C,
+/* _ */ PRINT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C,
+/* ` */ PRINT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C,
+/* a */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* b */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* c */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* d */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* e */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* f */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* g */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* h */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* i */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* j */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* k */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* l */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* m */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* n */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* o */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* p */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* q */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* r */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* s */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* t */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* u */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* v */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* w */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* x */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* y */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* z */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C,
+/* { */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C,
+/* | */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C,
+/* } */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C,
+/* ~ */ PRINT_C|ALPHA_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C,
+/* del */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x80 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x81 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x82 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x83 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x84 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x85 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x86 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x87 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x88 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x89 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x8A */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x8B */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x8C */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x8D */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x8E */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x8F */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x90 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x91 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x92 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x93 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x94 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x95 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x96 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x97 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x98 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x99 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x9A */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x9B */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x9C */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x9D */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x9E */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0x9F */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xA0 */ CHAN_C|NONEOS_C,
+/* 0xA1 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xA2 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xA3 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xA4 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xA5 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xA6 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xA7 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xA8 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xA9 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xAA */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xAB */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xAC */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xAD */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xAE */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xAF */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xB0 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xB1 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xB2 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xB3 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xB4 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xB5 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xB6 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xB7 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xB8 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xB9 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xBA */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xBB */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xBC */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xBD */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xBE */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xBF */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xC0 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xC1 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xC2 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xC3 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xC4 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xC5 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xC6 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xC7 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xC8 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xC9 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xCA */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xCB */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xCC */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xCD */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xCE */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xCF */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xD0 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xD1 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xD2 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xD3 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xD4 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xD5 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xD6 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xD7 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xD8 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xD9 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xDA */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xDB */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xDC */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xDD */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xDE */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xDF */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xE0 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xE1 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xE2 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xE3 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xE4 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xE5 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xE6 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xE7 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xE8 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xE9 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xEA */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xEB */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xEC */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xED */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xEE */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xEF */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xF0 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xF1 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xF2 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xF3 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xF4 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xF5 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xF6 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xF7 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xF8 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xF9 */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xFA */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xFB */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xFC */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xFD */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xFE */ CHAN_C|VCHAN_C|NONEOS_C,
+/* 0xFF */ CHAN_C|VCHAN_C|NONEOS_C
+};
diff --git a/src/memory.c b/src/memory.c
new file mode 100644
index 0000000..037807a
--- /dev/null
+++ b/src/memory.c
@@ -0,0 +1,114 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * memory.c: Memory utilities.
+ *
+ * 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$
+ */
+
+
+#include "stdinc.h"
+#include "ircd_defs.h"
+#include "irc_string.h"
+#include "memory.h"
+#include "log.h"
+#include "restart.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;
+}
+
+void
+MyFree(void *x)
+{
+ if (x)
+ free(x);
+}
+
+void
+_DupString(char **x, const char *y)
+{
+ (*x) = malloc(strlen(y) + 1);
+ strcpy((*x), y);
+}
+
+/* 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(void)
+{
+ static int was_here = 0;
+
+ if (was_here++)
+ abort();
+
+ ilog(LOG_TYPE_IRCD, "Out of memory: restarting server...");
+ restart("Out of Memory");
+}
+
+#ifndef NDEBUG
+/*
+ * frob some memory. debugging time.
+ * -- adrian
+ */
+void
+mem_frob(void *data, int len)
+{
+ /* correct for Intel only! little endian */
+ unsigned char b[4] = { 0xef, 0xbe, 0xad, 0xde };
+ int i;
+ char *cdata = data;
+
+ for (i = 0; i < len; i++)
+ {
+ *cdata = b[i % 4];
+ cdata++;
+ }
+}
+#endif
diff --git a/src/messages.tab b/src/messages.tab
new file mode 100644
index 0000000..12e22c6
--- /dev/null
+++ b/src/messages.tab
@@ -0,0 +1,1029 @@
+/************************************************************************
+ * 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$
+ */
+
+static struct NumericInfo replies[] = {
+/* 000 */ {NULL, NULL, NULL},
+/* 001 */ {"RPL_WELCOME", ":%s 001 %s :Welcome to the %s Internet Relay Chat Network %s", NULL},
+/* 002 */ {"RPL_YOURHOST", ":%s 002 %s :Your host is %s, running version %s", NULL},
+/* 003 */ {"RPL_CREATED", ":%s 003 %s :This server was created %s", NULL},
+#ifdef HALFOPS
+/* 004 */ {"RPL_MYINFO", ":%s 004 %s %s %s %s biklmnoprstveIhORS bkloveIh", NULL},
+#else
+/* 004 */ {"RPL_MYINFO", ":%s 004 %s %s %s %s biklmnoprstveIORS bkloveI", NULL},
+#endif
+/* 005 */ {"RPL_ISUPPORT", ":%s 005 %s %s :are supported by this server", NULL},
+/* 006 */ {NULL, NULL, NULL},
+/* 007 */ {NULL, NULL, NULL},
+/* 008 */ {NULL, NULL, NULL},
+/* 009 */ {NULL, NULL, NULL},
+/* 010 */ {"RPL_REDIR", ":%s 010 %s %s %d :Please use this Server/Port instead", NULL},
+/* 011 */ {NULL, NULL, NULL},
+/* 012 */ {NULL, NULL, NULL},
+/* 013 */ {NULL, NULL, NULL},
+/* 014 */ {NULL, NULL, NULL},
+/* 015 */ {"RPL_MAP", ":%s 015 %s :%s", NULL},
+/* 016 */ {NULL, NULL, NULL},
+/* 017 */ {"RPL_MAPEND", ":%s 017 %s :End of /MAP", NULL},
+/* 018 */ {NULL, NULL, NULL},
+/* 019 */ {NULL, NULL, NULL},
+/* 020 */ {NULL, NULL, NULL},
+/* 021 */ {NULL, NULL, NULL},
+/* 022 */ {NULL, NULL, NULL},
+/* 023 */ {NULL, NULL, NULL},
+/* 024 */ {NULL, NULL, NULL},
+/* 025 */ {NULL, NULL, NULL},
+/* 026 */ {NULL, NULL, NULL},
+/* 027 */ {NULL, NULL, NULL},
+/* 028 */ {NULL, NULL, NULL},
+/* 029 */ {NULL, NULL, NULL},
+/* 030 */ {NULL, NULL, NULL},
+/* 031 */ {NULL, NULL, NULL},
+/* 032 */ {NULL, NULL, NULL},
+/* 033 */ {NULL, NULL, NULL},
+/* 034 */ {NULL, NULL, NULL},
+/* 035 */ {NULL, NULL, NULL},
+/* 036 */ {NULL, NULL, NULL},
+/* 037 */ {NULL, NULL, NULL},
+/* 038 */ {NULL, NULL, NULL},
+/* 039 */ {NULL, NULL, NULL},
+/* 040 */ {NULL, NULL, NULL},
+/* 041 */ {NULL, NULL, NULL},
+/* 042 */ {"RPL_YOURID", ":%s 042 %s %s :your unique ID", NULL},
+/* 043 */ {NULL, NULL, NULL},
+/* 044 */ {NULL, NULL, NULL},
+/* 045 */ {NULL, NULL, NULL},
+/* 046 */ {NULL, NULL, NULL},
+/* 047 */ {NULL, NULL, NULL},
+/* 048 */ {NULL, NULL, NULL},
+/* 049 */ {NULL, NULL, NULL},
+/* 050 */ {NULL, NULL, NULL},
+/* 051 */ {NULL, NULL, NULL},
+/* 052 */ {NULL, NULL, NULL},
+/* 053 */ {NULL, NULL, NULL},
+/* 054 */ {NULL, NULL, NULL},
+/* 055 */ {NULL, NULL, NULL},
+/* 056 */ {NULL, NULL, NULL},
+/* 057 */ {NULL, NULL, NULL},
+/* 058 */ {NULL, NULL, NULL},
+/* 059 */ {NULL, NULL, NULL},
+/* 060 */ {NULL, NULL, NULL},
+/* 061 */ {NULL, NULL, NULL},
+/* 062 */ {NULL, NULL, NULL},
+/* 063 */ {NULL, NULL, NULL},
+/* 064 */ {NULL, NULL, NULL},
+/* 065 */ {NULL, NULL, NULL},
+/* 066 */ {NULL, NULL, NULL},
+/* 067 */ {NULL, NULL, NULL},
+/* 068 */ {NULL, NULL, NULL},
+/* 069 */ {NULL, NULL, NULL},
+/* 070 */ {NULL, NULL, NULL},
+/* 071 */ {NULL, NULL, NULL},
+/* 072 */ {NULL, NULL, NULL},
+/* 073 */ {NULL, NULL, NULL},
+/* 074 */ {NULL, NULL, NULL},
+/* 075 */ {NULL, NULL, NULL},
+/* 076 */ {NULL, NULL, NULL},
+/* 077 */ {NULL, NULL, NULL},
+/* 078 */ {NULL, NULL, NULL},
+/* 079 */ {NULL, NULL, NULL},
+/* 080 */ {NULL, NULL, NULL},
+/* 081 */ {NULL, NULL, NULL},
+/* 082 */ {NULL, NULL, NULL},
+/* 083 */ {NULL, NULL, NULL},
+/* 084 */ {NULL, NULL, NULL},
+/* 085 */ {NULL, NULL, NULL},
+/* 086 */ {NULL, NULL, NULL},
+/* 087 */ {NULL, NULL, NULL},
+/* 088 */ {NULL, NULL, NULL},
+/* 089 */ {NULL, NULL, NULL},
+/* 090 */ {NULL, NULL, NULL},
+/* 091 */ {NULL, NULL, NULL},
+/* 092 */ {NULL, NULL, NULL},
+/* 093 */ {NULL, NULL, NULL},
+/* 094 */ {NULL, NULL, NULL},
+/* 095 */ {NULL, NULL, NULL},
+/* 096 */ {NULL, NULL, NULL},
+/* 097 */ {NULL, NULL, NULL},
+/* 098 */ {NULL, NULL, NULL},
+/* 099 */ {NULL, NULL, NULL},
+/* 100 */ {NULL, NULL, NULL},
+/* 101 */ {NULL, NULL, NULL},
+/* 102 */ {NULL, NULL, NULL},
+/* 103 */ {NULL, NULL, NULL},
+/* 104 */ {NULL, NULL, NULL},
+/* 105 */ {NULL, NULL, NULL},
+/* 106 */ {NULL, NULL, NULL},
+/* 107 */ {NULL, NULL, NULL},
+/* 108 */ {NULL, NULL, NULL},
+/* 109 */ {NULL, NULL, NULL},
+/* 110 */ {NULL, NULL, NULL},
+/* 111 */ {NULL, NULL, NULL},
+/* 112 */ {NULL, NULL, NULL},
+/* 113 */ {NULL, NULL, NULL},
+/* 114 */ {NULL, NULL, NULL},
+/* 115 */ {NULL, NULL, NULL},
+/* 116 */ {NULL, NULL, NULL},
+/* 117 */ {NULL, NULL, NULL},
+/* 118 */ {NULL, NULL, NULL},
+/* 119 */ {NULL, NULL, NULL},
+/* 120 */ {NULL, NULL, NULL},
+/* 121 */ {NULL, NULL, NULL},
+/* 122 */ {NULL, NULL, NULL},
+/* 123 */ {NULL, NULL, NULL},
+/* 124 */ {NULL, NULL, NULL},
+/* 125 */ {NULL, NULL, NULL},
+/* 126 */ {NULL, NULL, NULL},
+/* 127 */ {NULL, NULL, NULL},
+/* 128 */ {NULL, NULL, NULL},
+/* 129 */ {NULL, NULL, NULL},
+/* 130 */ {NULL, NULL, NULL},
+/* 131 */ {NULL, NULL, NULL},
+/* 132 */ {NULL, NULL, NULL},
+/* 133 */ {NULL, NULL, NULL},
+/* 134 */ {NULL, NULL, NULL},
+/* 135 */ {NULL, NULL, NULL},
+/* 136 */ {NULL, NULL, NULL},
+/* 137 */ {NULL, NULL, NULL},
+/* 138 */ {NULL, NULL, NULL},
+/* 139 */ {NULL, NULL, NULL},
+/* 140 */ {NULL, NULL, NULL},
+/* 141 */ {NULL, NULL, NULL},
+/* 142 */ {NULL, NULL, NULL},
+/* 143 */ {NULL, NULL, NULL},
+/* 144 */ {NULL, NULL, NULL},
+/* 145 */ {NULL, NULL, NULL},
+/* 146 */ {NULL, NULL, NULL},
+/* 147 */ {NULL, NULL, NULL},
+/* 148 */ {NULL, NULL, NULL},
+/* 149 */ {NULL, NULL, NULL},
+/* 150 */ {NULL, NULL, NULL},
+/* 151 */ {NULL, NULL, NULL},
+/* 152 */ {NULL, NULL, NULL},
+/* 153 */ {NULL, NULL, NULL},
+/* 154 */ {NULL, NULL, NULL},
+/* 155 */ {NULL, NULL, NULL},
+/* 156 */ {NULL, NULL, NULL},
+/* 157 */ {NULL, NULL, NULL},
+/* 158 */ {NULL, NULL, NULL},
+/* 159 */ {NULL, NULL, NULL},
+/* 160 */ {NULL, NULL, NULL},
+/* 161 */ {NULL, NULL, NULL},
+/* 162 */ {NULL, NULL, NULL},
+/* 163 */ {NULL, NULL, NULL},
+/* 164 */ {NULL, NULL, NULL},
+/* 165 */ {NULL, NULL, NULL},
+/* 166 */ {NULL, NULL, NULL},
+/* 167 */ {NULL, NULL, NULL},
+/* 168 */ {NULL, NULL, NULL},
+/* 169 */ {NULL, NULL, NULL},
+/* 170 */ {NULL, NULL, NULL},
+/* 171 */ {NULL, NULL, NULL},
+/* 172 */ {NULL, NULL, NULL},
+/* 173 */ {NULL, NULL, NULL},
+/* 174 */ {NULL, NULL, NULL},
+/* 175 */ {NULL, NULL, NULL},
+/* 176 */ {NULL, NULL, NULL},
+/* 177 */ {NULL, NULL, NULL},
+/* 178 */ {NULL, NULL, NULL},
+/* 179 */ {NULL, NULL, NULL},
+/* 180 */ {NULL, NULL, NULL},
+/* 181 */ {NULL, NULL, NULL},
+/* 182 */ {NULL, NULL, NULL},
+/* 183 */ {NULL, NULL, NULL},
+/* 184 */ {NULL, NULL, NULL},
+/* 185 */ {NULL, NULL, NULL},
+/* 186 */ {NULL, NULL, NULL},
+/* 187 */ {NULL, NULL, NULL},
+/* 188 */ {NULL, NULL, NULL},
+/* 189 */ {NULL, NULL, NULL},
+/* 190 */ {NULL, NULL, NULL},
+/* 191 */ {NULL, NULL, NULL},
+/* 192 */ {NULL, NULL, NULL},
+/* 193 */ {NULL, NULL, NULL},
+/* 194 */ {NULL, NULL, NULL},
+/* 195 */ {NULL, NULL, NULL},
+/* 196 */ {NULL, NULL, NULL},
+/* 197 */ {NULL, NULL, NULL},
+/* 198 */ {NULL, NULL, NULL},
+/* 199 */ {NULL, NULL, NULL},
+/* 200 */ {"RPL_TRACELINK", ":%s 200 %s Link %s %s %s", NULL},
+/* 201 */ {"RPL_TRACECONNECTING", ":%s 201 %s Try. %s %s", NULL},
+/* 202 */ {"RPL_TRACEHANDSHAKE", ":%s 202 %s H.S. %s %s", NULL},
+/* 203 */ {"RPL_TRACEUNKNOWN", ":%s 203 %s ???? %s %s (%s) %d", NULL},
+/* 204 */ {"RPL_TRACEOPERATOR", ":%s 204 %s Oper %s %s (%s) %lu %lu", NULL},
+/* 205 */ {"RPL_TRACEUSER", ":%s 205 %s User %s %s (%s) %lu %lu", NULL},
+/* 206 */ {"RPL_TRACESERVER", ":%s 206 %s Serv %s %dS %dC %s %s!%s@%s %lu", NULL},
+/* 207 */ {NULL, NULL, NULL},
+/* 208 */ {"RPL_TRACENEWTYPE", ":%s 208 %s <newtype> 0 %s", NULL},
+/* 209 */ {"RPL_TRACECLASS", ":%s 209 %s Class %s %d", NULL},
+/* 210 */ {NULL, NULL, NULL},
+/* 211 */ {"RPL_STATSLINKINFO", ":%s 211 %s %s %u %u %llu %u %llu :%u %u %s", NULL},
+/* 212 */ {"RPL_STATSCOMMANDS", ":%s 212 %s %s %u %llu :%u", NULL},
+/* 213 */ {"RPL_STATSCLINE", ":%s 213 %s %c %s %s %s %d %s", NULL},
+/* 214 */ {"RPL_STATSNLINE", ":%s 214 %s %c %s * %s %d %s", NULL},
+/* 215 */ {"RPL_STATSILINE", ":%s 215 %s %c %s * %s@%s %d %s", NULL},
+/* 216 */ {"RPL_STATSKLINE", ":%s 216 %s %s %s * %s :%s | %s", NULL},
+/* 217 */ {"RPL_STATSQLINE", ":%s 217 %s %c %s :%s", NULL},
+/* 218 */ {"RPL_STATSYLINE", ":%s 218 %s %c %s %d %d %d %lu %lu %d %d/%d %d/%d %s", NULL},
+/* 219 */ {"RPL_ENDOFSTATS", ":%s 219 %s %c :End of /STATS report", NULL},
+/* 220 */ {"RPL_STATSPLINE", ":%s 220 %s %c %d %s %d %s :%s", NULL},
+/* 221 */ {"RPL_UMODEIS", ":%s 221 %s %s", NULL},
+/* 222 */ {NULL, NULL, NULL},
+/* 223 */ {NULL, NULL, NULL},
+/* 224 */ {NULL, NULL, NULL},
+/* 225 */ {"RPL_STATSDLINE", ":%s 225 %s %c %s :%s | %s", NULL},
+/* 226 */ {"RPL_STATSALINE", ":%s 226 %s %s", NULL},
+/* 227 */ {NULL, NULL, NULL},
+/* 228 */ {NULL, NULL, NULL},
+/* 229 */ {NULL, NULL, NULL},
+/* 230 */ {NULL, NULL, NULL},
+/* 231 */ {NULL, NULL, NULL},
+/* 232 */ {NULL, NULL, NULL},
+/* 233 */ {NULL, NULL, NULL},
+/* 234 */ {NULL, NULL, NULL},
+/* 235 */ {NULL, NULL, NULL},
+/* 236 */ {NULL, NULL, NULL},
+/* 237 */ {NULL, NULL, NULL},
+/* 238 */ {NULL, NULL, NULL},
+/* 239 */ {NULL, NULL, NULL},
+/* 240 */ {NULL, NULL, NULL},
+/* 241 */ {"RPL_STATSLLINE", ":%s 241 %s %c %s * %s %d %s", NULL},
+/* 242 */ {"RPL_STATSUPTIME", ":%s 242 %s :Server Up %d days, %d:%02d:%02d", NULL},
+/* 243 */ {"RPL_STATSOLINE", ":%s 243 %s %c %s@%s * %s %s %s", NULL},
+/* 244 */ {"RPL_STATSHLINE", ":%s 244 %s %c %s * %s %d %s", NULL},
+/* 245 */ {"RPL_STATSSLINE", NULL, NULL},
+/* 246 */ {"RPL_STATSSERVICE", ":%s 246 %s %c %s * %s %d %d", NULL},
+/* 247 */ {"RPL_STATSXLINE", ":%s 247 %s %s %d %s :%s", NULL},
+/* 248 */ {"RPL_STATSULINE", ":%s 248 %s U %s %s@%s %s", NULL},
+/* 249 */ {NULL, NULL, NULL},
+/* 250 */ {"RPL_STATSCONN", ":%s 250 %s :Highest connection count: %d (%d clients) (%llu connections received)", NULL},
+/* 251 */ {"RPL_LUSERCLIENT", ":%s 251 %s :There are %d users and %d invisible on %d servers", NULL},
+/* 252 */ {"RPL_LUSEROP", ":%s 252 %s %d :IRC Operators online", NULL},
+/* 253 */ {"RPL_LUSERUNKNOWN", ":%s 253 %s %d :unknown connection(s)", NULL},
+/* 254 */ {"RPL_LUSERCHANNELS", ":%s 254 %s %d :channels formed", NULL},
+/* 255 */ {"RPL_LUSERME", ":%s 255 %s :I have %d clients and %d servers", NULL},
+/* 256 */ {"RPL_ADMINME", ":%s 256 %s :Administrative info about %s", NULL},
+/* 257 */ {"RPL_ADMINLOC1", ":%s 257 %s :%s", NULL},
+/* 258 */ {"RPL_ADMINLOC2", ":%s 258 %s :%s", NULL},
+/* 259 */ {"RPL_ADMINEMAIL", ":%s 259 %s :%s", NULL},
+/* 260 */ {NULL, NULL, NULL},
+/* 261 */ {NULL, NULL, NULL},
+/* 262 */ {"RPL_ENDOFTRACE", ":%s 262 %s %s :End of TRACE", NULL},
+/* 263 */ {"RPL_LOAD2HI", ":%s 263 %s :Server load is temporarily too heavy. Please wait a while and try again.", NULL},
+/* 264 */ {NULL, NULL, NULL},
+/* 265 */ {"RPL_LOCALUSERS", ":%s 265 %s :Current local users: %d Max: %d", NULL},
+/* 266 */ {"RPL_GLOBALUSERS", ":%s 266 %s :Current global users: %d Max: %d", NULL},
+/* 267 */ {NULL, NULL, NULL},
+/* 268 */ {NULL, NULL, NULL},
+/* 269 */ {NULL, NULL, NULL},
+/* 270 */ {NULL, NULL, NULL},
+/* 271 */ {NULL, NULL, NULL},
+/* 272 */ {NULL, NULL, NULL},
+/* 273 */ {NULL, NULL, NULL},
+/* 274 */ {NULL, NULL, NULL},
+/* 275 */ {NULL, NULL, NULL},
+/* 276 */ {NULL, NULL, NULL},
+/* 277 */ {NULL, NULL, NULL},
+/* 278 */ {NULL, NULL, NULL},
+/* 279 */ {NULL, NULL, NULL},
+/* 280 */ {NULL, NULL, NULL},
+/* 281 */ {"RPL_ACCEPTLIST", ":%s 281 %s :%s", NULL},
+/* 282 */ {"RPL_ENDOFACCEPT", ":%s 282 %s :End of /ACCEPT list.", NULL},
+/* 283 */ {NULL, NULL, NULL},
+/* 284 */ {NULL, NULL, NULL},
+/* 285 */ {NULL, NULL, NULL},
+/* 286 */ {NULL, NULL, NULL},
+/* 287 */ {NULL, NULL, NULL},
+/* 288 */ {NULL, NULL, NULL},
+/* 289 */ {NULL, NULL, NULL},
+/* 290 */ {NULL, NULL, NULL},
+/* 291 */ {NULL, NULL, NULL},
+/* 292 */ {NULL, NULL, NULL},
+/* 293 */ {NULL, NULL, NULL},
+/* 294 */ {NULL, NULL, NULL},
+/* 295 */ {NULL, NULL, NULL},
+/* 296 */ {NULL, NULL, NULL},
+/* 297 */ {NULL, NULL, NULL},
+/* 298 */ {NULL, NULL, NULL},
+/* 299 */ {NULL, NULL, NULL},
+/* 300 */ {NULL, NULL, NULL},
+/* 301 */ {"RPL_AWAY", ":%s 301 %s %s :%s", NULL},
+/* 302 */ {"RPL_USERHOST", ":%s 302 %s :%s", NULL},
+/* 303 */ {"RPL_ISON", ":%s 303 %s :", NULL},
+/* 304 */ {"RPL_TEXT", NULL, NULL},
+/* 305 */ {"RPL_UNAWAY", ":%s 305 %s :You are no longer marked as being away", NULL},
+/* 306 */ {"RPL_NOWAWAY", ":%s 306 %s :You have been marked as being away", NULL},
+/* 307 */ {"RPL_WHOISREGNICK", ":%s 307 %s %s :has identified for this nick", NULL},
+/* 308 */ {"RPL_WHOISADMIN", ":%s 313 %s %s :is a Server Administrator", NULL},
+/* 309 */ {NULL, NULL, NULL},
+/* 310 */ {NULL, NULL, NULL},
+/* 311 */ {"RPL_WHOISUSER", ":%s 311 %s %s %s %s * :%s", NULL},
+/* 312 */ {"RPL_WHOISSERVER", ":%s 312 %s %s %s :%s", NULL},
+/* 313 */ {"RPL_WHOISOPERATOR", ":%s 313 %s %s :is an IRC Operator", NULL},
+/* 314 */ {"RPL_WHOWASUSER", ":%s 314 %s %s %s %s * :%s", NULL},
+/* 315 */ {"RPL_ENDOFWHO", ":%s 315 %s %s :End of /WHO list.", NULL},
+/* 316 */ {"RPL_WHOISCHANOP", NULL, NULL},
+/* 317 */ {"RPL_WHOISIDLE", ":%s 317 %s %s %d %d :seconds idle, signon time", NULL},
+/* 318 */ {"RPL_ENDOFWHOIS", ":%s 318 %s %s :End of /WHOIS list.", NULL},
+/* 319 */ {"RPL_WHOISCHANNELS", ":%s 319 %s %s :%s", NULL},
+/* 320 */ {NULL, NULL, NULL},
+/* 321 */ {"RPL_LISTSTART", ":%s 321 %s Channel :Users Name", NULL},
+/* 322 */ {"RPL_LIST", ":%s 322 %s %s %d :%s", NULL},
+/* 323 */ {"RPL_LISTEND", ":%s 323 %s :End of /LIST", NULL},
+/* 324 */ {"RPL_CHANNELMODEIS", ":%s 324 %s %s %s %s", NULL},
+/* 325 */ {NULL, NULL, NULL},
+/* 326 */ {NULL, NULL, NULL},
+/* 327 */ {NULL, NULL, NULL},
+/* 328 */ {NULL, NULL, NULL},
+/* 329 */ {"RPL_CREATIONTIME", ":%s 329 %s %s %lu", NULL},
+/* 330 */ {NULL, NULL, NULL},
+/* 331 */ {"RPL_NOTOPIC", ":%s 331 %s %s :No topic is set.", NULL},
+/* 332 */ {"RPL_TOPIC", ":%s 332 %s %s :%s", NULL},
+/* 333 */ {"RPL_TOPICWHOTIME", ":%s 333 %s %s %s %lu", NULL},
+/* 334 */ {NULL, NULL, NULL},
+/* 335 */ {NULL, NULL, NULL},
+/* 336 */ {NULL, NULL, NULL},
+/* 337 */ {NULL, NULL, NULL},
+/* 338 */ {"RPL_WHOISACTUALLY", ":%s 338 %s %s %s :actually using host", NULL},
+/* 339 */ {NULL, NULL, NULL},
+/* 340 */ {NULL, NULL, NULL},
+/* 341 */ {"RPL_INVITING", ":%s 341 %s %s %s", NULL},
+/* 342 */ {NULL, NULL, NULL},
+/* 343 */ {NULL, NULL, NULL},
+/* 344 */ {NULL, NULL, NULL},
+/* 345 */ {NULL, NULL, NULL},
+/* 346 */ {"RPL_INVEXLIST", ":%s 346 %s %s %s!%s@%s %s %lu", NULL},
+/* 347 */ {"RPL_ENDOFINVEXLIST", ":%s 347 %s %s :End of Channel Invite List", NULL},
+/* 348 */ {"RPL_EXCEPTLIST", ":%s 348 %s %s %s!%s@%s %s %lu", NULL},
+/* 349 */ {"RPL_ENDOFEXCEPTLIST", ":%s 349 %s %s :End of Channel Exception List", NULL},
+/* 350 */ {NULL, NULL, NULL},
+/* 351 */ {"RPL_VERSION", ":%s 351 %s %s(%s). %s :%s%s", NULL},
+/* 352 */ {"RPL_WHOREPLY", ":%s 352 %s %s %s %s %s %s %s :%d %s", NULL},
+/* 353 */ {"RPL_NAMREPLY", ":%s 353 %s %s %s :", NULL},
+/* 354 */ {NULL, NULL, NULL},
+/* 355 */ {NULL, NULL, NULL},
+/* 356 */ {NULL, NULL, NULL},
+/* 357 */ {NULL, NULL, NULL},
+/* 358 */ {NULL, NULL, NULL},
+/* 359 */ {NULL, NULL, NULL},
+/* 360 */ {NULL, NULL, NULL},
+/* 361 */ {NULL, NULL, NULL},
+/* 362 */ {"RPL_CLOSING", ":%s 362 %s %s :Closed. Status = %d", NULL},
+/* 363 */ {"RPL_CLOSEEND", ":%s 363 %s %d: Connections Closed", NULL},
+/* 364 */ {"RPL_LINKS", ":%s 364 %s %s %s :%d %s", NULL},
+/* 365 */ {"RPL_ENDOFLINKS", ":%s 365 %s %s :End of /LINKS list.", NULL},
+/* 366 */ {"RPL_ENDOFNAMES", ":%s 366 %s %s :End of /NAMES list.", NULL},
+/* 367 */ {"RPL_BANLIST", ":%s 367 %s %s %s!%s@%s %s %lu", NULL},
+/* 368 */ {"RPL_ENDOFBANLIST", ":%s 368 %s %s :End of Channel Ban List", NULL},
+/* 369 */ {"RPL_ENDOFWHOWAS", ":%s 369 %s %s :End of WHOWAS", NULL},
+/* 370 */ {NULL, NULL, NULL},
+/* 371 */ {"RPL_INFO", ":%s 371 %s :%s", NULL},
+/* 372 */ {"RPL_MOTD", ":%s 372 %s :- %s", NULL},
+/* 373 */ {"RPL_INFOSTART", ":%s 373 %s :Server INFO", NULL},
+/* 374 */ {"RPL_ENDOFINFO", ":%s 374 %s :End of /INFO list.", NULL},
+/* 375 */ {"RPL_MOTDSTART", ":%s 375 %s :- %s Message of the Day - ", NULL},
+/* 376 */ {"RPL_ENDOFMOTD", ":%s 376 %s :End of /MOTD command.", NULL},
+/* 377 */ {NULL, NULL, NULL},
+/* 378 */ {NULL, NULL, NULL},
+/* 379 */ {NULL, NULL, NULL},
+/* 380 */ {NULL, NULL, NULL},
+/* 381 */ {"RPL_YOUREOPER", ":%s 381 %s :You have entered... the Twilight Zone!", NULL},
+/* 382 */ {"RPL_REHASHING", ":%s 382 %s %s :Rehashing", NULL},
+/* 383 */ {NULL, NULL, NULL},
+/* 384 */ {NULL, NULL, NULL},
+/* 385 */ {NULL, NULL, NULL},
+/* 386 */ {NULL, ":%s 386 %s :%s", NULL},
+/* 387 */ {NULL, NULL, NULL},
+/* 388 */ {NULL, NULL, NULL},
+/* 389 */ {NULL, NULL, NULL},
+/* 390 */ {NULL, NULL, NULL},
+/* 391 */ {"RPL_TIME", ":%s 391 %s %s :%s", NULL},
+/* 392 */ {NULL, NULL, NULL},
+/* 393 */ {NULL, NULL, NULL},
+/* 394 */ {NULL, NULL, NULL},
+/* 395 */ {NULL, NULL, NULL},
+/* 396 */ {"RPL_HOSTHIDDEN", ":%s 396 %s %s :is now your hidden host", NULL},
+/* 397 */ {NULL, NULL, NULL},
+/* 398 */ {NULL, NULL, NULL},
+/* 399 */ {NULL, NULL, NULL},
+/* 400 */ {NULL, NULL, NULL},
+/* 401 */ {"ERR_NOSUCHNICK", ":%s 401 %s %s :No such nick/channel", NULL},
+/* 402 */ {"ERR_NOSUCHSERVER", ":%s 402 %s %s :No such server", NULL},
+/* 403 */ {"ERR_NOSUCHCHANNEL", ":%s 403 %s %s :No such channel", NULL},
+/* 404 */ {"ERR_CANNOTSENDTOCHAN", ":%s 404 %s %s :Cannot send to channel", NULL},
+/* 405 */ {"ERR_TOOMANYCHANNELS", ":%s 405 %s %s :You have joined too many channels", NULL},
+/* 406 */ {"ERR_WASNOSUCHNICK", ":%s 406 %s %s :There was no such nickname", NULL},
+/* 407 */ {"ERR_TOOMANYTARGETS", ":%s 407 %s %s :Too many recipients. Only %d processed", NULL},
+/* 408 */ {NULL, NULL, NULL},
+/* 409 */ {"ERR_NOORIGIN", ":%s 409 %s :No origin specified", NULL},
+/* 410 */ {"ERR_INVALIDCAPCMD", ":%s 410 %s %s :Invalid CAP subcommand", NULL},
+/* 411 */ {"ERR_NORECIPIENT", ":%s 411 %s :No recipient given (%s)", NULL},
+/* 412 */ {"ERR_NOTEXTTOSEND", ":%s 412 %s :No text to send", NULL},
+/* 413 */ {"ERR_NOTOPLEVEL", ":%s 413 %s %s :No toplevel domain specified", NULL},
+/* 414 */ {"ERR_WILDTOPLEVEL", ":%s 414 %s %s :Wildcard in toplevel Domain", NULL},
+/* 415 */ {NULL, NULL, NULL},
+/* 416 */ {NULL, NULL, NULL},
+/* 417 */ {NULL, NULL, NULL},
+/* 418 */ {NULL, NULL, NULL},
+/* 419 */ {NULL, NULL, NULL},
+/* 420 */ {NULL, NULL, NULL},
+/* 421 */ {"ERR_UNKNOWNCOMMAND", ":%s 421 %s %s :Unknown command", NULL},
+/* 422 */ {"ERR_NOMOTD", ":%s 422 %s :MOTD File is missing", NULL},
+/* 423 */ {"ERR_NOADMININFO", ":%s 423 %s %s :No administrative info available", NULL},
+/* 424 */ {NULL, NULL, NULL},
+/* 425 */ {NULL, NULL, NULL},
+/* 426 */ {NULL, NULL, NULL},
+/* 427 */ {NULL, NULL, NULL},
+/* 428 */ {NULL, NULL, NULL},
+/* 429 */ {NULL, NULL, NULL},
+/* 430 */ {NULL, NULL, NULL},
+/* 431 */ {"ERR_NONICKNAMEGIVEN", ":%s 431 %s :No nickname given", NULL},
+/* 432 */ {"ERR_ERRONEUSNICKNAME", ":%s 432 %s %s :Erroneous Nickname", NULL},
+/* 433 */ {"ERR_NICKNAMEINUSE", ":%s 433 %s %s :Nickname is already in use.", NULL},
+/* 434 */ {NULL, NULL, NULL},
+/* 435 */ {NULL, NULL, NULL},
+/* 436 */ {"ERR_NICKCOLLISION", ":%s 436 %s %s :Nickname collision KILL", NULL},
+/* 437 */ {"ERR_UNAVAILRESOURCE", ":%s 437 %s %s :Nick/channel is temporarily unavailable", NULL},
+/* 438 */ {"ERR_NICKTOOFAST", ":%s 438 %s %s %s :Nick change too fast. Please wait %d seconds.", NULL},
+/* 439 */ {NULL, NULL, NULL},
+/* 440 */ {"ERR_SERVICESDOWN", ":%s 440 %s %s :Services is currently down.", NULL},
+/* 441 */ {"ERR_USERNOTINCHANNEL", ":%s 441 %s %s %s :They aren't on that channel", NULL},
+/* 442 */ {"ERR_NOTONCHANNEL", ":%s 442 %s %s :You're not on that channel", NULL},
+/* 443 */ {"ERR_USERONCHANNEL", ":%s 443 %s %s %s :is already on channel", NULL},
+/* 444 */ {NULL, NULL, NULL},
+/* 445 */ {NULL, NULL, NULL},
+/* 446 */ {NULL, NULL, NULL},
+/* 447 */ {NULL, NULL, NULL},
+/* 448 */ {NULL, NULL, NULL},
+/* 449 */ {NULL, NULL, NULL},
+/* 450 */ {NULL, NULL, NULL},
+/* 451 */ {"ERR_NOTREGISTERED", ":%s 451 %s :You have not registered", NULL},
+/* 452 */ {NULL, NULL, NULL},
+/* 453 */ {NULL, NULL, NULL},
+/* 454 */ {NULL, NULL, NULL},
+/* 455 */ {NULL, NULL, NULL},
+/* 456 */ {"ERR_ACCEPTFULL", ":%s 456 %s :Accept list is full", NULL},
+/* 457 */ {"ERR_ACCEPTEXIST", ":%s 457 %s %s!%s@%s :is already on your accept list", NULL},
+/* 458 */ {"ERR_ACCEPTNOT", ":%s 458 %s %s!%s@%s :is not on your accept list", NULL},
+/* 459 */ {NULL, NULL, NULL},
+/* 460 */ {NULL, NULL, NULL},
+/* 461 */ {"ERR_NEEDMOREPARAMS", ":%s 461 %s %s :Not enough parameters", NULL},
+/* 462 */ {"ERR_ALREADYREGISTRED", ":%s 462 %s :You may not reregister", NULL},
+/* 463 */ {NULL, NULL, NULL},
+/* 464 */ {"ERR_PASSWDMISMATCH", ":%s 464 %s :Password Incorrect", NULL},
+/* 465 */ {"ERR_YOUREBANNEDCREEP", ":%s 465 %s :You are banned from this server- %s", NULL},
+/* 466 */ {NULL, NULL, NULL},
+/* 467 */ {NULL, NULL, NULL},
+/* 468 */ {"ERR_ONLYSERVERSCANCHANGE", ":%s 468 %s %s :Only servers can change that mode", NULL},
+/* 469 */ {NULL, NULL, NULL},
+/* 470 */ {"ERR_OPERONLYCHAN", ":%s 470 %s %s :Cannot join channel (+O)", NULL},
+/* 471 */ {"ERR_CHANNELISFULL", ":%s 471 %s %s :Cannot join channel (+l)", NULL},
+/* 472 */ {"ERR_UNKNOWNMODE", ":%s 472 %s %c :is unknown mode char to me", NULL},
+/* 473 */ {"ERR_INVITEONLYCHAN", ":%s 473 %s %s :Cannot join channel (+i)", NULL},
+/* 474 */ {"ERR_BANNEDFROMCHAN", ":%s 474 %s %s :Cannot join channel (+b)", NULL},
+/* 475 */ {"ERR_BADCHANNELKEY", ":%s 475 %s %s :Cannot join channel (+k)", NULL},
+/* 476 */ {NULL, NULL, NULL},
+/* 477 */ {"ERR_NEEDREGGEDNICK", ":%s 477 %s %s :You need to identify to a registered nick to join or speak in that "
+ "channel.", NULL},
+/* 478 */ {"ERR_BANLISTFULL", ":%s 478 %s %s %s :Channel ban list is full", NULL},
+/* 479 */ {"ERR_BADCHANNAME", ":%s 479 %s %s :Illegal channel name", NULL},
+/* 480 */ {"ERR_SSLONLYCHAN", ":%s 480 %s %s :Cannot join channel (+S)", NULL},
+/* 481 */ {"ERR_NOPRIVILEGES", ":%s 481 %s :Permission Denied - You're not an IRC operator", NULL},
+/* 482 */ {"ERR_CHANOPRIVSNEEDED", ":%s 482 %s %s :You're not channel operator", NULL},
+/* 483 */ {"ERR_CANTKILLSERVER", ":%s 483 %s :You can't kill a server!", NULL},
+/* 484 */ {"ERR_RESTRICTED", ":%s 484 %s :You are restricted", NULL},
+/* 485 */ {NULL, NULL, NULL},
+/* 486 */ {"ERR_NONONREG", ":%s 486 %s %s :You must identify to a registered "
+ "nick to private message that person", NULL},
+/* 487 */ {NULL, NULL, NULL},
+/* 488 */ {NULL, NULL, NULL},
+/* 489 */ {NULL, NULL, NULL},
+/* 490 */ {NULL, NULL, NULL},
+/* 491 */ {"ERR_NOOPERHOST", ":%s 491 %s :Only few of mere mortals may try to enter the twilight zone", NULL},
+/* 492 */ {NULL, NULL, NULL},
+/* 493 */ {NULL, NULL, NULL},
+/* 494 */ {NULL, NULL, NULL},
+/* 495 */ {NULL, NULL, NULL},
+/* 496 */ {NULL, NULL, NULL},
+/* 497 */ {NULL, NULL, NULL},
+/* 498 */ {NULL, NULL, NULL},
+/* 499 */ {NULL, NULL, NULL},
+/* 500 */ {NULL, NULL, NULL},
+/* 501 */ {"ERR_UMODEUNKNOWNFLAG", ":%s 501 %s :Unknown MODE flag", NULL},
+/* 502 */ {"ERR_USERSDONTMATCH", ":%s 502 %s :Can't change mode for other users", NULL},
+/* 503 */ {"ERR_GHOSTEDCLIENT", ":%s 503 %s :Message could not be delivered to %s", NULL},
+/* 504 */ {"ERR_USERNOTONSERV", ":%s 504 %s %s :User is not on this server", NULL},
+/* 505 */ {NULL, NULL, NULL},
+/* 506 */ {NULL, NULL, NULL},
+/* 507 */ {NULL, NULL, NULL},
+/* 508 */ {NULL, NULL, NULL},
+/* 509 */ {NULL, NULL, NULL},
+/* 510 */ {NULL, NULL, NULL},
+/* 511 */ {NULL, NULL, NULL},
+/* 512 */ {"ERR_TOOMANYWATCH", ":%s 512 %s %s :Maximum size for WATCH-list is %d entries", NULL},
+/* 513 */ {"ERR_WRONGPONG", ":%s 513 %s :To connect type /QUOTE PONG %lu", NULL},
+/* 514 */ {NULL, NULL, NULL},
+/* 515 */ {NULL, NULL, NULL},
+/* 516 */ {NULL, NULL, NULL},
+/* 517 */ {NULL, NULL, NULL},
+/* 518 */ {NULL, NULL, NULL},
+/* 519 */ {NULL, NULL, NULL},
+/* 520 */ {NULL, NULL, NULL},
+/* 521 */ {"ERR_LISTSYNTAX", ":%s 521 %s :Bad list syntax, type /QUOTE HELP LIST", NULL},
+/* 522 */ {NULL, NULL, NULL},
+/* 523 */ {NULL, NULL, NULL},
+/* 524 */ {"ERR_HELPNOTFOUND", ":%s 524 %s %s :Help not found", NULL},
+/* 525 */ {NULL, NULL, NULL},
+/* 526 */ {NULL, NULL, NULL},
+/* 527 */ {NULL, NULL, NULL},
+/* 528 */ {NULL, NULL, NULL},
+/* 529 */ {NULL, NULL, NULL},
+/* 530 */ {NULL, NULL, NULL},
+/* 531 */ {NULL, NULL, NULL},
+/* 532 */ {NULL, NULL, NULL},
+/* 533 */ {NULL, NULL, NULL},
+/* 534 */ {NULL, NULL, NULL},
+/* 535 */ {NULL, NULL, NULL},
+/* 536 */ {NULL, NULL, NULL},
+/* 537 */ {NULL, NULL, NULL},
+/* 538 */ {NULL, NULL, NULL},
+/* 539 */ {NULL, NULL, NULL},
+/* 540 */ {NULL, NULL, NULL},
+/* 541 */ {NULL, NULL, NULL},
+/* 542 */ {NULL, NULL, NULL},
+/* 543 */ {NULL, NULL, NULL},
+/* 544 */ {NULL, NULL, NULL},
+/* 545 */ {NULL, NULL, NULL},
+/* 546 */ {NULL, NULL, NULL},
+/* 547 */ {NULL, NULL, NULL},
+/* 548 */ {NULL, NULL, NULL},
+/* 549 */ {NULL, NULL, NULL},
+/* 550 */ {NULL, NULL, NULL},
+/* 551 */ {NULL, NULL, NULL},
+/* 552 */ {NULL, NULL, NULL},
+/* 553 */ {NULL, NULL, NULL},
+/* 554 */ {NULL, NULL, NULL},
+/* 555 */ {NULL, NULL, NULL},
+/* 556 */ {NULL, NULL, NULL},
+/* 557 */ {NULL, NULL, NULL},
+/* 558 */ {NULL, NULL, NULL},
+/* 559 */ {NULL, NULL, NULL},
+/* 560 */ {NULL, NULL, NULL},
+/* 561 */ {NULL, NULL, NULL},
+/* 562 */ {NULL, NULL, NULL},
+/* 563 */ {NULL, NULL, NULL},
+/* 564 */ {NULL, NULL, NULL},
+/* 565 */ {NULL, NULL, NULL},
+/* 566 */ {NULL, NULL, NULL},
+/* 567 */ {NULL, NULL, NULL},
+/* 568 */ {NULL, NULL, NULL},
+/* 569 */ {NULL, NULL, NULL},
+/* 570 */ {NULL, NULL, NULL},
+/* 571 */ {NULL, NULL, NULL},
+/* 572 */ {NULL, NULL, NULL},
+/* 573 */ {NULL, NULL, NULL},
+/* 574 */ {NULL, NULL, NULL},
+/* 575 */ {NULL, NULL, NULL},
+/* 576 */ {NULL, NULL, NULL},
+/* 577 */ {NULL, NULL, NULL},
+/* 578 */ {NULL, NULL, NULL},
+/* 579 */ {NULL, NULL, NULL},
+/* 580 */ {NULL, NULL, NULL},
+/* 581 */ {NULL, NULL, NULL},
+/* 582 */ {NULL, NULL, NULL},
+/* 583 */ {NULL, NULL, NULL},
+/* 584 */ {NULL, NULL, NULL},
+/* 585 */ {NULL, NULL, NULL},
+/* 586 */ {NULL, NULL, NULL},
+/* 587 */ {NULL, NULL, NULL},
+/* 588 */ {NULL, NULL, NULL},
+/* 589 */ {NULL, NULL, NULL},
+/* 590 */ {NULL, NULL, NULL},
+/* 591 */ {NULL, NULL, NULL},
+/* 592 */ {NULL, NULL, NULL},
+/* 593 */ {NULL, NULL, NULL},
+/* 594 */ {NULL, NULL, NULL},
+/* 595 */ {NULL, NULL, NULL},
+/* 596 */ {NULL, NULL, NULL},
+/* 597 */ {NULL, NULL, NULL},
+/* 598 */ {NULL, NULL, NULL},
+/* 599 */ {NULL, NULL, NULL},
+/* 600 */ {"RPL_LOGON", ":%s 600 %s %s %s %s %d :logged online", NULL},
+/* 601 */ {"RPL_LOGOFF", ":%s 601 %s %s %s %s %d :logged offline", NULL},
+/* 602 */ {"RPL_WATCHOFF", ":%s 602 %s %s %s %s %d :stopped watching", NULL},
+/* 603 */ {"RPL_WATCHSTAT", ":%s 603 %s :You have %u and are on %u WATCH entries", NULL},
+/* 604 */ {"RPL_NOWON", ":%s 604 %s %s %s %s %d :is online", NULL},
+/* 605 */ {"RPL_NOWOFF", ":%s 605 %s %s %s %s %d :is offline", NULL},
+/* 606 */ {"RPL_WATCHLIST", ":%s 606 %s :%s", NULL},
+/* 607 */ {"RPL_ENDOFWATCHLIST", ":%s 607 %s :End of WATCH %c", NULL},
+/* 608 */ {NULL, NULL, NULL},
+/* 609 */ {NULL, NULL, NULL},
+/* 610 */ {NULL, NULL, NULL},
+/* 611 */ {NULL, NULL, NULL},
+/* 612 */ {NULL, NULL, NULL},
+/* 613 */ {NULL, NULL, NULL},
+/* 614 */ {NULL, NULL, NULL},
+/* 615 */ {NULL, NULL, NULL},
+/* 616 */ {NULL, NULL, NULL},
+/* 617 */ {NULL, NULL, NULL},
+/* 618 */ {NULL, NULL, NULL},
+/* 619 */ {NULL, NULL, NULL},
+/* 620 */ {NULL, NULL, NULL},
+/* 621 */ {NULL, NULL, NULL},
+/* 622 */ {NULL, NULL, NULL},
+/* 623 */ {NULL, NULL, NULL},
+/* 624 */ {NULL, NULL, NULL},
+/* 625 */ {NULL, NULL, NULL},
+/* 626 */ {NULL, NULL, NULL},
+/* 627 */ {NULL, NULL, NULL},
+/* 628 */ {NULL, NULL, NULL},
+/* 629 */ {NULL, NULL, NULL},
+/* 630 */ {NULL, NULL, NULL},
+/* 631 */ {NULL, NULL, NULL},
+/* 632 */ {NULL, NULL, NULL},
+/* 633 */ {NULL, NULL, NULL},
+/* 634 */ {NULL, NULL, NULL},
+/* 635 */ {NULL, NULL, NULL},
+/* 636 */ {NULL, NULL, NULL},
+/* 637 */ {NULL, NULL, NULL},
+/* 638 */ {NULL, NULL, NULL},
+/* 639 */ {NULL, NULL, NULL},
+/* 640 */ {NULL, NULL, NULL},
+/* 641 */ {NULL, NULL, NULL},
+/* 642 */ {NULL, NULL, NULL},
+/* 643 */ {NULL, NULL, NULL},
+/* 644 */ {NULL, NULL, NULL},
+/* 645 */ {NULL, NULL, NULL},
+/* 646 */ {NULL, NULL, NULL},
+/* 647 */ {NULL, NULL, NULL},
+/* 648 */ {NULL, NULL, NULL},
+/* 649 */ {NULL, NULL, NULL},
+/* 650 */ {NULL, NULL, NULL},
+/* 651 */ {NULL, NULL, NULL},
+/* 652 */ {NULL, NULL, NULL},
+/* 653 */ {NULL, NULL, NULL},
+/* 654 */ {NULL, NULL, NULL},
+/* 655 */ {NULL, NULL, NULL},
+/* 656 */ {NULL, NULL, NULL},
+/* 657 */ {NULL, NULL, NULL},
+/* 658 */ {NULL, NULL, NULL},
+/* 659 */ {NULL, NULL, NULL},
+/* 660 */ {NULL, NULL, NULL},
+/* 661 */ {NULL, NULL, NULL},
+/* 662 */ {NULL, NULL, NULL},
+/* 663 */ {NULL, NULL, NULL},
+/* 664 */ {NULL, NULL, NULL},
+/* 665 */ {NULL, NULL, NULL},
+/* 666 */ {NULL, NULL, NULL},
+/* 667 */ {NULL, NULL, NULL},
+/* 668 */ {NULL, NULL, NULL},
+/* 669 */ {NULL, NULL, NULL},
+/* 670 */ {NULL, NULL, NULL},
+/* 671 */ {"RPL_WHOISSECURE", ":%s 671 %s %s :is connected via SSL (secure link)", NULL},
+/* 672 */ {NULL, NULL, NULL},
+/* 673 */ {NULL, NULL, NULL},
+/* 674 */ {NULL, NULL, NULL},
+/* 675 */ {NULL, NULL, NULL},
+/* 676 */ {NULL, NULL, NULL},
+/* 677 */ {NULL, NULL, NULL},
+/* 678 */ {NULL, NULL, NULL},
+/* 679 */ {NULL, NULL, NULL},
+/* 680 */ {NULL, NULL, NULL},
+/* 681 */ {NULL, NULL, NULL},
+/* 682 */ {NULL, NULL, NULL},
+/* 683 */ {NULL, NULL, NULL},
+/* 684 */ {NULL, NULL, NULL},
+/* 685 */ {NULL, NULL, NULL},
+/* 686 */ {NULL, NULL, NULL},
+/* 687 */ {NULL, NULL, NULL},
+/* 688 */ {NULL, NULL, NULL},
+/* 689 */ {NULL, NULL, NULL},
+/* 690 */ {NULL, NULL, NULL},
+/* 691 */ {NULL, NULL, NULL},
+/* 692 */ {NULL, NULL, NULL},
+/* 693 */ {NULL, NULL, NULL},
+/* 694 */ {NULL, NULL, NULL},
+/* 695 */ {NULL, NULL, NULL},
+/* 696 */ {NULL, NULL, NULL},
+/* 697 */ {NULL, NULL, NULL},
+/* 698 */ {NULL, NULL, NULL},
+/* 699 */ {NULL, NULL, NULL},
+/* 700 */ {NULL, NULL, NULL},
+/* 701 */ {NULL, NULL, NULL},
+/* 702 */ {"RPL_MODLIST", ":%s 702 %s %s %p %s %s", NULL},
+/* 703 */ {"RPL_ENDOFMODLIST", ":%s 703 %s :End of /MODLIST.", NULL},
+/* 704 */ {"RPL_HELPSTART", ":%s 704 %s %s :%s", NULL},
+/* 705 */ {"RPL_HELPTXT", ":%s 705 %s %s :%s", NULL},
+/* 706 */ {"RPL_ENDOFHELP", ":%s 706 %s %s :End of /HELP.", NULL},
+/* 707 */ {NULL, NULL, NULL},
+/* 708 */ {"RPL_ETRACE_FULL", ":%s 708 %s %s %s %s %s %s %s %s %s :%s", NULL},
+/* 709 */ {"RPL_ETRACE", ":%s 709 %s %s %s %s %s %s %s :%s", NULL},
+/* 710 */ {"RPL_KNOCK", ":%s 710 %s %s %s!%s@%s :has asked for an invite.", NULL},
+/* 711 */ {"RPL_KNOCKDLVR", ":%s 711 %s %s :Your KNOCK has been delivered.", NULL},
+/* 712 */ {"ERR_TOOMANYKNOCK", ":%s 712 %s %s :Too many KNOCKs (%s).", NULL},
+/* 713 */ {"ERR_CHANOPEN", ":%s 713 %s %s :Channel is open.", NULL},
+/* 714 */ {"ERR_KNOCKONCHAN", ":%s 714 %s %s :You are already on that channel.", NULL},
+/* 715 */ {NULL, NULL, NULL},
+/* 716 */ {"RPL_TARGUMODEG", ":%s 716 %s %s :is in +g mode (server side ignore)", NULL},
+/* 717 */ {"RPL_TARGNOTIFY", ":%s 717 %s %s :has been informed that you messaged them.", NULL},
+/* 718 */ {"RPL_UMODEGMSG", ":%s 718 %s %s :is messaging you, and you are umode +g.", NULL},
+/* 719 */ {NULL, NULL, NULL},
+/* 720 */ {NULL, NULL, NULL},
+/* 721 */ {NULL, NULL, NULL},
+/* 722 */ {NULL, NULL, NULL},
+/* 723 */ {"ERR_NOPRIVS", ":%s 723 %s %s :Insufficient oper privs.", NULL },
+/* 724 */ {"RPL_TESTMASK", ":%s 724 %s %s!%s@%s %u %u :Local/remote clients match.", NULL },
+/* 725 */ {"RPL_TESTLINE", ":%s 725 %s %c %ld %s :%s | %s", NULL },
+/* 726 */ {"RPL_NOTESTLINE", ":%s 726 %s %s :No matches", NULL },
+/* 727 */ {NULL, NULL, NULL},
+/* 728 */ {NULL, NULL, NULL},
+/* 729 */ {NULL, NULL, NULL},
+/* 730 */ {NULL, NULL, NULL},
+/* 731 */ {NULL, NULL, NULL},
+/* 732 */ {NULL, NULL, NULL},
+/* 733 */ {NULL, NULL, NULL},
+/* 734 */ {NULL, NULL, NULL},
+/* 735 */ {NULL, NULL, NULL},
+/* 736 */ {NULL, NULL, NULL},
+/* 737 */ {NULL, NULL, NULL},
+/* 738 */ {NULL, NULL, NULL},
+/* 739 */ {NULL, NULL, NULL},
+/* 740 */ {NULL, NULL, NULL},
+/* 741 */ {NULL, NULL, NULL},
+/* 742 */ {NULL, NULL, NULL},
+/* 743 */ {NULL, NULL, NULL},
+/* 744 */ {NULL, NULL, NULL},
+/* 745 */ {NULL, NULL, NULL},
+/* 746 */ {NULL, NULL, NULL},
+/* 747 */ {NULL, NULL, NULL},
+/* 748 */ {NULL, NULL, NULL},
+/* 749 */ {NULL, NULL, NULL},
+/* 750 */ {NULL, NULL, NULL},
+/* 751 */ {NULL, NULL, NULL},
+/* 752 */ {NULL, NULL, NULL},
+/* 753 */ {NULL, NULL, NULL},
+/* 754 */ {NULL, NULL, NULL},
+/* 755 */ {NULL, NULL, NULL},
+/* 756 */ {NULL, NULL, NULL},
+/* 757 */ {NULL, NULL, NULL},
+/* 758 */ {NULL, NULL, NULL},
+/* 759 */ {NULL, NULL, NULL},
+/* 760 */ {NULL, NULL, NULL},
+/* 761 */ {NULL, NULL, NULL},
+/* 762 */ {NULL, NULL, NULL},
+/* 763 */ {NULL, NULL, NULL},
+/* 764 */ {NULL, NULL, NULL},
+/* 765 */ {NULL, NULL, NULL},
+/* 766 */ {NULL, NULL, NULL},
+/* 767 */ {NULL, NULL, NULL},
+/* 768 */ {NULL, NULL, NULL},
+/* 769 */ {NULL, NULL, NULL},
+/* 770 */ {NULL, NULL, NULL},
+/* 771 */ {NULL, NULL, NULL},
+/* 772 */ {NULL, NULL, NULL},
+/* 773 */ {NULL, NULL, NULL},
+/* 774 */ {NULL, NULL, NULL},
+/* 775 */ {NULL, NULL, NULL},
+/* 776 */ {NULL, NULL, NULL},
+/* 777 */ {NULL, NULL, NULL},
+/* 778 */ {NULL, NULL, NULL},
+/* 779 */ {NULL, NULL, NULL},
+/* 780 */ {NULL, NULL, NULL},
+/* 781 */ {NULL, NULL, NULL},
+/* 782 */ {NULL, NULL, NULL},
+/* 783 */ {NULL, NULL, NULL},
+/* 784 */ {NULL, NULL, NULL},
+/* 785 */ {NULL, NULL, NULL},
+/* 786 */ {NULL, NULL, NULL},
+/* 787 */ {NULL, NULL, NULL},
+/* 788 */ {NULL, NULL, NULL},
+/* 789 */ {NULL, NULL, NULL},
+/* 790 */ {NULL, NULL, NULL},
+/* 791 */ {NULL, NULL, NULL},
+/* 792 */ {NULL, NULL, NULL},
+/* 793 */ {NULL, NULL, NULL},
+/* 794 */ {NULL, NULL, NULL},
+/* 795 */ {NULL, NULL, NULL},
+/* 796 */ {NULL, NULL, NULL},
+/* 797 */ {NULL, NULL, NULL},
+/* 798 */ {NULL, NULL, NULL},
+/* 799 */ {NULL, NULL, NULL},
+/* 800 */ {NULL, NULL, NULL},
+/* 801 */ {NULL, NULL, NULL},
+/* 802 */ {NULL, NULL, NULL},
+/* 803 */ {NULL, NULL, NULL},
+/* 804 */ {NULL, NULL, NULL},
+/* 805 */ {NULL, NULL, NULL},
+/* 806 */ {NULL, NULL, NULL},
+/* 807 */ {NULL, NULL, NULL},
+/* 808 */ {NULL, NULL, NULL},
+/* 809 */ {NULL, NULL, NULL},
+/* 810 */ {NULL, NULL, NULL},
+/* 811 */ {NULL, NULL, NULL},
+/* 812 */ {NULL, NULL, NULL},
+/* 813 */ {NULL, NULL, NULL},
+/* 814 */ {NULL, NULL, NULL},
+/* 815 */ {NULL, NULL, NULL},
+/* 816 */ {NULL, NULL, NULL},
+/* 817 */ {NULL, NULL, NULL},
+/* 818 */ {NULL, NULL, NULL},
+/* 819 */ {NULL, NULL, NULL},
+/* 820 */ {NULL, NULL, NULL},
+/* 821 */ {NULL, NULL, NULL},
+/* 822 */ {NULL, NULL, NULL},
+/* 823 */ {NULL, NULL, NULL},
+/* 824 */ {NULL, NULL, NULL},
+/* 825 */ {NULL, NULL, NULL},
+/* 826 */ {NULL, NULL, NULL},
+/* 827 */ {NULL, NULL, NULL},
+/* 828 */ {NULL, NULL, NULL},
+/* 829 */ {NULL, NULL, NULL},
+/* 830 */ {NULL, NULL, NULL},
+/* 831 */ {NULL, NULL, NULL},
+/* 832 */ {NULL, NULL, NULL},
+/* 833 */ {NULL, NULL, NULL},
+/* 834 */ {NULL, NULL, NULL},
+/* 835 */ {NULL, NULL, NULL},
+/* 836 */ {NULL, NULL, NULL},
+/* 837 */ {NULL, NULL, NULL},
+/* 838 */ {NULL, NULL, NULL},
+/* 839 */ {NULL, NULL, NULL},
+/* 840 */ {NULL, NULL, NULL},
+/* 841 */ {NULL, NULL, NULL},
+/* 842 */ {NULL, NULL, NULL},
+/* 843 */ {NULL, NULL, NULL},
+/* 844 */ {NULL, NULL, NULL},
+/* 845 */ {NULL, NULL, NULL},
+/* 846 */ {NULL, NULL, NULL},
+/* 847 */ {NULL, NULL, NULL},
+/* 848 */ {NULL, NULL, NULL},
+/* 849 */ {NULL, NULL, NULL},
+/* 850 */ {NULL, NULL, NULL},
+/* 851 */ {NULL, NULL, NULL},
+/* 852 */ {NULL, NULL, NULL},
+/* 853 */ {NULL, NULL, NULL},
+/* 854 */ {NULL, NULL, NULL},
+/* 855 */ {NULL, NULL, NULL},
+/* 856 */ {NULL, NULL, NULL},
+/* 857 */ {NULL, NULL, NULL},
+/* 858 */ {NULL, NULL, NULL},
+/* 859 */ {NULL, NULL, NULL},
+/* 860 */ {NULL, NULL, NULL},
+/* 861 */ {NULL, NULL, NULL},
+/* 862 */ {NULL, NULL, NULL},
+/* 863 */ {NULL, NULL, NULL},
+/* 864 */ {NULL, NULL, NULL},
+/* 865 */ {NULL, NULL, NULL},
+/* 866 */ {NULL, NULL, NULL},
+/* 867 */ {NULL, NULL, NULL},
+/* 868 */ {NULL, NULL, NULL},
+/* 869 */ {NULL, NULL, NULL},
+/* 870 */ {NULL, NULL, NULL},
+/* 871 */ {NULL, NULL, NULL},
+/* 872 */ {NULL, NULL, NULL},
+/* 873 */ {NULL, NULL, NULL},
+/* 874 */ {NULL, NULL, NULL},
+/* 875 */ {NULL, NULL, NULL},
+/* 876 */ {NULL, NULL, NULL},
+/* 877 */ {NULL, NULL, NULL},
+/* 878 */ {NULL, NULL, NULL},
+/* 879 */ {NULL, NULL, NULL},
+/* 880 */ {NULL, NULL, NULL},
+/* 881 */ {NULL, NULL, NULL},
+/* 882 */ {NULL, NULL, NULL},
+/* 883 */ {NULL, NULL, NULL},
+/* 884 */ {NULL, NULL, NULL},
+/* 885 */ {NULL, NULL, NULL},
+/* 886 */ {NULL, NULL, NULL},
+/* 887 */ {NULL, NULL, NULL},
+/* 888 */ {NULL, NULL, NULL},
+/* 889 */ {NULL, NULL, NULL},
+/* 890 */ {NULL, NULL, NULL},
+/* 891 */ {NULL, NULL, NULL},
+/* 892 */ {NULL, NULL, NULL},
+/* 893 */ {NULL, NULL, NULL},
+/* 894 */ {NULL, NULL, NULL},
+/* 895 */ {NULL, NULL, NULL},
+/* 896 */ {NULL, NULL, NULL},
+/* 897 */ {NULL, NULL, NULL},
+/* 898 */ {NULL, NULL, NULL},
+/* 899 */ {NULL, NULL, NULL},
+/* 900 */ {NULL, NULL, NULL},
+/* 901 */ {NULL, NULL, NULL},
+/* 902 */ {NULL, NULL, NULL},
+/* 903 */ {NULL, NULL, NULL},
+/* 904 */ {NULL, NULL, NULL},
+/* 905 */ {NULL, NULL, NULL},
+/* 906 */ {NULL, NULL, NULL},
+/* 907 */ {NULL, NULL, NULL},
+/* 908 */ {NULL, NULL, NULL},
+/* 909 */ {NULL, NULL, NULL},
+/* 910 */ {NULL, NULL, NULL},
+/* 911 */ {NULL, NULL, NULL},
+/* 912 */ {NULL, NULL, NULL},
+/* 913 */ {NULL, NULL, NULL},
+/* 914 */ {NULL, NULL, NULL},
+/* 915 */ {NULL, NULL, NULL},
+/* 916 */ {NULL, NULL, NULL},
+/* 917 */ {NULL, NULL, NULL},
+/* 918 */ {NULL, NULL, NULL},
+/* 919 */ {NULL, NULL, NULL},
+/* 920 */ {NULL, NULL, NULL},
+/* 921 */ {NULL, NULL, NULL},
+/* 922 */ {NULL, NULL, NULL},
+/* 923 */ {NULL, NULL, NULL},
+/* 924 */ {NULL, NULL, NULL},
+/* 925 */ {NULL, NULL, NULL},
+/* 926 */ {NULL, NULL, NULL},
+/* 927 */ {NULL, NULL, NULL},
+/* 928 */ {NULL, NULL, NULL},
+/* 929 */ {NULL, NULL, NULL},
+/* 930 */ {NULL, NULL, NULL},
+/* 931 */ {NULL, NULL, NULL},
+/* 932 */ {NULL, NULL, NULL},
+/* 933 */ {NULL, NULL, NULL},
+/* 934 */ {NULL, NULL, NULL},
+/* 935 */ {NULL, NULL, NULL},
+/* 936 */ {NULL, NULL, NULL},
+/* 937 */ {NULL, NULL, NULL},
+/* 938 */ {NULL, NULL, NULL},
+/* 939 */ {NULL, NULL, NULL},
+/* 940 */ {NULL, NULL, NULL},
+/* 941 */ {NULL, NULL, NULL},
+/* 942 */ {NULL, NULL, NULL},
+/* 943 */ {NULL, NULL, NULL},
+/* 944 */ {NULL, NULL, NULL},
+/* 945 */ {NULL, NULL, NULL},
+/* 946 */ {NULL, NULL, NULL},
+/* 947 */ {NULL, NULL, NULL},
+/* 948 */ {NULL, NULL, NULL},
+/* 949 */ {NULL, NULL, NULL},
+/* 950 */ {NULL, NULL, NULL},
+/* 951 */ {NULL, NULL, NULL},
+/* 952 */ {NULL, NULL, NULL},
+/* 953 */ {NULL, NULL, NULL},
+/* 954 */ {NULL, NULL, NULL},
+/* 955 */ {NULL, NULL, NULL},
+/* 956 */ {NULL, NULL, NULL},
+/* 957 */ {NULL, NULL, NULL},
+/* 958 */ {NULL, NULL, NULL},
+/* 959 */ {NULL, NULL, NULL},
+/* 960 */ {NULL, NULL, NULL},
+/* 961 */ {NULL, NULL, NULL},
+/* 962 */ {NULL, NULL, NULL},
+/* 963 */ {NULL, NULL, NULL},
+/* 964 */ {NULL, NULL, NULL},
+/* 965 */ {NULL, NULL, NULL},
+/* 966 */ {NULL, NULL, NULL},
+/* 967 */ {NULL, NULL, NULL},
+/* 968 */ {NULL, NULL, NULL},
+/* 969 */ {NULL, NULL, NULL},
+/* 970 */ {NULL, NULL, NULL},
+/* 971 */ {NULL, NULL, NULL},
+/* 972 */ {NULL, NULL, NULL},
+/* 973 */ {NULL, NULL, NULL},
+/* 974 */ {NULL, NULL, NULL},
+/* 975 */ {NULL, NULL, NULL},
+/* 976 */ {NULL, NULL, NULL},
+/* 977 */ {NULL, NULL, NULL},
+/* 978 */ {NULL, NULL, NULL},
+/* 979 */ {NULL, NULL, NULL},
+/* 980 */ {NULL, NULL, NULL},
+/* 981 */ {NULL, NULL, NULL},
+/* 982 */ {NULL, NULL, NULL},
+/* 983 */ {NULL, NULL, NULL},
+/* 984 */ {NULL, NULL, NULL},
+/* 985 */ {NULL, NULL, NULL},
+/* 986 */ {NULL, NULL, NULL},
+/* 987 */ {NULL, NULL, NULL},
+/* 988 */ {NULL, NULL, NULL},
+/* 989 */ {NULL, NULL, NULL},
+/* 990 */ {NULL, NULL, NULL},
+/* 991 */ {NULL, NULL, NULL},
+/* 992 */ {NULL, NULL, NULL},
+/* 993 */ {NULL, NULL, NULL},
+/* 994 */ {NULL, NULL, NULL},
+/* 995 */ {NULL, NULL, NULL},
+/* 996 */ {NULL, NULL, NULL},
+/* 997 */ {NULL, NULL, NULL},
+/* 998 */ {NULL, NULL, NULL},
+/* 999 */ {NULL, NULL, NULL}
+};
diff --git a/src/modules.c b/src/modules.c
new file mode 100644
index 0000000..8a5ab1b
--- /dev/null
+++ b/src/modules.c
@@ -0,0 +1,401 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * modules.c: A module loader.
+ *
+ * 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$
+ */
+
+#include "ltdl.h"
+
+#include "stdinc.h"
+#include "list.h"
+#include "modules.h"
+#include "log.h"
+#include "ircd.h"
+#include "client.h"
+#include "send.h"
+#include "conf.h"
+#include "numeric.h"
+#include "parse.h"
+#include "ircd_defs.h"
+#include "irc_string.h"
+#include "memory.h"
+
+
+dlink_list modules_list = { NULL, NULL, 0 };
+
+static const char *unknown_ver = "<unknown>";
+
+static const char *core_module_table[] =
+{
+ "m_die.la",
+ "m_error.la",
+ "m_join.la",
+ "m_kick.la",
+ "m_kill.la",
+ "m_message.la",
+ "m_mode.la",
+ "m_nick.la",
+ "m_part.la",
+ "m_quit.la",
+ "m_server.la",
+ "m_sjoin.la",
+ "m_squit.la",
+ NULL
+};
+
+static dlink_list mod_paths = { NULL, NULL, 0 };
+static dlink_list conf_modules = { NULL, NULL, 0 };
+
+int
+modules_valid_suffix(const char *name)
+{
+ return ((name = strrchr(name, '.'))) && !strcmp(name, ".la");
+}
+
+/* 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)
+{
+ struct module *modp = NULL;
+
+ if ((modp = findmodule_byname(name)) == NULL)
+ return -1;
+
+ if (modp->modexit)
+ modp->modexit();
+
+ assert(dlink_list_length(&modules_list) > 0);
+ dlinkDelete(&modp->node, &modules_list);
+ MyFree(modp->name);
+
+ lt_dlclose(modp->handle);
+
+ if (warn == 1)
+ {
+ ilog(LOG_TYPE_IRCD, "Module %s unloaded", name);
+ sendto_realops_flags(UMODE_ALL, 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)
+{
+ lt_dlhandle tmpptr = NULL;
+ const char *mod_basename = NULL;
+ struct module *modp = NULL;
+
+ if (findmodule_byname((mod_basename = libio_basename(path))))
+ return 1;
+
+ if (!(tmpptr = lt_dlopen(path))) {
+ const char *err = ((err = lt_dlerror())) ? err : "<unknown>";
+
+ sendto_realops_flags(UMODE_ALL, L_ALL, "Error loading module %s: %s",
+ mod_basename, err);
+ ilog(LOG_TYPE_IRCD, "Error loading module %s: %s", mod_basename, err);
+ return -1;
+ }
+
+ if ((modp = lt_dlsym(tmpptr, "module_entry")) == NULL)
+ {
+ const char *err = ((err = lt_dlerror())) ? err : "<unknown>";
+
+ sendto_realops_flags(UMODE_ALL, L_ALL, "Error loading module %s: %s",
+ mod_basename, err);
+ ilog(LOG_TYPE_IRCD, "Error loading module %s: %s", mod_basename, err);
+ lt_dlclose(tmpptr);
+ return -1;
+ }
+
+ modp->handle = tmpptr;
+
+ if (EmptyString(modp->version))
+ modp->version = unknown_ver;
+
+ DupString(modp->name, mod_basename);
+ dlinkAdd(modp, &modp->node, &modules_list);
+
+ if (modp->modinit)
+ modp->modinit();
+
+ if (warn == 1)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Module %s [version: %s handle: %p] loaded.",
+ modp->name, modp->version, tmpptr);
+ ilog(LOG_TYPE_IRCD, "Module %s [version: %s handle: %p] loaded.",
+ modp->name, modp->version, tmpptr);
+ }
+
+ return 0;
+}
+
+/*
+ * modules_init
+ *
+ * input - NONE
+ * output - NONE
+ * side effects - The basic module manipulation modules are loaded
+ */
+void
+modules_init(void)
+{
+ if (lt_dlinit())
+ {
+ ilog(LOG_TYPE_IRCD, "Couldn't initialize the libltdl run time dynamic"
+ " link library. Exiting.");
+ exit(0);
+ }
+}
+
+/* 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;
+
+ DLINK_FOREACH(ptr, mod_paths.head)
+ {
+ struct module_path *mpath = ptr->data;
+
+ if (!strcmp(path, mpath->path))
+ return mpath;
+ }
+
+ return NULL;
+}
+
+/* mod_add_path()
+ *
+ * input - path
+ * output - NONE
+ * 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));
+
+ strlcpy(pathst->path, path, sizeof(pathst->path));
+ dlinkAdd(pathst, &pathst->node, &mod_paths);
+}
+
+/* add_conf_module
+ *
+ * input - module name
+ * output - NONE
+ * side effects - adds module to conf_mod
+ */
+void
+add_conf_module(const char *name)
+{
+ struct module_path *pathst;
+
+ pathst = MyMalloc(sizeof(struct module_path));
+
+ strlcpy(pathst->path, name, sizeof(pathst->path));
+ dlinkAdd(pathst, &pathst->node, &conf_modules);
+}
+
+/* mod_clear_paths()
+ *
+ * input - NONE
+ * output - NONE
+ * side effects - clear the lists of paths and conf modules
+ */
+void
+mod_clear_paths(void)
+{
+ dlink_node *ptr = NULL, *next_ptr = NULL;
+
+ DLINK_FOREACH_SAFE(ptr, next_ptr, mod_paths.head)
+ {
+ dlinkDelete(ptr, &mod_paths);
+ MyFree(ptr->data);
+ }
+
+ DLINK_FOREACH_SAFE(ptr, next_ptr, conf_modules.head)
+ {
+ dlinkDelete(ptr, &conf_modules);
+ MyFree(ptr->data);
+ }
+}
+
+/* findmodule_byname
+ *
+ * input - name of module
+ * output - NULL if not found or pointer to module
+ * side effects - NONE
+ */
+struct module *
+findmodule_byname(const char *name)
+{
+ dlink_node *ptr = NULL;
+
+ DLINK_FOREACH(ptr, modules_list.head)
+ {
+ struct module *modp = ptr->data;
+
+ if (strcmp(modp->name, name) == 0)
+ return modp;
+ }
+
+ return NULL;
+}
+
+/* load_all_modules()
+ *
+ * input - int flag warn
+ * output - NONE
+ * side effects - load all modules found in autoload directory
+ */
+void
+load_all_modules(int warn)
+{
+ DIR *system_module_dir = NULL;
+ struct dirent *ldirent = NULL;
+ char module_fq_name[PATH_MAX + 1];
+
+ if ((system_module_dir = opendir(AUTOMODPATH)) == NULL)
+ {
+ ilog(LOG_TYPE_IRCD, "Could not load modules from %s: %s",
+ AUTOMODPATH, strerror(errno));
+ return;
+ }
+
+ while ((ldirent = readdir(system_module_dir)) != NULL)
+ {
+ if (modules_valid_suffix(ldirent->d_name))
+ {
+ snprintf(module_fq_name, sizeof(module_fq_name), "%s/%s",
+ AUTOMODPATH, ldirent->d_name);
+ load_a_module(module_fq_name, warn);
+ }
+ }
+
+ closedir(system_module_dir);
+}
+
+/* load_conf_modules()
+ *
+ * input - NONE
+ * output - NONE
+ * side effects - load modules given in ircd.conf
+ */
+void
+load_conf_modules(void)
+{
+ dlink_node *ptr = NULL;
+
+ DLINK_FOREACH(ptr, conf_modules.head)
+ {
+ struct module_path *mpath = ptr->data;
+
+ if (findmodule_byname(mpath->path) == NULL)
+ load_one_module(mpath->path);
+ }
+}
+
+/* load_core_modules()
+ *
+ * input - int flag warn
+ * output - NONE
+ * side effects - core modules are loaded, if any fail, kill ircd
+ */
+void
+load_core_modules(int warn)
+{
+ char module_name[PATH_MAX + 1];
+ int i = 0;
+
+ for (; core_module_table[i]; ++i)
+ {
+ snprintf(module_name, sizeof(module_name), "%s%s",
+ MODPATH, core_module_table[i]);
+
+ if (load_a_module(module_name, warn) == -1)
+ {
+ ilog(LOG_TYPE_IRCD, "Error loading core module %s: terminating ircd",
+ core_module_table[i]);
+ exit(EXIT_FAILURE);
+ }
+ }
+}
+
+/* load_one_module()
+ *
+ * input - pointer to path
+ * - flagged as core module or not
+ * output - -1 if error
+ * side effects - module is loaded if found.
+ */
+int
+load_one_module(const char *path)
+{
+ dlink_node *ptr = NULL;
+ char modpath[PATH_MAX + 1];
+ struct stat statbuf;
+
+ DLINK_FOREACH(ptr, mod_paths.head)
+ {
+ const struct module_path *mpath = ptr->data;
+
+ snprintf(modpath, sizeof(modpath), "%s/%s", mpath->path, path);
+
+ if (!modules_valid_suffix(path))
+ continue;
+
+ if (strstr(modpath, "../") == NULL &&
+ strstr(modpath, "/..") == NULL)
+ if (!stat(modpath, &statbuf))
+ if (S_ISREG(statbuf.st_mode)) /* Regular files only please */
+ return load_a_module(modpath, 1);
+ }
+
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Cannot locate module %s", path);
+ ilog(LOG_TYPE_IRCD, "Cannot locate module %s", path);
+ return -1;
+}
diff --git a/src/motd.c b/src/motd.c
new file mode 100644
index 0000000..a4c2612
--- /dev/null
+++ b/src/motd.c
@@ -0,0 +1,283 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * motd.c: Message of the day functions.
+ *
+ * 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$
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "motd.h"
+#include "ircd.h"
+#include "fdlist.h"
+#include "s_bsd.h"
+#include "conf.h"
+#include "send.h"
+#include "numeric.h"
+#include "client.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "memory.h"
+#include "s_serv.h"
+
+/*
+** init_message_file
+**
+*/
+void
+init_message_file(MotdType motdType, const char *fileName, MessageFile *motd)
+{
+ strlcpy(motd->fileName, fileName, sizeof(motd->fileName));
+ motd->motdType = motdType;
+ motd->contentsOfFile = NULL;
+ motd->lastChangedDate[0] = '\0';
+}
+
+/*
+** send_message_file
+**
+** This function split off so a server notice could be generated on a
+** user requested motd, but not on each connecting client.
+*/
+int
+send_message_file(struct Client *source_p, MessageFile *motdToPrint)
+{
+ MessageFileLine *linePointer;
+ MotdType motdType;
+ const char *from, *to;
+
+ if (motdToPrint == NULL)
+ return(-1);
+
+ motdType = motdToPrint->motdType;
+
+ from = ID_or_name(&me, source_p->from);
+ to = ID_or_name(source_p, source_p->from);
+
+ switch (motdType)
+ {
+ case USER_MOTD:
+ if (motdToPrint->contentsOfFile == NULL)
+ sendto_one(source_p, form_str(ERR_NOMOTD), from, to);
+ else
+ {
+ sendto_one(source_p, form_str(RPL_MOTDSTART),
+ from, to, me.name);
+
+ for (linePointer = motdToPrint->contentsOfFile; linePointer;
+ linePointer = linePointer->next)
+ {
+ sendto_one(source_p, form_str(RPL_MOTD),
+ from, to, linePointer->line);
+ }
+
+ sendto_one(source_p, form_str(RPL_ENDOFMOTD), from, to);
+ }
+ break;
+
+ case USER_LINKS:
+ if (motdToPrint->contentsOfFile != NULL)
+ {
+ for (linePointer = motdToPrint->contentsOfFile; linePointer;
+ linePointer = linePointer->next)
+ {
+ sendto_one(source_p, ":%s 364 %s %s", /* XXX */
+ from, to, linePointer->line);
+ }
+ }
+ break;
+
+ case ISSUPPORT:
+ if (motdToPrint->contentsOfFile != NULL)
+ {
+ for (linePointer = motdToPrint->contentsOfFile; linePointer;
+ linePointer = linePointer->next)
+ {
+ sendto_one(source_p, form_str(RPL_ISUPPORT),
+ me.name, source_p->name, linePointer->line);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return(0);
+}
+
+/*
+ * read_message_file() - original From CoMSTuD, added Aug 29, 1996
+ *
+ * inputs - pointer to MessageFileptr
+ * output -
+ * side effects -
+ */
+int
+read_message_file(MessageFile *MessageFileptr)
+{
+ struct stat sb;
+ struct tm *local_tm;
+
+ /* used to clear out old MessageFile entries */
+ MessageFileLine *mptr = 0;
+ MessageFileLine *next_mptr = 0;
+
+ /* used to add new MessageFile entries */
+ MessageFileLine *newMessageLine = 0;
+ MessageFileLine *currentMessageLine = 0;
+
+ char buffer[MESSAGELINELEN];
+ char *p;
+ FILE *file;
+
+ for (mptr = MessageFileptr->contentsOfFile; mptr; mptr = next_mptr)
+ {
+ next_mptr = mptr->next;
+ MyFree(mptr);
+ }
+
+ MessageFileptr->contentsOfFile = NULL;
+
+ if (stat(MessageFileptr->fileName, &sb) < 0)
+ return(-1);
+
+ local_tm = localtime(&sb.st_mtime);
+
+ if (local_tm)
+ ircsprintf(MessageFileptr->lastChangedDate,
+ "%d/%d/%d %d:%02d",
+ local_tm->tm_mday,
+ local_tm->tm_mon + 1,
+ 1900 + local_tm->tm_year,
+ local_tm->tm_hour,
+ local_tm->tm_min);
+
+ if ((file = fopen(MessageFileptr->fileName, "r")) == NULL)
+ return(-1);
+
+ while (fgets(buffer, sizeof(buffer), file))
+ {
+ if ((p = strchr(buffer, '\n')) != NULL)
+ *p = '\0';
+
+ newMessageLine = (MessageFileLine *)MyMalloc(sizeof(MessageFileLine));
+ strlcpy(newMessageLine->line, buffer, sizeof(newMessageLine->line));
+ newMessageLine->next = NULL;
+
+ if (MessageFileptr->contentsOfFile != NULL)
+ {
+ if (currentMessageLine)
+ currentMessageLine->next = newMessageLine;
+
+ currentMessageLine = newMessageLine;
+ }
+ else
+ {
+ MessageFileptr->contentsOfFile = newMessageLine;
+ currentMessageLine = newMessageLine;
+ }
+ }
+
+ fclose(file);
+ return(0);
+}
+
+/*
+ * init_MessageLine
+ *
+ * inputs - NONE
+ * output - pointer to new MessageFile
+ * side effects - Use this when an internal Message File is wanted
+ * without reading an actual file. The MessageFile
+ * is init'ed, but must have content added to it through
+ * addto_MessageLine()
+ */
+
+MessageFile *
+init_MessageLine(void)
+{
+ MessageFile *mf;
+ MessageFileLine *mptr = NULL;
+
+ mf = MyMalloc(sizeof(MessageFile));
+ mf->motdType = ISSUPPORT; /* XXX maybe pass it alone in args? */
+ mptr = MyMalloc(sizeof(MessageFileLine));
+ mf->contentsOfFile = mptr;
+ return(mf);
+}
+
+/*
+ * addto_MessageLine
+ *
+ * inputs - Pointer to existing MessageFile
+ * - New string to add to this MessageFile
+ * output - NONE
+ * side effects - Use this when an internal MessageFile is wanted
+ * without reading an actual file. Content is added
+ * to this MessageFile through this function.
+ */
+
+void
+addto_MessageLine(MessageFile *mf, const char *str)
+{
+ MessageFileLine *mptr = mf->contentsOfFile;
+ MessageFileLine *nmptr = NULL;
+
+ if (mptr == NULL)
+ {
+ mptr = MyMalloc(sizeof(MessageFileLine));
+ strcpy(mptr->line, str);
+ mf->contentsOfFile = mptr;
+ }
+ else
+ {
+ while (mptr->next != NULL)
+ mptr = mptr->next;
+ nmptr = MyMalloc(sizeof(MessageFileLine));
+ strcpy(nmptr->line, str);
+ mptr->next = nmptr;
+ }
+}
+
+/*
+ * destroy_MessageLine(MessageFile *mf)
+ *
+ * inputs - pointer to the MessageFile to destroy
+ * output - NONE
+ * side effects - All the MessageLines attached to the given mf
+ * Are freed then one MessageLine is recreated
+ */
+void
+destroy_MessageLine(MessageFile *mf)
+{
+ MessageFileLine *mptr = mf->contentsOfFile;
+ MessageFileLine *nmptr = NULL;
+
+ if (mptr == NULL)
+ return;
+
+ for (mptr = mf->contentsOfFile; mptr != NULL; mptr = nmptr)
+ {
+ nmptr = mptr->next;
+ MyFree(mptr);
+ }
+ mf->contentsOfFile = NULL;
+}
diff --git a/src/numeric.c b/src/numeric.c
new file mode 100644
index 0000000..2a1042d
--- /dev/null
+++ b/src/numeric.c
@@ -0,0 +1,226 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * numeric.c: Numeric handling functions.
+ *
+ * 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$
+ */
+
+#include "stdinc.h"
+
+#include "numeric.h"
+#include "irc_string.h"
+#include "memory.h"
+#include "log.h"
+#include "send.h"
+#include "client.h"
+#include "messages.tab"
+
+static char used_locale[LOCALE_LENGTH] = "standard";
+
+/*
+ * form_str
+ *
+ * inputs - numeric
+ * output - corresponding string
+ * side effects - NONE
+ */
+const char* form_str(int numeric)
+{
+ assert(-1 < numeric);
+ assert(numeric < ERR_LAST_ERR_MSG);
+
+ if (numeric > ERR_LAST_ERR_MSG)
+ numeric = ERR_LAST_ERR_MSG;
+ if (numeric < 0)
+ numeric = ERR_LAST_ERR_MSG;
+
+ assert(replies[numeric].standard != NULL);
+
+ return (replies[numeric].translated != NULL ? replies[numeric].translated :
+ replies[numeric].standard);
+}
+
+/* Attempts to change a numeric with index "reply" to "new_reply".
+ * Returns 1 if ok, 0 otherwise.
+ */
+static int
+change_reply(const char *locale, int linecnt, int reply, char *new_reply)
+{
+ int found;
+ char *new = new_reply;
+ const char *old = replies[reply].standard;
+
+ for (; *new; new++)
+ {
+ if (*new == '%')
+ {
+ if (!*++new) break;
+ if (*new != '%')
+ {
+ /* We've just found a format symbol. Check if it is the next format
+ * symbol in the original reply.
+ */
+ for (; *new >= '0' && *new <= '9'; new++); /* skip size prefix */
+ found = 0;
+ for (; *old; old++)
+ {
+ if (*old == '%')
+ {
+ if (!*++old) break; /* shouldn't happen */
+ if (*old != '%')
+ {
+ for (; *old >= '0' && *old <= '9'; old++); /* skip size prefix */
+ if (*new != *old++)
+ {
+ ilog(LOG_TYPE_IRCD, "Incompatible format symbols (%s.lang, %d)",
+ locale, linecnt);
+ return 0;
+ }
+ found = 1;
+ break;
+ }
+ }
+ }
+ if (!found)
+ {
+ ilog(LOG_TYPE_IRCD, "Too many format symbols (%s.lang, %d)", locale, linecnt);
+ return(0);
+ }
+ }
+ }
+ }
+
+ MyFree(replies[reply].translated);
+ DupString(replies[reply].translated, new_reply);
+ return(1);
+}
+
+/* Loads a language file. Errors are logged into the log file. */
+void
+set_locale(const char *locale)
+{
+ int i, res = 1, linecnt = 0;
+ char buffer[IRCD_BUFSIZE + 1];
+ char *ident, *reply;
+ FILE *f;
+
+ /* Restore standard replies */
+ for (i = 0; i <= ERR_LAST_ERR_MSG; i++) /* 0 isn't a magic number! ;> */
+ {
+ if (replies[i].translated != NULL)
+ {
+ MyFree(replies[i].translated);
+ replies[i].translated = NULL;
+ }
+ }
+
+ if (strchr(locale, '/') != NULL)
+ {
+ strlcpy(used_locale, "standard", sizeof(used_locale)); /* XXX paranoid */
+ return;
+ }
+
+ /* yes, I know - the slash isn't necessary. But I have to be sure
+ * that it'll work even if some lame admin won't put "/" at the end
+ * of MSGPATH.
+ */
+ snprintf(buffer, sizeof(buffer), "%s/%s.lang", MSGPATH, locale);
+ if ((f = fopen(buffer, "r")) == NULL)
+ {
+ strlcpy(used_locale, "standard", sizeof(used_locale)); /* XXX */
+ return;
+ }
+
+ /* Process the language file */
+ while (fgets(buffer, sizeof(buffer), f))
+ {
+ ++linecnt;
+ if (buffer[0] == ';')
+ continue; /* that's a comment */
+
+ if ((ident = strpbrk(buffer, "\r\n")) != NULL)
+ *ident = '\0';
+
+ /* skip spaces if there are any */
+ for (ident = buffer; *ident == ' ' || *ident == '\t'; ident++)/* null */;
+ if (*ident == '\0')
+ continue; /* empty line */
+
+ /* skip after the reply identificator */
+ for (reply = ident; *reply != ' ' && *reply != '\t' && *reply != ':';
+ reply++)
+ if (*reply == '\0') goto error;
+
+ if (*reply == ' ' || *reply == '\t')
+ {
+ for (*reply++ = '\0'; *reply == ' ' || *reply == '\t'; reply++);
+ if (*reply != ':')
+ {
+ error:
+ ilog(LOG_TYPE_IRCD, "Invalid line in language file (%s.lang, %d)",
+ locale, linecnt);
+ res = 0;
+ continue;
+ }
+ }
+ else
+ *reply++ = '\0';
+ if (*ident == '\0')
+ goto error;
+
+ /* skip to the beginning of reply */
+ while (*reply == ' ' || *reply == '\t') reply++;
+ if (*reply == '\0')
+ goto error;
+
+ for (i = 0; i <= ERR_LAST_ERR_MSG; i++)
+ {
+ if (replies[i].name != NULL)
+ {
+ if (irccmp(replies[i].name, ident) == 0)
+ {
+ if (!change_reply(locale, linecnt, i, reply)) res = 0;
+ i = -1;
+ break;
+ }
+ }
+ }
+ if (i != -1)
+ {
+ ilog(LOG_TYPE_IRCD,
+ "Unknown numeric %s (%s.lang, %d)", ident, locale, linecnt);
+ res = 0;
+ }
+ }
+ fclose(f);
+
+ strlcpy(used_locale, locale, sizeof(used_locale));
+ if (!res)
+ sendto_realops_flags(UMODE_ALL, L_ADMIN, "Language file [%s] contains "
+ "errors, check server log file for more details",
+ used_locale);
+}
+
+/* Returns the name of current locale. */
+const char *
+get_locale(void)
+{
+ return used_locale;
+}
diff --git a/src/packet.c b/src/packet.c
new file mode 100644
index 0000000..aeb4ac6
--- /dev/null
+++ b/src/packet.c
@@ -0,0 +1,414 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * packet.c: Packet handlers.
+ *
+ * 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$
+ */
+#include "stdinc.h"
+#include "list.h"
+#include "s_bsd.h"
+#include "conf.h"
+#include "s_serv.h"
+#include "client.h"
+#include "ircd.h"
+#include "parse.h"
+#include "fdlist.h"
+#include "packet.h"
+#include "irc_string.h"
+#include "memory.h"
+#include "hook.h"
+#include "send.h"
+#include "s_misc.h"
+
+#define READBUF_SIZE 16384
+
+struct Callback *iorecv_cb = NULL;
+
+static char readBuf[READBUF_SIZE];
+static void client_dopacket(struct Client *, char *, size_t);
+
+/* extract_one_line()
+ *
+ * inputs - pointer to a dbuf queue
+ * - pointer to buffer to copy data to
+ * output - length of <buffer>
+ * side effects - one line is copied and removed from the dbuf
+ */
+static int
+extract_one_line(struct dbuf_queue *qptr, char *buffer)
+{
+ struct dbuf_block *block;
+ int line_bytes = 0, empty_bytes = 0, phase = 0;
+ unsigned int idx;
+
+ char c;
+ dlink_node *ptr;
+
+ /*
+ * Phase 0: "empty" characters before the line
+ * Phase 1: copying the line
+ * Phase 2: "empty" characters after the line
+ * (delete them as well and free some space in the dbuf)
+ *
+ * Empty characters are CR, LF and space (but, of course, not
+ * in the middle of a line). We try to remove as much of them as we can,
+ * since they simply eat server memory.
+ *
+ * --adx
+ */
+ DLINK_FOREACH(ptr, qptr->blocks.head)
+ {
+ block = ptr->data;
+
+ for (idx = 0; idx < block->size; idx++)
+ {
+ c = block->data[idx];
+ if (IsEol(c) || (c == ' ' && phase != 1))
+ {
+ empty_bytes++;
+ if (phase == 1)
+ phase = 2;
+ }
+ else switch (phase)
+ {
+ case 0: phase = 1;
+ case 1: if (line_bytes++ < IRCD_BUFSIZE - 2)
+ *buffer++ = c;
+ break;
+ case 2: *buffer = '\0';
+ dbuf_delete(qptr, line_bytes + empty_bytes);
+ return IRCD_MIN(line_bytes, IRCD_BUFSIZE - 2);
+ }
+ }
+ }
+
+ /*
+ * Now, if we haven't reached phase 2, ignore all line bytes
+ * that we have read, since this is a partial line case.
+ */
+ if (phase != 2)
+ line_bytes = 0;
+ else
+ *buffer = '\0';
+
+ /* Remove what is now unnecessary */
+ dbuf_delete(qptr, line_bytes + empty_bytes);
+ return IRCD_MIN(line_bytes, IRCD_BUFSIZE - 2);
+}
+
+/*
+ * parse_client_queued - parse client queued messages
+ */
+static void
+parse_client_queued(struct Client *client_p)
+{
+ int dolen = 0;
+ int checkflood = 1;
+ struct LocalUser *lclient_p = client_p->localClient;
+
+ if (IsUnknown(client_p))
+ {
+ int i = 0;
+
+ for(;;)
+ {
+ if (IsDefunct(client_p))
+ return;
+
+ /* rate unknown clients at MAX_FLOOD per loop */
+ if (i >= MAX_FLOOD)
+ break;
+
+ dolen = extract_one_line(&lclient_p->buf_recvq, readBuf);
+ if (dolen == 0)
+ break;
+
+ client_dopacket(client_p, readBuf, dolen);
+ i++;
+
+ /* if they've dropped out of the unknown state, break and move
+ * to the parsing for their appropriate status. --fl
+ */
+ if(!IsUnknown(client_p))
+ break;
+ }
+ }
+
+ if (IsServer(client_p) || IsConnecting(client_p) || IsHandshake(client_p))
+ {
+ while (1)
+ {
+ if (IsDefunct(client_p))
+ return;
+ if ((dolen = extract_one_line(&lclient_p->buf_recvq,
+ readBuf)) == 0)
+ break;
+ client_dopacket(client_p, readBuf, dolen);
+ }
+ }
+ else if (IsClient(client_p))
+ {
+ if (ConfigFileEntry.no_oper_flood && (HasUMode(client_p, UMODE_OPER) || IsCanFlood(client_p)))
+ {
+ if (ConfigFileEntry.true_no_oper_flood)
+ checkflood = -1;
+ else
+ 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 (;;)
+ {
+ if (IsDefunct(client_p))
+ break;
+
+ /* 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 > 0)
+ {
+ if(lclient_p->sent_parsed >= lclient_p->allow_read)
+ break;
+ }
+
+ /* allow opers 4 times the amount of messages as users. why 4?
+ * why not. :) --fl_
+ */
+ else if (lclient_p->sent_parsed >= (4 * lclient_p->allow_read) &&
+ checkflood != -1)
+ break;
+
+ dolen = extract_one_line(&lclient_p->buf_recvq, readBuf);
+ if (dolen == 0)
+ break;
+
+ client_dopacket(client_p, readBuf, dolen);
+ lclient_p->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(fde_t *fd, void *data)
+{
+ struct Client *client_p = data;
+ struct LocalUser *lclient_p = client_p->localClient;
+
+ /* 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;
+
+ parse_client_queued(client_p);
+
+ /* And now, try flushing .. */
+ if (!IsDead(client_p))
+ {
+ /* and finally, reset the flood check */
+ comm_setflush(fd, 1000, flood_recalc, client_p);
+ }
+}
+
+/*
+ * iorecv_default - append a packet to the recvq dbuf
+ */
+void *
+iorecv_default(va_list args)
+{
+ struct Client *client_p = va_arg(args, struct Client *);
+ int length = va_arg(args, int);
+ char *buf = va_arg(args, char *);
+
+ dbuf_put(&client_p->localClient->buf_recvq, buf, length);
+ return NULL;
+}
+
+/*
+ * read_packet - Read a 'packet' of data from a connection and process it.
+ */
+void
+read_packet(fde_t *fd, void *data)
+{
+ struct Client *client_p = data;
+ int length = 0;
+
+ if (IsDefunct(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
+ */
+ do {
+#ifdef HAVE_LIBCRYPTO
+ if (fd->ssl)
+ {
+ length = SSL_read(fd->ssl, readBuf, READBUF_SIZE);
+
+ /* translate openssl error codes, sigh */
+ if (length < 0)
+ switch (SSL_get_error(fd->ssl, length))
+ {
+ case SSL_ERROR_WANT_WRITE:
+ fd->flags.pending_read = 1;
+ SetSendqBlocked(client_p);
+ comm_setselect(fd, COMM_SELECT_WRITE, (PF *) sendq_unblocked,
+ client_p, 0);
+ return;
+ case SSL_ERROR_WANT_READ:
+ errno = EWOULDBLOCK;
+ case SSL_ERROR_SYSCALL:
+ break;
+ case SSL_ERROR_SSL:
+ if (errno == EAGAIN)
+ break;
+ default:
+ length = errno = 0;
+ }
+ }
+ else
+#endif
+ {
+ length = recv(fd->fd, readBuf, READBUF_SIZE, 0);
+ }
+
+ if (length <= 0)
+ {
+ /*
+ * If true, then we can recover from this error. Just jump out of
+ * the loop and re-register a new io-request.
+ */
+ if (length < 0 && ignoreErrno(errno))
+ break;
+
+ dead_link_on_read(client_p, length);
+ return;
+ }
+
+ execute_callback(iorecv_cb, client_p, length, readBuf);
+
+ if (client_p->localClient->lasttime < CurrentTime)
+ client_p->localClient->lasttime = CurrentTime;
+ if (client_p->localClient->lasttime > client_p->localClient->since)
+ client_p->localClient->since = CurrentTime;
+ ClearPingSent(client_p);
+
+ /* Attempt to parse what we have */
+ parse_client_queued(client_p);
+
+ if (IsDefunct(client_p))
+ return;
+
+ /* Check to make sure we're not flooding */
+ if (!(IsServer(client_p) || IsHandshake(client_p) || IsConnecting(client_p))
+ && (dbuf_length(&client_p->localClient->buf_recvq) >
+ get_recvq(client_p)))
+ {
+ if (!(ConfigFileEntry.no_oper_flood && HasUMode(client_p, UMODE_OPER)))
+ {
+ exit_client(client_p, client_p, "Excess Flood");
+ return;
+ }
+ }
+ }
+#ifdef HAVE_LIBCRYPTO
+ while (length == sizeof(readBuf) || fd->ssl);
+#else
+ while (length == sizeof(readBuf));
+#endif
+
+ /* If we get here, we need to register for another COMM_SELECT_READ */
+ comm_setselect(fd, 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..)
+ */
+static void
+client_dopacket(struct Client *client_p, char *buffer, size_t length)
+{
+ /*
+ * Update messages received
+ */
+ ++me.localClient->recv.messages;
+ ++client_p->localClient->recv.messages;
+
+ /*
+ * Update bytes received
+ */
+ client_p->localClient->recv.bytes += length;
+ me.localClient->recv.bytes += length;
+
+ parse(client_p, buffer, buffer + length);
+}
diff --git a/src/parse.c b/src/parse.c
new file mode 100644
index 0000000..f326d74
--- /dev/null
+++ b/src/parse.c
@@ -0,0 +1,815 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * parse.c: The message parser.
+ *
+ * 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$
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "parse.h"
+#include "channel.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "log.h"
+#include "send.h"
+#include "conf.h"
+#include "memory.h"
+#include "s_user.h"
+#include "s_serv.h"
+
+/*
+ * (based on orabidoo's parser code)
+ *
+ * This has always just been a trie. Look at volume III of Knuth ACP
+ *
+ *
+ * ok, you start out with an array of pointers, each one corresponds
+ * to a letter at the current position in the command being examined.
+ *
+ * so roughly you have this for matching 'trie' or 'tie'
+ *
+ * 't' points -> [MessageTree *] 'r' -> [MessageTree *] -> 'i'
+ * -> [MessageTree *] -> [MessageTree *] -> 'e' and matches
+ *
+ * 'i' -> [MessageTree *] -> 'e' and matches
+ *
+ * BUGS (Limitations!)
+ *
+ * I designed this trie to parse ircd commands. Hence it currently
+ * casefolds. This is trivial to fix by increasing MAXPTRLEN.
+ * This trie also "folds" '{' etc. down. This means, the input to this
+ * trie must be alpha tokens only. This again, is a limitation that
+ * can be overcome by increasing MAXPTRLEN to include upper/lower case
+ * at the expense of more memory. At the extreme end, you could make
+ * MAXPTRLEN 128.
+ *
+ * This is also not a patricia trie. On short ircd tokens, this is
+ * not likely going to matter.
+ *
+ * Diane Bruce (Dianora), June 6 2003
+ */
+
+#define MAXPTRLEN 32
+ /* Must be a power of 2, and
+ * larger than 26 [a-z]|[A-Z]
+ * its used to allocate the set
+ * of pointers at each node of the tree
+ * There are MAXPTRLEN pointers at each node.
+ * Obviously, there have to be more pointers
+ * Than ASCII letters. 32 is a nice number
+ * since there is then no need to shift
+ * 'A'/'a' to base 0 index, at the expense
+ * of a few never used pointers. For a small
+ * parser like this, this is a good compromise
+ * and does make it somewhat faster.
+ *
+ * - Dianora
+ */
+
+struct MessageTree
+{
+ int links; /* Count of all pointers (including msg) at this node
+ * used as reference count for deletion of _this_ node.
+ */
+ struct Message *msg;
+ struct MessageTree *pointers[MAXPTRLEN];
+};
+
+static struct MessageTree msg_tree;
+
+/*
+ * NOTE: parse() should not be called recursively by other functions!
+ */
+static char *sender;
+static char *para[MAXPARA + 2]; /* <prefix> + <params> + NULL */
+static char buffer[1024];
+
+static int cancel_clients(struct Client *, struct Client *, char *);
+static void remove_unknown(struct Client *, char *, char *);
+static void handle_numeric(char[], struct Client *, struct Client *, int, char *[]);
+static void handle_command(struct Message *, struct Client *, struct Client *, unsigned int, char *[]);
+
+
+/*
+ * parse a buffer.
+ *
+ * NOTE: parse() should not be called recusively by any other functions!
+ */
+void
+parse(struct Client *client_p, char *pbuffer, char *bufend)
+{
+ struct Client *from = client_p;
+ struct Message *msg_ptr = NULL;
+ char *ch = NULL;
+ char *s = NULL;
+ char *numeric = NULL;
+ unsigned int parc = 0;
+ unsigned int paramcount;
+
+ if (IsDefunct(client_p))
+ return;
+
+ assert(client_p->localClient->fd.flags.open);
+ assert((bufend - pbuffer) < 512);
+
+ for (ch = pbuffer; *ch == ' '; ++ch) /* skip spaces */
+ /* null statement */ ;
+
+ if (*ch == ':')
+ {
+ /*
+ * Copy the prefix to 'sender' assuming it terminates
+ * with SPACE (or NULL, which is an error, though).
+ */
+ sender = ++ch;
+
+ if ((s = strchr(ch, ' ')) != NULL)
+ {
+ *s = '\0';
+ ch = ++s;
+ }
+
+ if (*sender && IsServer(client_p))
+ {
+ if ((from = find_person(client_p, sender)) == NULL)
+ from = hash_find_server(sender);
+
+ /* Hmm! If the client corresponding to the
+ * prefix is not found--what is the correct
+ * action??? Now, I will ignore the message
+ * (old IRC just let it through as if the
+ * prefix just wasn't there...) --msa
+ */
+ if (from == NULL)
+ {
+ ++ServerStats.is_unpf;
+ remove_unknown(client_p, sender, pbuffer);
+ return;
+ }
+
+ 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;
+ }
+
+ /* 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)))
+ {
+ numeric = ch;
+ paramcount = MAXPARA;
+ ++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
+ {
+ unsigned int ii = 0;
+
+ if ((s = strchr(ch, ' ')) != NULL)
+ *s++ = '\0';
+
+ if ((msg_ptr = find_command(ch)) == NULL)
+ {
+ /* Note: Give error message *only* to recognized
+ * persons. It's a nightmare situation to have
+ * two programs sending "Unknown command"'s or
+ * equivalent to each other at full blast....
+ * If it has got to person state, it at least
+ * seems to be well behaving. Perhaps this message
+ * should never be generated, though... --msa
+ * Hm, when is the buffer empty -- if a command
+ * code has been found ?? -Armin
+ */
+ if (*pbuffer != '\0')
+ {
+ if (IsClient(from))
+ sendto_one(from, form_str(ERR_UNKNOWNCOMMAND),
+ me.name, from->name, ch);
+ }
+
+ ++ServerStats.is_unco;
+ return;
+ }
+
+ assert(msg_ptr->cmd != NULL);
+
+ paramcount = msg_ptr->args_max;
+ ii = bufend - ((s) ? s : ch);
+ msg_ptr->bytes += ii;
+ }
+
+ /*
+ * Must the following loop really be so devious? On surface it
+ * splits the message to parameters from blank spaces. But, if
+ * paramcount has been reached, the rest of the message goes into
+ * this last parameter (about same effect as ":" has...) --msa
+ */
+
+ /* Note initially true: s==NULL || *(s-1) == '\0' !! */
+
+ para[parc] = from->name;
+
+ if (s)
+ {
+ if (paramcount > MAXPARA)
+ paramcount = MAXPARA;
+
+ while (1)
+ {
+ while (*s == ' ')
+ *s++ = '\0';
+
+ if (*s == '\0')
+ break;
+
+ if (*s == ':')
+ {
+ /* The rest is a single parameter */
+ para[++parc] = s + 1;
+ break;
+ }
+
+ para[++parc] = s;
+
+ if (parc >= paramcount)
+ break;
+
+ while (*s && *s != ' ')
+ ++s;
+ }
+ }
+
+ para[++parc] = NULL;
+
+ if (msg_ptr != NULL)
+ handle_command(msg_ptr, client_p, from, parc, para);
+ else
+ handle_numeric(numeric, client_p, from, parc, para);
+}
+
+/* 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 void
+handle_command(struct Message *mptr, struct Client *client_p,
+ struct Client *from, unsigned int i, char *hpara[])
+{
+ MessageHandler handler = 0;
+
+ if (IsServer(client_p))
+ mptr->rcount++;
+
+ mptr->count++;
+
+ handler = mptr->handlers[client_p->handler];
+
+ /* check right amount of params is passed... --is */
+ if (i < mptr->args_min)
+ {
+ if (!IsServer(client_p))
+ {
+ sendto_one(client_p, form_str(ERR_NEEDMOREPARAMS), me.name,
+ EmptyString(hpara[0]) ? "*" : hpara[0], mptr->cmd);
+ }
+ else
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Dropping server %s due to (invalid) command '%s' "
+ "with only %d arguments (expecting %d).",
+ client_p->name, mptr->cmd, i, mptr->args_min);
+ ilog(LOG_TYPE_IRCD, "Insufficient parameters (%d) for command '%s' from %s.",
+ i, mptr->cmd, client_p->name);
+ exit_client(client_p, client_p,
+ "Not enough arguments to server command.");
+ }
+ }
+ else
+ (*handler)(client_p, from, i, hpara);
+}
+
+/* add_msg_element()
+ *
+ * inputs - pointer to MessageTree
+ * - pointer to Message to add for given command
+ * - pointer to current portion of command being added
+ * output - NONE
+ * side effects - recursively build the Message Tree ;-)
+ */
+/*
+ * How this works.
+ *
+ * The code first checks to see if its reached the end of the command
+ * If so, that struct MessageTree has a msg pointer updated and the links
+ * count incremented, since a msg pointer is a reference.
+ * Then the code descends recursively, building the trie.
+ * If a pointer index inside the struct MessageTree is NULL a new
+ * child struct MessageTree has to be allocated.
+ * The links (reference count) is incremented as they are created
+ * in the parent.
+ */
+static void
+add_msg_element(struct MessageTree *mtree_p, struct Message *msg_p,
+ const char *cmd)
+{
+ struct MessageTree *ntree_p;
+
+ if (*cmd == '\0')
+ {
+ mtree_p->msg = msg_p;
+ mtree_p->links++; /* Have msg pointer, so up ref count */
+ }
+ else
+ {
+ /* *cmd & (MAXPTRLEN-1)
+ * convert the char pointed to at *cmd from ASCII to an integer
+ * between 0 and MAXPTRLEN.
+ * Thus 'A' -> 0x1 'B' -> 0x2 'c' -> 0x3 etc.
+ */
+
+ if ((ntree_p = mtree_p->pointers[*cmd & (MAXPTRLEN - 1)]) == NULL)
+ {
+ ntree_p = MyMalloc(sizeof(struct MessageTree));
+ mtree_p->pointers[*cmd & (MAXPTRLEN - 1)] = ntree_p;
+
+ mtree_p->links++; /* Have new pointer, so up ref count */
+ }
+
+ add_msg_element(ntree_p, msg_p, cmd + 1);
+ }
+}
+
+/* del_msg_element()
+ *
+ * inputs - Pointer to MessageTree to delete from
+ * - pointer to command name to delete
+ * output - NONE
+ * side effects - recursively deletes a token from the Message Tree ;-)
+ */
+/*
+ * How this works.
+ *
+ * Well, first off, the code recursively descends into the trie
+ * until it finds the terminating letter of the command being removed.
+ * Once it has done that, it marks the msg pointer as NULL then
+ * reduces the reference count on that allocated struct MessageTree
+ * since a command counts as a reference.
+ *
+ * Then it pops up the recurse stack. As it comes back up the recurse
+ * The code checks to see if the child now has no pointers or msg
+ * i.e. the links count has gone to zero. If its no longer used, the
+ * child struct MessageTree can be deleted. The parent reference
+ * to this child is then removed and the parents link count goes down.
+ * Thus, we continue to go back up removing all unused MessageTree(s)
+ */
+static void
+del_msg_element(struct MessageTree *mtree_p, const char *cmd)
+{
+ struct MessageTree *ntree_p;
+
+ /*
+ * In case this is called for a nonexistent command
+ * check that there is a msg pointer here, else links-- goes -ve
+ * -db
+ */
+ if ((*cmd == '\0') && (mtree_p->msg != NULL))
+ {
+ mtree_p->msg = NULL;
+ mtree_p->links--;
+ }
+ else
+ {
+ if ((ntree_p = mtree_p->pointers[*cmd & (MAXPTRLEN - 1)]) != NULL)
+ {
+ del_msg_element(ntree_p, cmd + 1);
+
+ if (ntree_p->links == 0)
+ {
+ mtree_p->pointers[*cmd & (MAXPTRLEN - 1)] = NULL;
+ mtree_p->links--;
+ MyFree(ntree_p);
+ }
+ }
+ }
+}
+
+/* msg_tree_parse()
+ *
+ * inputs - Pointer to command to find
+ * - Pointer to MessageTree root
+ * output - Find given command returning Message * if found NULL if not
+ * side effects - none
+ */
+static struct Message *
+msg_tree_parse(const char *cmd)
+{
+ struct MessageTree *mtree = &msg_tree;
+ assert(cmd && *cmd);
+
+ while (IsAlpha(*cmd) && (mtree = mtree->pointers[*cmd & (MAXPTRLEN - 1)]))
+ if (*++cmd == '\0')
+ return mtree->msg;
+
+ return NULL;
+}
+
+/* mod_add_cmd()
+ *
+ * inputs - 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)
+{
+ assert(msg && msg->cmd);
+
+ /* command already added? */
+ if (msg_tree_parse(msg->cmd))
+ return;
+
+ add_msg_element(&msg_tree, msg, msg->cmd);
+ msg->count = msg->rcount = msg->bytes = 0;
+}
+
+/* mod_del_cmd()
+ *
+ * inputs - pointer to struct Message
+ * output - none
+ * side effects - unload this one command name
+ */
+void
+mod_del_cmd(struct Message *msg)
+{
+ assert(msg && msg->cmd);
+
+ del_msg_element(&msg_tree, msg->cmd);
+}
+
+/* find_command()
+ *
+ * inputs - command name
+ * output - pointer to struct Message
+ * side effects - none
+ */
+struct Message *
+find_command(const char *cmd)
+{
+ return msg_tree_parse(cmd);
+}
+
+static void
+recurse_report_messages(struct Client *source_p, const struct MessageTree *mtree)
+{
+ unsigned int i;
+
+ if (mtree->msg != NULL)
+ sendto_one(source_p, form_str(RPL_STATSCOMMANDS),
+ me.name, source_p->name, mtree->msg->cmd,
+ mtree->msg->count, mtree->msg->bytes,
+ mtree->msg->rcount);
+
+ for (i = 0; i < MAXPTRLEN; ++i)
+ if (mtree->pointers[i] != NULL)
+ recurse_report_messages(source_p, mtree->pointers[i]);
+}
+
+/* report_messages()
+ *
+ * inputs - pointer to client to report to
+ * output - NONE
+ * side effects - client is shown list of commands
+ */
+void
+report_messages(struct Client *source_p)
+{
+ const struct MessageTree *mtree = &msg_tree;
+ unsigned int i;
+
+ for (i = 0; i < MAXPTRLEN; ++i)
+ if (mtree->pointers[i] != NULL)
+ recurse_report_messages(source_p, mtree->pointers[i]);
+}
+
+/* cancel_clients()
+ *
+ * inputs -
+ * output -
+ * side effects -
+ */
+static int
+cancel_clients(struct Client *client_p, struct Client *source_p, char *cmd)
+{
+ /* kill all possible points that are causing confusion here,
+ * I'm not sure I've got this all right...
+ * - avalon
+ *
+ * knowing avalon, probably not.
+ */
+
+ /* with TS, fake prefixes are a common thing, during the
+ * connect burst when there's a nick collision, and they
+ * must be ignored rather than killed because one of the
+ * two is surviving.. so we don't bother sending them to
+ * all ops everytime, as this could send 'private' stuff
+ * from lagged clients. we do send the ones that cause
+ * servers to be dropped though, as well as the ones from
+ * non-TS servers -orabidoo
+ */
+ /* Incorrect prefix for a server from some connection. If it is a
+ * client trying to be annoying, just QUIT them, if it is a server
+ * then the same deal.
+ */
+ if (IsServer(source_p) || IsMe(source_p))
+ {
+ sendto_realops_flags(UMODE_DEBUG, L_ADMIN, "Message for %s[%s] from %s",
+ source_p->name, source_p->from->name,
+ get_client_name(client_p, SHOW_IP));
+ sendto_realops_flags(UMODE_DEBUG, L_OPER, "Message for %s[%s] from %s",
+ source_p->name, source_p->from->name,
+ get_client_name(client_p, MASK_IP));
+ sendto_realops_flags(UMODE_DEBUG, L_ALL,
+ "Not dropping server %s (%s) for Fake Direction",
+ client_p->name, source_p->name);
+ return -1;
+ /* return exit_client(client_p, client_p, &me, "Fake Direction");*/
+ }
+
+ /* Ok, someone is trying to impose as a client and things are
+ * confused. If we got the wrong prefix from a server, send out a
+ * kill, else just exit the lame client.
+ */
+ /* If the fake prefix is coming from a TS server, discard it
+ * silently -orabidoo
+ *
+ * all servers must be TS these days --is
+ */
+ sendto_realops_flags(UMODE_DEBUG, L_ADMIN,
+ "Message for %s[%s@%s!%s] from %s (TS, ignored)",
+ source_p->name, source_p->username, source_p->host,
+ source_p->from->name, get_client_name(client_p, SHOW_IP));
+ sendto_realops_flags(UMODE_DEBUG, L_OPER,
+ "Message for %s[%s@%s!%s] from %s (TS, ignored)",
+ source_p->name, source_p->username, source_p->host,
+ source_p->from->name, get_client_name(client_p, MASK_IP));
+
+ return 0;
+}
+
+/* remove_unknown()
+ *
+ * inputs -
+ * output -
+ * side effects -
+ */
+static void
+remove_unknown(struct Client *client_p, char *lsender, char *lbuffer)
+{
+ /* Do kill if it came from a server because it means there is a ghost
+ * user on the other server which needs to be removed. -avalon
+ * Tell opers about this. -Taner
+ */
+ /* '[0-9]something' is an ID (KILL/SQUIT depending on its length)
+ * 'nodots' is a nickname (KILL)
+ * 'no.dot.at.start' is a server (SQUIT)
+ */
+ if ((IsDigit(*lsender) && strlen(lsender) <= IRC_MAXSID) ||
+ strchr(lsender, '.') != NULL)
+ {
+ sendto_realops_flags(UMODE_DEBUG, L_ADMIN,
+ "Unknown prefix (%s) from %s, Squitting %s",
+ lbuffer, get_client_name(client_p, SHOW_IP), lsender);
+ sendto_realops_flags(UMODE_DEBUG, L_OPER,
+ "Unknown prefix (%s) from %s, Squitting %s",
+ lbuffer, client_p->name, lsender);
+ sendto_one(client_p, ":%s SQUIT %s :(Unknown prefix (%s) from %s)",
+ me.name, lsender, lbuffer, client_p->name);
+ }
+ else
+ sendto_one(client_p, ":%s KILL %s :%s (Unknown Client)",
+ me.name, 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
+handle_numeric(char numeric[], struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *target_p;
+ struct Channel *chptr;
+ char *t; /* current position within the buffer */
+ int i, tl; /* current length of presently being built string in t */
+
+ 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)
+ */
+ t = buffer;
+ 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_person(client_p, parv[1])) != NULL) ||
+ ((target_p = hash_find_server(parv[1])) != NULL))
+ {
+ if (IsMe(target_p))
+ {
+ int num;
+
+ /*
+ * 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
+ */
+
+ /* Yes, a good compiler would have optimised this, but
+ * this is probably easier to read. -db
+ */
+ num = atoi(numeric);
+
+ if ((num != ERR_NOSUCHNICK))
+ sendto_realops_flags(UMODE_ALL, 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 */
+ if (ConfigServerHide.hide_servers &&
+ MyClient(target_p) && !HasUMode(target_p, UMODE_OPER))
+ sendto_one(target_p, ":%s %s %s%s", me.name, numeric, target_p->name, buffer);
+ else
+ sendto_one(target_p, ":%s %s %s%s", ID_or_name(source_p, target_p->from),
+ numeric, ID_or_name(target_p, target_p->from), buffer);
+ return;
+ }
+ else if ((chptr = hash_find_channel(parv[1])) != NULL)
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s %s %s %s",
+ source_p->name,
+ numeric, chptr->chname, buffer);
+}
+
+/* m_not_oper()
+ * inputs -
+ * output -
+ * side effects - just returns a nastyogram to given user
+ */
+void
+m_not_oper(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
+ me.name, source_p->name);
+}
+
+void
+m_unregistered(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ sendto_one(source_p, form_str(ERR_NOTREGISTERED), me.name,
+ source_p->name[0] ? source_p->name : "*");
+}
+
+void
+m_registered(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ sendto_one(source_p, form_str(ERR_ALREADYREGISTRED),
+ me.name, source_p->name);
+}
+
+void
+m_ignore(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ return;
+}
+
+void
+rfc1459_command_send_error(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ const char *in_para;
+
+ in_para = (parc > 1 && *parv[1] != '\0') ? parv[1] : "<>";
+
+ ilog(LOG_TYPE_IRCD, "Received ERROR message from %s: %s",
+ source_p->name, in_para);
+
+ if (client_p == source_p)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ADMIN, "ERROR :from %s -- %s",
+ get_client_name(client_p, HIDE_IP), in_para);
+ sendto_realops_flags(UMODE_ALL, L_OPER, "ERROR :from %s -- %s",
+ get_client_name(client_p, MASK_IP), in_para);
+ }
+ else
+ {
+ sendto_realops_flags(UMODE_ALL, L_OPER, "ERROR :from %s via %s -- %s",
+ source_p->name, get_client_name(client_p, MASK_IP), in_para);
+ sendto_realops_flags(UMODE_ALL, L_ADMIN, "ERROR :from %s via %s -- %s",
+ source_p->name, get_client_name(client_p, HIDE_IP), in_para);
+ }
+
+ if (MyClient(source_p))
+ exit_client(source_p, source_p, "ERROR");
+}
diff --git a/src/restart.c b/src/restart.c
new file mode 100644
index 0000000..01966a6
--- /dev/null
+++ b/src/restart.c
@@ -0,0 +1,94 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * restart.c: Functions to allow the ircd to restart.
+ *
+ * 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$
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "restart.h"
+#include "fdlist.h"
+#include "ircd.h"
+#include "irc_string.h"
+#include "send.h"
+#include "log.h"
+#include "client.h" /* for UMODE_ALL */
+#include "memory.h"
+
+void
+restart(const char *mesg)
+{
+ static int was_here = 0; /* redundant due to restarting flag below */
+
+ if (was_here++)
+ abort();
+
+ server_die(mesg, 1);
+}
+
+void
+server_die(const char *mesg, int rboot)
+{
+ char buffer[IRCD_BUFSIZE];
+ dlink_node *ptr = NULL;
+ struct Client *target_p = NULL;
+ static int was_here = 0;
+
+ if (rboot && was_here++)
+ abort();
+
+ if (EmptyString(mesg))
+ snprintf(buffer, sizeof(buffer), "Server %s",
+ rboot ? "Restarting" : "Terminating");
+ else
+ snprintf(buffer, sizeof(buffer), "Server %s: %s",
+ rboot ? "Restarting" : "Terminating", mesg);
+
+ DLINK_FOREACH(ptr, local_client_list.head)
+ {
+ target_p = ptr->data;
+
+ sendto_one(target_p, ":%s NOTICE %s :%s",
+ me.name, target_p->name, buffer);
+ }
+
+ DLINK_FOREACH(ptr, serv_list.head)
+ {
+ target_p = ptr->data;
+
+ sendto_one(target_p, ":%s ERROR :%s", me.name, buffer);
+ }
+
+ ilog(LOG_TYPE_IRCD, "%s", buffer);
+
+ send_queued_all();
+ close_fds(NULL);
+
+ unlink(pidFileName);
+
+ if (rboot)
+ {
+ execv(SPATH, myargv);
+ exit(1);
+ }
+ else
+ exit(0);
+}
diff --git a/src/resv.c b/src/resv.c
new file mode 100644
index 0000000..6f4ec14
--- /dev/null
+++ b/src/resv.c
@@ -0,0 +1,230 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * resv.c: Functions to reserve(jupe) a nick/channel.
+ *
+ * Copyright (C) 2001-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$
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "ircd.h"
+#include "send.h"
+#include "client.h"
+#include "memory.h"
+#include "numeric.h"
+#include "resv.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd_defs.h"
+#include "conf.h"
+
+dlink_list resv_channel_list = { NULL, NULL, 0 };
+
+
+/* create_channel_resv()
+ *
+ * inputs - name of channel to create resv for
+ * - reason for resv
+ * - flag, 1 for from ircd.conf 0 from elsehwere
+ * output - pointer to struct ResvChannel
+ * side effects -
+ */
+struct ConfItem *
+create_channel_resv(char *name, char *reason, int in_conf)
+{
+ struct ConfItem *conf = NULL;
+ struct ResvChannel *resv_p = NULL;
+
+ if (name == NULL || reason == NULL)
+ return NULL;
+
+ if (hash_find_resv(name))
+ return NULL;
+
+ if (strlen(reason) > REASONLEN)
+ reason[REASONLEN] = '\0';
+
+ conf = make_conf_item(CRESV_TYPE);
+ resv_p = map_to_conf(conf);
+
+ strlcpy(resv_p->name, name, sizeof(resv_p->name));
+ DupString(conf->name, name);
+ DupString(resv_p->reason, reason);
+ resv_p->conf = in_conf;
+
+ dlinkAdd(resv_p, &resv_p->node, &resv_channel_list);
+ hash_add_resv(resv_p);
+
+ return conf;
+}
+
+/* create_nick_resv()
+ *
+ * inputs - name of nick to create resv for
+ * - reason for resv
+ * - 1 if from ircd.conf, 0 if from elsewhere
+ * output - pointer to struct ResvNick
+ * side effects -
+ */
+struct ConfItem *
+create_nick_resv(char *name, char *reason, int in_conf)
+{
+ struct ConfItem *conf = NULL;
+ struct MatchItem *resv_p = NULL;
+
+ if (name == NULL || reason == NULL)
+ return NULL;
+
+ if (find_matching_name_conf(NRESV_TYPE, name, NULL, NULL, 0))
+ return NULL;
+
+ if (strlen(reason) > REASONLEN)
+ reason[REASONLEN] = '\0';
+
+ conf = make_conf_item(NRESV_TYPE);
+ resv_p = map_to_conf(conf);
+
+ DupString(conf->name, name);
+ DupString(resv_p->reason, reason);
+ resv_p->action = in_conf;
+
+ return conf;
+}
+
+/* clear_conf_resv()
+ *
+ * inputs - none
+ * output - none
+ * side effects - All resvs are cleared out
+ */
+void
+clear_conf_resv(void)
+{
+ dlink_node *ptr = NULL, *next_ptr = NULL;
+
+ DLINK_FOREACH_SAFE(ptr, next_ptr, resv_channel_list.head)
+ delete_channel_resv(ptr->data);
+}
+
+/* delete_channel_resv()
+ *
+ * inputs - pointer to channel resv to delete
+ * output - none
+ * side effects - given struct ResvChannel * is removed
+ */
+int
+delete_channel_resv(struct ResvChannel *resv_p)
+{
+ struct ConfItem *conf = NULL;
+ assert(resv_p != NULL);
+
+ hash_del_resv(resv_p);
+ dlinkDelete(&resv_p->node, &resv_channel_list);
+ MyFree(resv_p->reason);
+ conf = unmap_conf_item(resv_p);
+ delete_conf_item(conf);
+
+ return 1;
+}
+
+/* match_find_resv()
+ *
+ * inputs - pointer to name
+ * output - pointer to a struct ResvChannel
+ * side effects - Finds a reserved channel whose name matches 'name',
+ * if can't find one returns NULL.
+ */
+struct ResvChannel *
+match_find_resv(const char *name)
+{
+ dlink_node *ptr = NULL;
+
+ if (EmptyString(name))
+ return NULL;
+
+ DLINK_FOREACH(ptr, resv_channel_list.head)
+ {
+ struct ResvChannel *chptr = ptr->data;
+
+ if (match_chan(name, chptr->name))
+ return chptr;
+ }
+
+ return NULL;
+}
+
+/* report_resv()
+ *
+ * inputs - pointer to client pointer to report to.
+ * output - NONE
+ * side effects - report all resvs to client.
+ */
+void
+report_resv(struct Client *source_p)
+{
+ dlink_node *ptr;
+ struct ConfItem *conf;
+ struct ResvChannel *resv_cp;
+ struct MatchItem *resv_np;
+
+ DLINK_FOREACH(ptr, resv_channel_list.head)
+ {
+ resv_cp = ptr->data;
+ sendto_one(source_p, form_str(RPL_STATSQLINE),
+ me.name, source_p->name,
+ resv_cp->conf ? 'Q' : 'q',
+ resv_cp->name, resv_cp->reason);
+ }
+
+ DLINK_FOREACH(ptr, nresv_items.head)
+ {
+ conf = ptr->data;
+ resv_np = map_to_conf(conf);
+
+ sendto_one(source_p, form_str(RPL_STATSQLINE),
+ me.name, source_p->name,
+ resv_np->action ? 'Q' : 'q',
+ conf->name, resv_np->reason);
+ }
+}
+
+/* valid_wild_card_simple()
+ *
+ * inputs - data to check for sufficient non-wildcard characters
+ * outputs - 1 if valid, else 0
+ * side effects - none
+ */
+int
+valid_wild_card_simple(const char *data)
+{
+ const unsigned char *p = (const unsigned char *)data;
+ int nonwild = 0;
+
+ while (*p != '\0')
+ {
+ if ((*p == '\\' && *++p) || (*p && !IsMWildChar(*p)))
+ if (++nonwild == ConfigFileEntry.min_nonwildcard_simple)
+ return 1;
+ if (*p != '\0')
+ ++p;
+ }
+
+ return 0;
+}
diff --git a/src/rng_mt.c b/src/rng_mt.c
new file mode 100644
index 0000000..dacc11f
--- /dev/null
+++ b/src/rng_mt.c
@@ -0,0 +1,167 @@
+/*
+ A C-program for MT19937, with initialization improved 2002/1/26.
+ Coded by Takuji Nishimura and Makoto Matsumoto.
+
+ Before using, initialize the state by using init_genrand(seed)
+ or init_by_array(init_key, key_length).
+
+ Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
+ 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 names of its contributors may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+
+
+ Any feedback is very welcome.
+ http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+ email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
+
+ $Id$
+*/
+
+#include "stdinc.h"
+#include "rng_mt.h"
+
+/* Period parameters */
+#define N 624
+#define M 397
+#define MATRIX_A 0x9908b0dfU /* constant vector a */
+#define UPPER_MASK 0x80000000U /* most significant w-r bits */
+#define LOWER_MASK 0x7fffffffU /* least significant r bits */
+
+static uint32_t mt[N]; /* the array for the state vector */
+static int mti = N + 1; /* mti==N+1 means mt[N] is not initialized */
+
+/* initializes mt[N] with a seed */
+void
+init_genrand(uint32_t s)
+{
+ mt[0] = s & 0xffffffffU;
+
+ for (mti = 1; mti < N; mti++)
+ {
+ mt[mti] = (1812433253U * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + mti);
+ /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
+ /* In the previous versions, MSBs of the seed affect */
+ /* only MSBs of the array mt[]. */
+ /* 2002/01/09 modified by Makoto Matsumoto */
+ mt[mti] &= 0xffffffffU;
+ /* for >32 bit machines */
+ }
+}
+
+/* initialize by an array with array-length */
+/* init_key is the array for initializing keys */
+/* key_length is its length */
+/* slight change for C++, 2004/2/26 */
+void
+init_by_array(uint32_t init_key[], int key_length)
+{
+ int i, j, k;
+
+ init_genrand(19650218U);
+
+ i = 1; j = 0;
+ k = (N > key_length ? N : key_length);
+
+ for (; k; k--)
+ {
+ mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1664525U))
+ + init_key[j] + j; /* non linear */
+ mt[i] &= 0xffffffffU; /* for WORDSIZE > 32 machines */
+ i++; j++;
+
+ if (i >= N)
+ {
+ mt[0] = mt[N - 1];
+ i = 1;
+ }
+
+ if (j >= key_length)
+ j = 0;
+ }
+
+ for (k = N - 1; k; k--)
+ {
+ mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1566083941U))
+ - i; /* non linear */
+ mt[i] &= 0xffffffffU; /* for WORDSIZE > 32 machines */
+ i++;
+
+ if (i >= N)
+ {
+ mt[0] = mt[N - 1];
+ i = 1;
+ }
+ }
+
+ mt[0] = 0x80000000U; /* MSB is 1; assuring non-zero initial array */
+}
+
+/* generates a random number on [0,0xffffffff]-interval */
+uint32_t
+genrand_int32(void)
+{
+ uint32_t y;
+ static uint32_t mag01[2]={ 0x0U, MATRIX_A };
+ /* mag01[x] = x * MATRIX_A for x=0,1 */
+
+ if (mti >= N)
+ { /* generate N words at one time */
+ int kk;
+
+ if (mti == N + 1) /* if init_genrand() has not been called, */
+ init_genrand(5489U); /* a default initial seed is used */
+
+ for (kk = 0; kk < N - M; kk++)
+ {
+ y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
+ mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1U];
+ }
+
+ for (; kk < N - 1; kk++)
+ {
+ y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
+ mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1U];
+ }
+
+ y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+ mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1U];
+
+ mti = 0;
+ }
+
+ y = mt[mti++];
+
+ /* Tempering */
+ y ^= (y >> 11);
+ y ^= (y << 7) & 0x9d2c5680U;
+ y ^= (y << 15) & 0xefc60000U;
+ y ^= (y >> 18);
+
+ return y;
+}
diff --git a/src/rsa.c b/src/rsa.c
new file mode 100644
index 0000000..8623ae0
--- /dev/null
+++ b/src/rsa.c
@@ -0,0 +1,120 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * rsa.c: Functions for use with RSA public key cryptography.
+ *
+ * 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$
+ */
+
+#include "stdinc.h"
+#ifdef HAVE_LIBCRYPTO
+#include <openssl/pem.h>
+#include <openssl/rand.h>
+#include <openssl/rsa.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/opensslv.h>
+
+#include "memory.h"
+#include "rsa.h"
+#include "conf.h"
+#include "log.h"
+
+
+/*
+ * report_crypto_errors - Dump crypto error list to log
+ */
+void
+report_crypto_errors(void)
+{
+ unsigned long e = 0;
+ unsigned long cnt = 0;
+
+ while ((cnt < 100) && (e = ERR_get_error()))
+ {
+ ilog(LOG_TYPE_IRCD, "SSL error: %s", ERR_error_string(e, 0));
+ cnt++;
+ }
+}
+
+static void
+binary_to_hex(unsigned char *bin, char *hex, int length)
+{
+ static const char trans[] = "0123456789ABCDEF";
+ int i;
+
+ for (i = 0; i < length; i++)
+ {
+ hex[i << 1] = trans[bin[i] >> 4];
+ hex[(i << 1) + 1] = trans[bin[i] & 0xf];
+ }
+
+ hex[i << 1] = '\0';
+}
+
+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())
+ return (RAND_bytes(buf, length));
+ else /* XXX - abort? */
+ return (RAND_pseudo_bytes(buf, length));
+}
+
+int
+generate_challenge(char **r_challenge, char **r_response, RSA *rsa)
+{
+ unsigned char secret[32], *tmp;
+ unsigned long length;
+ int ret = -1;
+
+ if (!rsa)
+ return -1;
+
+ get_randomness(secret, 32);
+ *r_response = MyMalloc(65);
+ binary_to_hex(secret, *r_response, 32);
+
+ length = RSA_size(rsa);
+ tmp = MyMalloc(length);
+ ret = RSA_public_encrypt(32, secret, tmp, rsa, RSA_PKCS1_PADDING);
+
+ *r_challenge = MyMalloc((length << 1) + 1);
+ binary_to_hex( tmp, *r_challenge, length);
+ (*r_challenge)[length<<1] = 0;
+ MyFree(tmp);
+
+ if (ret < 0)
+ {
+ report_crypto_errors();
+ return -1;
+ }
+
+ return 0;
+}
+#endif
diff --git a/src/s_auth.c b/src/s_auth.c
new file mode 100644
index 0000000..c14cb22
--- /dev/null
+++ b/src/s_auth.c
@@ -0,0 +1,598 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * s_auth.c: Functions for querying a users ident.
+ *
+ * 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$
+ */
+
+/*
+ * 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 "list.h"
+#include "ircd_defs.h"
+#include "fdlist.h"
+#include "s_auth.h"
+#include "conf.h"
+#include "balloc.h"
+#include "client.h"
+#include "event.h"
+#include "hook.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "packet.h"
+#include "irc_res.h"
+#include "s_bsd.h"
+#include "log.h"
+#include "send.h"
+
+
+static const char *HeaderMessages[] = {
+ ":%s NOTICE AUTH :*** Looking up your hostname...",
+ ":%s NOTICE AUTH :*** Found your hostname",
+ ":%s NOTICE AUTH :*** Couldn't look up your hostname",
+ ":%s NOTICE AUTH :*** Checking Ident",
+ ":%s NOTICE AUTH :*** Got Ident response",
+ ":%s NOTICE AUTH :*** No Ident response",
+ ":%s NOTICE AUTH :*** Your forward and reverse DNS do not match, ignoring hostname.",
+ ":%s NOTICE AUTH :*** Your hostname is too long, ignoring hostname"
+};
+
+enum {
+ REPORT_DO_DNS,
+ REPORT_FIN_DNS,
+ REPORT_FAIL_DNS,
+ REPORT_DO_ID,
+ REPORT_FIN_ID,
+ REPORT_FAIL_ID,
+ REPORT_IP_MISMATCH,
+ REPORT_HOST_TOOLONG
+};
+
+#define sendheader(c, i) sendto_one((c), HeaderMessages[(i)], me.name)
+
+static BlockHeap *auth_heap = NULL;
+static dlink_list auth_doing_list = { NULL, NULL, 0 };
+
+static EVH timeout_auth_queries_event;
+
+static PF read_auth_reply;
+static CNCB auth_connect_callback;
+static CBFUNC start_auth;
+
+struct Callback *auth_cb = NULL;
+
+/* init_auth()
+ *
+ * Initialise the auth code
+ */
+void
+init_auth(void)
+{
+ auth_heap = BlockHeapCreate("auth", sizeof(struct AuthRequest), AUTH_HEAP_SIZE);
+ auth_cb = register_callback("start_auth", start_auth);
+ eventAddIsh("timeout_auth_queries_event", timeout_auth_queries_event, NULL, 1);
+}
+
+/*
+ * 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->client = client;
+ request->timeout = CurrentTime + CONNECTTIMEOUT;
+
+ return 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
+ */
+void
+release_auth_client(struct AuthRequest *auth)
+{
+ struct Client *client = auth->client;
+
+ if (IsDoingAuth(auth) || IsDNSPending(auth))
+ return;
+
+ client->localClient->auth = NULL;
+ dlinkDelete(&auth->node, &auth_doing_list);
+ BlockHeapFree(auth_heap, auth);
+
+ /*
+ * 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);
+
+ dlinkAdd(client, &client->node, &global_client_list);
+
+ client->localClient->since = CurrentTime;
+ client->localClient->lasttime = CurrentTime;
+ client->localClient->firsttime = CurrentTime;
+ client->flags |= FLAGS_FINISHED_AUTH;
+
+ read_packet(&client->localClient->fd, client);
+}
+
+/*
+ * auth_dns_callback - called when resolver query finishes
+ * if the query resulted in a successful search, name will contain
+ * a non-NULL pointer, otherwise name 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, const struct irc_ssaddr *addr, const char *name)
+{
+ struct AuthRequest *auth = vptr;
+
+ ClearDNSPending(auth);
+
+ if (name != NULL)
+ {
+ const struct sockaddr_in *v4, *v4dns;
+#ifdef IPV6
+ const struct sockaddr_in6 *v6, *v6dns;
+#endif
+ int good = 1;
+
+#ifdef IPV6
+ if (auth->client->localClient->ip.ss.ss_family == AF_INET6)
+ {
+ v6 = (const struct sockaddr_in6 *)&auth->client->localClient->ip;
+ v6dns = (const struct sockaddr_in6 *)addr;
+ if (memcmp(&v6->sin6_addr, &v6dns->sin6_addr, sizeof(struct in6_addr)) != 0)
+ {
+ sendheader(auth->client, REPORT_IP_MISMATCH);
+ good = 0;
+ }
+ }
+ else
+#endif
+ {
+ v4 = (const struct sockaddr_in *)&auth->client->localClient->ip;
+ v4dns = (const struct sockaddr_in *)addr;
+ if(v4->sin_addr.s_addr != v4dns->sin_addr.s_addr)
+ {
+ sendheader(auth->client, REPORT_IP_MISMATCH);
+ good = 0;
+ }
+ }
+ if (good && strlen(name) <= HOSTLEN)
+ {
+ strlcpy(auth->client->host, name,
+ sizeof(auth->client->host));
+ sendheader(auth->client, REPORT_FIN_DNS);
+ }
+ else if (strlen(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;
+
+ fd_close(&auth->fd);
+
+ 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_ssaddr localaddr;
+ socklen_t locallen = sizeof(struct irc_ssaddr);
+#ifdef IPV6
+ struct sockaddr_in6 *v6;
+#else
+ struct sockaddr_in *v4;
+#endif
+
+ /* open a socket of the same type as the client socket */
+ if (comm_open(&auth->fd, auth->client->localClient->ip.ss.ss_family,
+ SOCK_STREAM, 0, "ident") == -1)
+ {
+ report_error(L_ALL, "creating auth stream socket %s:%s",
+ get_client_name(auth->client, SHOW_IP), errno);
+ ilog(LOG_TYPE_IRCD, "Unable to create auth socket for %s",
+ get_client_name(auth->client, SHOW_IP));
+ ++ServerStats.is_abad;
+ 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.fd, (struct sockaddr*)&localaddr,
+ &locallen);
+
+#ifdef IPV6
+ remove_ipv6_mapping(&localaddr);
+ v6 = (struct sockaddr_in6 *)&localaddr;
+ v6->sin6_port = htons(0);
+#else
+ localaddr.ss_len = locallen;
+ v4 = (struct sockaddr_in *)&localaddr;
+ v4->sin_port = htons(0);
+#endif
+ localaddr.ss_port = htons(0);
+
+ comm_connect_tcp(&auth->fd, auth->client->sockhost, 113,
+ (struct sockaddr *)&localaddr, localaddr.ss_len, auth_connect_callback,
+ auth, auth->client->localClient->ip.ss.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 -
+ */
+/*
+ * A few questions have been asked about this mess, obviously
+ * it should have been commented better the first time.
+ * The original idea was to remove all references to libc from ircd-hybrid.
+ * Instead of having to write a replacement for sscanf(), I did a
+ * rather gruseome parser here so we could remove this function call.
+ * Note, that I had also removed a few floating point printfs as well (though
+ * now we are still stuck with a few...)
+ * Remember, we have a replacement ircd sprintf, we have bleeps fputs lib
+ * it would have been nice to remove some unneeded code.
+ * Oh well. If we don't remove libc stuff totally, then it would be
+ * far cleaner to use sscanf()
+ *
+ * - Dianora
+ */
+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;
+
+ if ((colon1Ptr = strchr(remotePortString,':')) == NULL)
+ return 0;
+ *colon1Ptr = '\0';
+ colon1Ptr++;
+
+ if ((colon2Ptr = strchr(colon1Ptr,':')) == NULL)
+ return 0;
+ *colon2Ptr = '\0';
+ colon2Ptr++;
+
+ if ((commaPtr = strchr(remotePortString, ',')) == NULL)
+ return 0;
+ *commaPtr = '\0';
+ commaPtr++;
+
+ if ((remp = atoi(remotePortString)) == 0)
+ return 0;
+
+ if ((locp = atoi(commaPtr)) == 0)
+ return 0;
+
+ /* look for USERID bordered by first pair of colons */
+ if (strstr(colon1Ptr, "USERID") == NULL)
+ return 0;
+
+ if ((colon3Ptr = strchr(colon2Ptr,':')) == NULL)
+ return 0;
+ *colon3Ptr = '\0';
+ colon3Ptr++;
+ return (colon3Ptr);
+}
+
+/*
+ * start_auth
+ *
+ * inputs - pointer to client to auth
+ * output - NONE
+ * side effects - starts auth (identd) and dns queries for a client
+ */
+static void *
+start_auth(va_list args)
+{
+ struct Client *client = va_arg(args, struct Client *);
+ struct AuthRequest *auth = NULL;
+
+ assert(client != NULL);
+
+ auth = make_auth_request(client);
+ dlinkAdd(auth, &auth->node, &auth_doing_list);
+
+ sendheader(client, REPORT_DO_DNS);
+
+ SetDNSPending(auth);
+
+ if (ConfigFileEntry.disable_auth == 0)
+ {
+ SetDoingAuth(auth);
+ start_auth_query(auth);
+ }
+
+ gethost_byaddr(auth_dns_callback, auth, &client->localClient->ip);
+
+ return NULL;
+}
+
+/*
+ * 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 = NULL, *next_ptr = NULL;
+
+ DLINK_FOREACH_SAFE(ptr, next_ptr, auth_doing_list.head)
+ {
+ struct AuthRequest *auth = ptr->data;
+
+ if (auth->timeout > CurrentTime)
+ continue;
+
+ if (IsDoingAuth(auth))
+ {
+ ++ServerStats.is_abad;
+ fd_close(&auth->fd);
+ ClearAuth(auth);
+ sendheader(auth->client, REPORT_FAIL_ID);
+ }
+
+ if (IsDNSPending(auth))
+ {
+ delete_resolver_queries(auth);
+ ClearDNSPending(auth);
+ sendheader(auth->client, REPORT_FAIL_DNS);
+ }
+
+ ilog(LOG_TYPE_IRCD, "DNS/AUTH timeout %s",
+ get_client_name(auth->client, SHOW_IP));
+ 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(fde_t *fd, int error, void *data)
+{
+ struct AuthRequest *auth = data;
+ struct irc_ssaddr us;
+ struct irc_ssaddr them;
+ char authbuf[32];
+ socklen_t ulen = sizeof(struct irc_ssaddr);
+ socklen_t tlen = sizeof(struct irc_ssaddr);
+ uint16_t uport, tport;
+#ifdef IPV6
+ struct sockaddr_in6 *v6;
+#else
+ struct sockaddr_in *v4;
+#endif
+
+ if (error != COMM_OK)
+ {
+ auth_error(auth);
+ return;
+ }
+
+ if (getsockname(auth->client->localClient->fd.fd, (struct sockaddr *)&us,
+ &ulen) ||
+ getpeername(auth->client->localClient->fd.fd, (struct sockaddr *)&them,
+ &tlen))
+ {
+ ilog(LOG_TYPE_IRCD, "auth get{sock,peer}name error for %s",
+ get_client_name(auth->client, SHOW_IP));
+ auth_error(auth);
+ return;
+ }
+
+#ifdef IPV6
+ v6 = (struct sockaddr_in6 *)&us;
+ uport = ntohs(v6->sin6_port);
+ v6 = (struct sockaddr_in6 *)&them;
+ tport = ntohs(v6->sin6_port);
+ remove_ipv6_mapping(&us);
+ remove_ipv6_mapping(&them);
+#else
+ v4 = (struct sockaddr_in *)&us;
+ uport = ntohs(v4->sin_port);
+ v4 = (struct sockaddr_in *)&them;
+ tport = ntohs(v4->sin_port);
+ us.ss_len = ulen;
+ them.ss_len = tlen;
+#endif
+
+ snprintf(authbuf, sizeof(authbuf), "%u , %u\r\n", tport, uport);
+
+ if (send(fd->fd, authbuf, strlen(authbuf), 0) == -1)
+ {
+ auth_error(auth);
+ return;
+ }
+
+ 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(fde_t *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 */
+
+ /* Why?
+ * Well, recv() on many POSIX systems is a per-packet operation,
+ * and we do not necessarily want this, because on lowspec machines,
+ * the ident response may come back fragmented, thus resulting in an
+ * invalid ident response, even if the ident response was really OK.
+ *
+ * So PLEASE do not change this code to recv without being aware of the
+ * consequences.
+ *
+ * --nenolod
+ */
+ len = read(fd->fd, buf, AUTH_BUFSIZ);
+
+ if (len < 0)
+ {
+ if (ignoreErrno(errno))
+ comm_setselect(fd, COMM_SELECT_READ, read_auth_reply, auth, 0);
+ else
+ auth_error(auth);
+ 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';
+ }
+ }
+
+ fd_close(fd);
+
+ ClearAuth(auth);
+
+ if (s == NULL)
+ {
+ sendheader(auth->client, REPORT_FAIL_ID);
+ ++ServerStats.is_abad;
+ }
+ else
+ {
+ sendheader(auth->client, REPORT_FIN_ID);
+ ++ServerStats.is_asuc;
+ SetGotId(auth->client);
+ }
+
+ release_auth_client(auth);
+}
+
+/*
+ * delete_auth()
+ */
+void
+delete_auth(struct AuthRequest *auth)
+{
+ if (IsDNSPending(auth))
+ delete_resolver_queries(auth);
+
+ if (IsDoingAuth(auth))
+ fd_close(&auth->fd);
+
+ dlinkDelete(&auth->node, &auth_doing_list);
+ BlockHeapFree(auth_heap, auth);
+}
diff --git a/src/s_bsd.c b/src/s_bsd.c
new file mode 100644
index 0000000..316d3f4
--- /dev/null
+++ b/src/s_bsd.c
@@ -0,0 +1,757 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * s_bsd.c: Network functions.
+ *
+ * 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$
+ */
+
+#include "stdinc.h"
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include "list.h"
+#include "fdlist.h"
+#include "s_bsd.h"
+#include "client.h"
+#include "dbuf.h"
+#include "event.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "listener.h"
+#include "numeric.h"
+#include "packet.h"
+#include "irc_res.h"
+#include "restart.h"
+#include "s_auth.h"
+#include "conf.h"
+#include "log.h"
+#include "s_serv.h"
+#include "send.h"
+#include "memory.h"
+#include "s_user.h"
+#include "hook.h"
+
+static const char *comm_err_str[] = { "Comm OK", "Error during bind()",
+ "Error during DNS lookup", "connect timeout", "Error during connect()",
+ "Comm Error" };
+
+struct Callback *setup_socket_cb = NULL;
+
+static void comm_connect_callback(fde_t *, int);
+static PF comm_connect_timeout;
+static void comm_connect_dns_callback(void *, const struct irc_ssaddr *, const char *);
+static PF comm_connect_tryconnect;
+
+
+/* check_can_use_v6()
+ * Check if the system can open AF_INET6 sockets
+ */
+void
+check_can_use_v6(void)
+{
+#ifdef IPV6
+ int v6;
+
+ if ((v6 = socket(AF_INET6, SOCK_STREAM, 0)) < 0)
+ ServerInfo.can_use_v6 = 0;
+ else
+ {
+ ServerInfo.can_use_v6 = 1;
+ close(v6);
+ }
+#else
+ ServerInfo.can_use_v6 = 0;
+#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
+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, &err, &len))
+ {
+ if (err)
+ errtmp = err;
+ }
+ errno = errtmp;
+#endif
+ return errtmp;
+}
+
+/*
+ * 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(int level, const char* text, const char* who, int error)
+{
+ who = (who) ? who : "";
+
+ sendto_realops_flags(UMODE_DEBUG, level, text, who, strerror(error));
+ ilog(LOG_TYPE_IRCD, text, who, strerror(error));
+}
+
+/*
+ * setup_socket()
+ *
+ * Set the socket non-blocking, and other wonderful bits.
+ */
+static void *
+setup_socket(va_list args)
+{
+ int fd = va_arg(args, int);
+ int opt = 1;
+
+ setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
+
+#ifdef IPTOS_LOWDELAY
+ opt = IPTOS_LOWDELAY;
+ setsockopt(fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt));
+#endif
+
+ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
+
+ return NULL;
+}
+
+/*
+ * init_comm()
+ *
+ * Initializes comm subsystem.
+ */
+void
+init_comm(void)
+{
+ setup_socket_cb = register_callback("setup_socket", setup_socket);
+ init_netio();
+}
+
+/*
+ * 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)
+{
+ struct AccessItem *aconf;
+ struct ClassItem *aclass;
+ dlink_node *ptr = NULL;
+
+ assert(client_p);
+
+ if (!IsDead(client_p))
+ {
+ /* attempt to flush any pending dbufs. Evil, but .. -- adrian */
+ /* there is still a chance that we might send data to this socket
+ * even if it is marked as blocked (COMM_SELECT_READ handler is called
+ * before COMM_SELECT_WRITE). Let's try, nothing to lose.. -adx
+ */
+ ClearSendqBlocked(client_p);
+ send_queued_write(client_p);
+ }
+
+ if (IsClient(client_p))
+ {
+ ++ServerStats.is_cl;
+ ServerStats.is_cbs += client_p->localClient->send.bytes;
+ ServerStats.is_cbr += client_p->localClient->recv.bytes;
+ ServerStats.is_cti += CurrentTime - client_p->localClient->firsttime;
+ }
+ else if (IsServer(client_p))
+ {
+ ++ServerStats.is_sv;
+ ServerStats.is_sbs += client_p->localClient->send.bytes;
+ ServerStats.is_sbr += client_p->localClient->recv.bytes;
+ ServerStats.is_sti += CurrentTime - client_p->localClient->firsttime;
+
+ DLINK_FOREACH(ptr, server_items.head)
+ {
+ struct ConfItem *conf = ptr->data;
+
+ if (irccmp(conf->name, client_p->name))
+ continue;
+
+ /*
+ * Reset next-connect cycle of all connect{} blocks that match
+ * this servername.
+ */
+ aconf = map_to_conf(conf);
+ aclass = map_to_conf(aconf->class_ptr);
+ aconf->hold = CurrentTime + aclass->con_freq;
+ }
+ }
+ else
+ ++ServerStats.is_ni;
+
+#ifdef HAVE_LIBCRYPTO
+ if (client_p->localClient->fd.ssl)
+ {
+ SSL_set_shutdown(client_p->localClient->fd.ssl, SSL_RECEIVED_SHUTDOWN);
+
+ if (!SSL_shutdown(client_p->localClient->fd.ssl))
+ SSL_shutdown(client_p->localClient->fd.ssl);
+ }
+#endif
+ if (client_p->localClient->fd.flags.open)
+ fd_close(&client_p->localClient->fd);
+
+ dbuf_clear(&client_p->localClient->buf_sendq);
+ dbuf_clear(&client_p->localClient->buf_recvq);
+
+ MyFree(client_p->localClient->passwd);
+ detach_conf(client_p, CONF_TYPE);
+ client_p->from = NULL; /* ...this should catch them! >:) --msa */
+}
+
+#ifdef HAVE_LIBCRYPTO
+/*
+ * ssl_handshake - let OpenSSL initialize the protocol. Register for
+ * read/write events if necessary.
+ */
+static void
+ssl_handshake(int fd, struct Client *client_p)
+{
+ int ret = SSL_accept(client_p->localClient->fd.ssl);
+
+ if (ret <= 0)
+ switch (SSL_get_error(client_p->localClient->fd.ssl, ret))
+ {
+ case SSL_ERROR_WANT_WRITE:
+ comm_setselect(&client_p->localClient->fd, COMM_SELECT_WRITE,
+ (PF *) ssl_handshake, client_p, 0);
+ return;
+
+ case SSL_ERROR_WANT_READ:
+ comm_setselect(&client_p->localClient->fd, COMM_SELECT_READ,
+ (PF *) ssl_handshake, client_p, 0);
+ return;
+
+ default:
+ exit_client(client_p, client_p, "Error during SSL handshake");
+ return;
+ }
+
+ execute_callback(auth_cb, client_p);
+}
+#endif
+
+/*
+ * 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.
+ * An unique id is calculated now, in case it is needed for auth.
+ * The client is sent to the auth module for verification, and not put in
+ * any client list yet.
+ */
+void
+add_connection(struct Listener *listener, struct irc_ssaddr *irn, int fd)
+{
+ struct Client *new_client = make_client(NULL);
+
+ fd_open(&new_client->localClient->fd, fd, 1,
+ (listener->flags & LISTENER_SSL) ?
+ "Incoming SSL connection" : "Incoming connection");
+
+ /*
+ * copy address to 'sockhost' as a string, copy it to host too
+ * so we have something valid to put into error messages...
+ */
+ memcpy(&new_client->localClient->ip, irn, sizeof(struct irc_ssaddr));
+
+ getnameinfo((struct sockaddr *)&new_client->localClient->ip,
+ new_client->localClient->ip.ss_len, new_client->sockhost,
+ sizeof(new_client->sockhost), NULL, 0, NI_NUMERICHOST);
+ new_client->localClient->aftype = new_client->localClient->ip.ss.ss_family;
+
+ if (new_client->sockhost[0] == ':' && new_client->sockhost[1] == ':')
+ {
+ strlcpy(new_client->host, "0", sizeof(new_client->host));
+ strlcpy(new_client->host+1, new_client->sockhost, sizeof(new_client->host)-1);
+ memmove(new_client->sockhost+1, new_client->sockhost, sizeof(new_client->sockhost)-1);
+ new_client->sockhost[0] = '0';
+ }
+ else
+ strlcpy(new_client->host, new_client->sockhost, sizeof(new_client->host));
+
+ new_client->localClient->listener = listener;
+ ++listener->ref_count;
+
+#ifdef HAVE_LIBCRYPTO
+ if (listener->flags & LISTENER_SSL)
+ {
+ if ((new_client->localClient->fd.ssl = SSL_new(ServerInfo.server_ctx)) == NULL)
+ {
+ ilog(LOG_TYPE_IRCD, "SSL_new() ERROR! -- %s",
+ ERR_error_string(ERR_get_error(), NULL));
+
+ SetDead(new_client);
+ exit_client(new_client, new_client, "SSL_new failed");
+ return;
+ }
+
+ SSL_set_fd(new_client->localClient->fd.ssl, fd);
+ ssl_handshake(0, new_client);
+ }
+ else
+#endif
+ execute_callback(auth_cb, new_client);
+}
+
+/*
+ * 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(fde_t *fd, time_t timeout, PF *callback, void *cbdata)
+{
+ assert(fd->flags.open);
+
+ fd->timeout = CurrentTime + (timeout / 1000);
+ fd->timeout_handler = callback;
+ fd->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 separate, 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 ..
+ * -- originally Adrian's notes
+ * comm_close() is replaced with fd_close() in fdlist.c
+ */
+void
+comm_setflush(fde_t *fd, time_t timeout, PF *callback, void *cbdata)
+{
+ assert(fd->flags.open);
+
+ fd->flush_timeout = CurrentTime + (timeout / 1000);
+ fd->flush_handler = callback;
+ fd->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 i;
+ fde_t *F;
+ PF *hdl;
+ void *data;
+
+ for (i = 0; i < FD_HASH_SIZE; i++)
+ for (F = fd_hash[i]; F != NULL; F = fd_next_in_loop)
+ {
+ assert(F->flags.open);
+ fd_next_in_loop = F->hnext;
+
+ /* 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, 0, NULL, NULL);
+ hdl(F, 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, 0, NULL, NULL);
+ hdl(F, data);
+ }
+ }
+}
+
+/*
+ * void comm_connect_tcp(int fd, const char *host, unsigned 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(fde_t *fd, const char *host, unsigned short port,
+ struct sockaddr *clocal, int socklen, CNCB *callback,
+ void *data, int aftype, int timeout)
+{
+ struct addrinfo hints, *res;
+ char portname[PORTNAMELEN + 1];
+
+ assert(callback);
+ fd->connect.callback = callback;
+ fd->connect.data = data;
+
+ fd->connect.hostaddr.ss.ss_family = aftype;
+ fd->connect.hostaddr.ss_port = htons(port);
+
+ /* 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(fd->fd, clocal, socklen) < 0))
+ {
+ /* Failure, call the callback with COMM_ERR_BIND */
+ comm_connect_callback(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().
+ */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
+
+ snprintf(portname, sizeof(portname), "%d", port);
+
+ if (getaddrinfo(host, portname, &hints, &res))
+ {
+ /* Send the DNS request, for the next level */
+ if (aftype == AF_INET6)
+ gethost_byname_type(comm_connect_dns_callback, fd, host, T_AAAA);
+ else
+ gethost_byname_type(comm_connect_dns_callback, fd, host, T_A);
+ }
+ else
+ {
+ /* We have a valid IP, so we just call tryconnect */
+ /* Make sure we actually set the timeout here .. */
+ assert(res != NULL);
+ memcpy(&fd->connect.hostaddr, res->ai_addr, res->ai_addrlen);
+ fd->connect.hostaddr.ss_len = res->ai_addrlen;
+ fd->connect.hostaddr.ss.ss_family = res->ai_family;
+ freeaddrinfo(res);
+ comm_settimeout(fd, timeout*1000, comm_connect_timeout, NULL);
+ comm_connect_tryconnect(fd, NULL);
+ }
+}
+
+/*
+ * comm_connect_callback() - call the callback, and continue with life
+ */
+static void
+comm_connect_callback(fde_t *fd, int status)
+{
+ CNCB *hdl;
+
+ /* This check is gross..but probably necessary */
+ if (fd->connect.callback == NULL)
+ return;
+
+ /* Clear the connect flag + handler */
+ hdl = fd->connect.callback;
+ fd->connect.callback = NULL;
+
+ /* Clear the timeout handler */
+ comm_settimeout(fd, 0, NULL, NULL);
+
+ /* Call the handler */
+ hdl(fd, status, fd->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(fde_t *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, const struct irc_ssaddr *addr, const char *name)
+{
+ fde_t *F = vptr;
+
+ if (name == NULL)
+ {
+ comm_connect_callback(F, COMM_ERR_DNS);
+ return;
+ }
+
+ /* No error, set a 10 second timeout */
+ comm_settimeout(F, 30*1000, comm_connect_timeout, NULL);
+
+ /* Copy over the DNS reply info so we can use it in the connect() */
+ /*
+ * Note we don't fudge the refcount here, because we aren't keeping
+ * the DNS record around, and the DNS cache is gone anyway..
+ * -- adrian
+ */
+ memcpy(&F->connect.hostaddr, addr, addr->ss_len);
+ /* The cast is hacky, but safe - port offset is same on v4 and v6 */
+ ((struct sockaddr_in *) &F->connect.hostaddr)->sin_port =
+ F->connect.hostaddr.ss_port;
+ F->connect.hostaddr.ss_len = addr->ss_len;
+
+ /* Now, call the tryconnect() routine to try a connect() */
+ comm_connect_tryconnect(F, 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(fde_t *fd, void *notused)
+{
+ int retval;
+
+ /* This check is needed or re-entrant s_bsd_* like sigio break it. */
+ if (fd->connect.callback == NULL)
+ return;
+
+ /* Try the connect() */
+ retval = connect(fd->fd, (struct sockaddr *) &fd->connect.hostaddr,
+ fd->connect.hostaddr.ss_len);
+
+ /* 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(fd, COMM_OK);
+ else if (ignoreErrno(errno))
+ /* Ignore error? Reschedule */
+ comm_setselect(fd, COMM_SELECT_WRITE, comm_connect_tryconnect,
+ NULL, 0);
+ else
+ /* Error? Fail with COMM_ERR_CONNECT */
+ comm_connect_callback(fd, COMM_ERR_CONNECT);
+ return;
+ }
+
+ /* If we get here, we've suceeded, so call with COMM_OK */
+ comm_connect_callback(fd, COMM_OK);
+}
+
+/*
+ * comm_errorstr() - 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_open() - 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_open(fde_t *F, 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 >= hard_fdlimit)
+ {
+ 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);
+ if (fd < 0)
+ return -1; /* errno will be passed through, yay.. */
+
+ execute_callback(setup_socket_cb, fd);
+
+ /* update things in our fd tracking */
+ fd_open(F, fd, 1, note);
+ return 0;
+}
+
+/*
+ * comm_accept() - accept an incoming connection
+ *
+ * This is a simple wrapper for accept() which enforces FD limits like
+ * comm_open() does. Returned fd must be either closed or tagged with
+ * fd_open (this function no longer does it).
+ */
+int
+comm_accept(struct Listener *lptr, struct irc_ssaddr *pn)
+{
+ int newfd;
+ socklen_t addrlen = sizeof(struct irc_ssaddr);
+
+ if (number_fd >= hard_fdlimit)
+ {
+ 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(lptr->fd.fd, (struct sockaddr *)pn, &addrlen);
+ if (newfd < 0)
+ return -1;
+
+#ifdef IPV6
+ remove_ipv6_mapping(pn);
+#else
+ pn->ss_len = addrlen;
+#endif
+
+ execute_callback(setup_socket_cb, newfd);
+
+ /* .. and return */
+ return newfd;
+}
+
+/*
+ * remove_ipv6_mapping() - Removes IPv4-In-IPv6 mapping from an address
+ * OSes with IPv6 mapping listening on both
+ * AF_INET and AF_INET6 map AF_INET connections inside AF_INET6 structures
+ *
+ */
+#ifdef IPV6
+void
+remove_ipv6_mapping(struct irc_ssaddr *addr)
+{
+ if (addr->ss.ss_family == AF_INET6)
+ {
+ if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)addr)->sin6_addr))
+ {
+ struct sockaddr_in6 v6;
+ struct sockaddr_in *v4 = (struct sockaddr_in *)addr;
+
+ memcpy(&v6, addr, sizeof(v6));
+ memset(v4, 0, sizeof(struct sockaddr_in));
+ memcpy(&v4->sin_addr, &v6.sin6_addr.s6_addr[12], sizeof(v4->sin_addr));
+
+ addr->ss.ss_family = AF_INET;
+ addr->ss_len = sizeof(struct sockaddr_in);
+ }
+ else
+ addr->ss_len = sizeof(struct sockaddr_in6);
+ }
+ else
+ addr->ss_len = sizeof(struct sockaddr_in);
+}
+#endif
diff --git a/src/s_bsd_devpoll.c b/src/s_bsd_devpoll.c
new file mode 100644
index 0000000..49d4eee
--- /dev/null
+++ b/src/s_bsd_devpoll.c
@@ -0,0 +1,186 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * s_bsd_devpoll.c: /dev/poll compatible network routines.
+ *
+ * Originally by Adrian Chadd <adrian@creative.net.au>
+ * 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$
+ */
+
+#include "stdinc.h"
+#if USE_IOPOLL_MECHANISM == __IOPOLL_MECHANISM_DEVPOLL
+#include <sys/ioctl.h>
+/* HPUX uses devpoll.h and not sys/devpoll.h */
+#ifdef HAVE_DEVPOLL_H
+# include <devpoll.h>
+#else
+# ifdef HAVE_SYS_DEVPOLL_H
+# include <sys/devpoll.h>
+# else
+# error "No devpoll.h found! Try ./configuring and letting the script choose for you."
+# endif
+#endif
+#include "fdlist.h"
+#include "ircd.h"
+#include "s_bsd.h"
+#include "log.h"
+
+static fde_t dpfd;
+
+/*
+ * init_netio
+ *
+ * This is a needed exported function which will be called to initialise
+ * the network loop code.
+ */
+void
+init_netio(void)
+{
+ int fd;
+
+ if ((fd = open("/dev/poll", O_RDWR)) < 0)
+ {
+ ilog(LOG_TYPE_IRCD, "init_netio: Couldn't open /dev/poll - %d: %s",
+ errno, strerror(errno));
+ exit(115); /* Whee! */
+ }
+
+ fd_open(&dpfd, fd, 0, "/dev/poll file descriptor");
+}
+
+/*
+ * 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 pfd;
+
+ /* Build the pollfd entry */
+ pfd.revents = 0;
+ pfd.fd = fd;
+ pfd.events = events;
+
+ /* Write the thing to our poll fd */
+ if (write(dpfd.fd, &pfd, sizeof(pfd)) != sizeof(pfd))
+ ilog(LOG_TYPE_IRCD, "devpoll_write_update: dpfd write failed %d: %s",
+ errno, strerror(errno));
+}
+
+/*
+ * 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(fde_t *F, unsigned int type, PF *handler,
+ void *client_data, time_t timeout)
+{
+ int new_events;
+
+ if ((type & COMM_SELECT_READ))
+ {
+ F->read_handler = handler;
+ F->read_data = client_data;
+ }
+
+ if ((type & COMM_SELECT_WRITE))
+ {
+ F->write_handler = handler;
+ F->write_data = client_data;
+ }
+
+ new_events = (F->read_handler ? POLLIN : 0) |
+ (F->write_handler ? POLLOUT : 0);
+
+ if (timeout != 0)
+ F->timeout = CurrentTime + (timeout / 1000);
+
+ if (new_events != F->evcache)
+ {
+ devpoll_write_update(F->fd, POLLREMOVE);
+ if ((F->evcache = new_events))
+ devpoll_write_update(F->fd, new_events);
+ }
+}
+
+/*
+ * 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.
+ */
+void
+comm_select(void)
+{
+ int num, i;
+ struct pollfd pollfds[128];
+ struct dvpoll dopoll;
+ PF *hdl;
+ fde_t *F;
+
+ dopoll.dp_timeout = SELECT_DELAY;
+ dopoll.dp_nfds = 128;
+ dopoll.dp_fds = &pollfds[0];
+ num = ioctl(dpfd.fd, DP_POLL, &dopoll);
+
+ set_time();
+
+ if (num < 0)
+ {
+#ifdef HAVE_USLEEP
+ usleep(50000); /* avoid 99% CPU in comm_select */
+#endif
+ return;
+ }
+
+ for (i = 0; i < num; i++)
+ {
+ F = lookup_fd(dopoll.dp_fds[i].fd);
+ if (F == NULL || !F->flags.open)
+ continue;
+
+ if ((dopoll.dp_fds[i].revents & POLLIN))
+ if ((hdl = F->read_handler) != NULL)
+ {
+ F->read_handler = NULL;
+ hdl(F, F->read_data);
+ if (!F->flags.open)
+ continue;
+ }
+
+ if ((dopoll.dp_fds[i].revents & POLLOUT))
+ if ((hdl = F->write_handler) != NULL)
+ {
+ F->write_handler = NULL;
+ hdl(F, F->write_data);
+ if (!F->flags.open)
+ continue;
+ }
+
+ comm_setselect(F, 0, NULL, NULL, 0);
+ }
+}
+#endif
diff --git a/src/s_bsd_epoll.c b/src/s_bsd_epoll.c
new file mode 100644
index 0000000..8e8de83
--- /dev/null
+++ b/src/s_bsd_epoll.c
@@ -0,0 +1,221 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * s_bsd_epoll.c: Linux epoll() compatible network routines.
+ *
+ * Copyright (C) 2002-2005 Hybrid Development Team
+ * Based also on work of Adrian Chadd, Aaron Sethman 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$
+ */
+
+#include "stdinc.h"
+#if USE_IOPOLL_MECHANISM == __IOPOLL_MECHANISM_EPOLL
+#include "fdlist.h"
+#include "ircd.h"
+#include "memory.h"
+#include "s_bsd.h"
+#include "log.h"
+#include <sys/epoll.h>
+#include <sys/syscall.h>
+
+static fde_t efd;
+
+/* Thanks to ircu for the following ifdefs. */
+
+/* The GNU C library may have a valid header but stub implementations
+ * of the epoll system calls. If so, provide our own. */
+#if defined(__stub_epoll_create) || defined(__stub___epoll_create) || defined(EPOLL_NEED_BODY)
+
+/* Oh, did we mention that some glibc releases do not even define the
+ * syscall numbers? */
+#if !defined(__NR_epoll_create)
+#if defined(__ia64__)
+#define __NR_epoll_create 1243
+#define __NR_epoll_ctl 1244
+#define __NR_epoll_wait 1245
+#elif defined(__x86_64__)
+#define __NR_epoll_create 214
+#define __NR_epoll_ctl 233
+#define __NR_epoll_wait 232
+#elif defined(__sparc64__) || defined(__sparc__)
+#define __NR_epoll_create 193
+#define __NR_epoll_ctl 194
+#define __NR_epoll_wait 195
+#elif defined(__s390__) || defined(__m68k__)
+#define __NR_epoll_create 249
+#define __NR_epoll_ctl 250
+#define __NR_epoll_wait 251
+#elif defined(__ppc64__) || defined(__ppc__)
+#define __NR_epoll_create 236
+#define __NR_epoll_ctl 237
+#define __NR_epoll_wait 238
+#elif defined(__parisc__) || defined(__arm26__) || defined(__arm__)
+#define __NR_epoll_create 224
+#define __NR_epoll_ctl 225
+#define __NR_epoll_wait 226
+#elif defined(__alpha__)
+#define __NR_epoll_create 407
+#define __NR_epoll_ctl 408
+#define __NR_epoll_wait 409
+#elif defined(__sh64__)
+#define __NR_epoll_create 282
+#define __NR_epoll_ctl 283
+#define __NR_epoll_wait 284
+#elif defined(__i386__) || defined(__sh__) || defined(__m32r__) || defined(__h8300__) || defined(__frv__)
+#define __NR_epoll_create 254
+#define __NR_epoll_ctl 255
+#define __NR_epoll_wait 256
+#else /* cpu types */
+#error No system call numbers defined for epoll family.
+#endif /* cpu types */
+#endif /* !defined(__NR_epoll_create) */
+
+_syscall1(int, epoll_create, int, size)
+_syscall4(int, epoll_ctl, int, epfd, int, op, int, fd, struct epoll_event *, event)
+_syscall4(int, epoll_wait, int, epfd, struct epoll_event *, pevents, int, maxevents, int, timeout)
+
+#endif /* epoll_create defined as stub */
+
+/*
+ * init_netio
+ *
+ * This is a needed exported function which will be called to initialise
+ * the network loop code.
+ */
+void
+init_netio(void)
+{
+ int fd;
+
+ if ((fd = epoll_create(hard_fdlimit)) < 0)
+ {
+ ilog(LOG_TYPE_IRCD, "init_netio: Couldn't open epoll fd - %d: %s",
+ errno, strerror(errno));
+ exit(115); /* Whee! */
+ }
+
+ fd_open(&efd, fd, 0, "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(fde_t *F, unsigned int type, PF *handler,
+ void *client_data, time_t timeout)
+{
+ int new_events, op;
+ struct epoll_event ep_event = { 0, { 0 } };
+
+ if ((type & COMM_SELECT_READ))
+ {
+ F->read_handler = handler;
+ F->read_data = client_data;
+ }
+
+ if ((type & COMM_SELECT_WRITE))
+ {
+ F->write_handler = handler;
+ F->write_data = client_data;
+ }
+
+ new_events = (F->read_handler ? EPOLLIN : 0) |
+ (F->write_handler ? EPOLLOUT : 0);
+
+ if (timeout != 0)
+ F->timeout = CurrentTime + (timeout / 1000);
+
+ if (new_events != F->evcache)
+ {
+ if (new_events == 0)
+ op = EPOLL_CTL_DEL;
+ else if (F->evcache == 0)
+ op = EPOLL_CTL_ADD;
+ else
+ op = EPOLL_CTL_MOD;
+
+ ep_event.events = F->evcache = new_events;
+ ep_event.data.fd = F->fd;
+
+ if (epoll_ctl(efd.fd, op, F->fd, &ep_event) != 0)
+ {
+ ilog(LOG_TYPE_IRCD, "comm_setselect: epoll_ctl() failed: %s", strerror(errno));
+ abort();
+ }
+ }
+}
+
+/*
+ * comm_select()
+ *
+ * Called to do the new-style IO, courtesy of 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.
+ */
+void
+comm_select(void)
+{
+ struct epoll_event ep_fdlist[128];
+ int num, i;
+ PF *hdl;
+ fde_t *F;
+
+ num = epoll_wait(efd.fd, ep_fdlist, 128, SELECT_DELAY);
+
+ set_time();
+
+ if (num < 0)
+ {
+#ifdef HAVE_USLEEP
+ usleep(50000); /* avoid 99% CPU in comm_select */
+#endif
+ return;
+ }
+
+ for (i = 0; i < num; i++)
+ {
+ F = lookup_fd(ep_fdlist[i].data.fd);
+ if (F == NULL || !F->flags.open)
+ continue;
+
+ if ((ep_fdlist[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR)))
+ if ((hdl = F->read_handler) != NULL)
+ {
+ F->read_handler = NULL;
+ hdl(F, F->read_data);
+ if (!F->flags.open)
+ continue;
+ }
+
+ if ((ep_fdlist[i].events & (EPOLLOUT | EPOLLHUP | EPOLLERR)))
+ if ((hdl = F->write_handler) != NULL)
+ {
+ F->write_handler = NULL;
+ hdl(F, F->write_data);
+ if (!F->flags.open)
+ continue;
+ }
+
+ comm_setselect(F, 0, NULL, NULL, 0);
+ }
+}
+#endif
diff --git a/src/s_bsd_kqueue.c b/src/s_bsd_kqueue.c
new file mode 100644
index 0000000..6571878
--- /dev/null
+++ b/src/s_bsd_kqueue.c
@@ -0,0 +1,199 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * s_bsd_kqueue.c: FreeBSD kqueue compatible network routines.
+ *
+ * Originally by Adrian Chadd <adrian@creative.net.au>
+ * Copyright (C) 2005 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$
+ */
+
+#include "stdinc.h"
+#if USE_IOPOLL_MECHANISM == __IOPOLL_MECHANISM_KQUEUE
+#include <sys/event.h>
+#include "fdlist.h"
+#include "ircd.h"
+#include "memory.h"
+#include "s_bsd.h"
+#include "log.h"
+
+#define KE_LENGTH 128
+
+/* 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 fde_t kqfd;
+static struct kevent kq_fdlist[KE_LENGTH]; /* kevent buffer */
+static int kqoff; /* offset into the buffer */
+void init_netio(void);
+
+/*
+ * init_netio
+ *
+ * This is a needed exported function which will be called to initialise
+ * the network loop code.
+ */
+void
+init_netio(void)
+{
+ int fd;
+
+ if ((fd = kqueue()) < 0)
+ {
+ ilog(LOG_TYPE_IRCD, "init_netio: Couldn't open kqueue fd!");
+ exit(115); /* Whee! */
+ }
+
+ fd_open(&kqfd, fd, 0, "kqueue() file descriptor");
+}
+
+/*
+ * Write a single update to the kqueue list.
+ */
+static void
+kq_update_events(int fd, int filter, int what)
+{
+ static struct timespec zero_timespec = {0, 0};
+ struct kevent *kep = kq_fdlist + kqoff;
+
+ EV_SET(kep, (uintptr_t) fd, (short) filter, what, 0, 0, NULL);
+
+ if (++kqoff == KE_LENGTH)
+ {
+ kevent(kqfd.fd, kq_fdlist, kqoff, NULL, 0, &zero_timespec);
+ kqoff = 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(fde_t *F, unsigned int type, PF *handler,
+ void *client_data, time_t timeout)
+{
+ int new_events, diff;
+
+ if ((type & COMM_SELECT_READ))
+ {
+ F->read_handler = handler;
+ F->read_data = client_data;
+ }
+
+ if ((type & COMM_SELECT_WRITE))
+ {
+ F->write_handler = handler;
+ F->write_data = client_data;
+ }
+
+ new_events = (F->read_handler ? COMM_SELECT_READ : 0) |
+ (F->write_handler ? COMM_SELECT_WRITE : 0);
+
+ if (timeout != 0)
+ F->timeout = CurrentTime + (timeout / 1000);
+
+ diff = new_events ^ F->evcache;
+
+ if ((diff & COMM_SELECT_READ))
+ kq_update_events(F->fd, EVFILT_READ,
+ (new_events & COMM_SELECT_READ) ? EV_ADD : EV_DELETE);
+ if ((diff & COMM_SELECT_WRITE))
+ kq_update_events(F->fd, EVFILT_WRITE,
+ (new_events & COMM_SELECT_WRITE) ? EV_ADD : EV_DELETE);
+
+ F->evcache = new_events;
+}
+
+/*
+ * 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.
+ */
+void
+comm_select(void)
+{
+ int num, i;
+ static struct kevent ke[KE_LENGTH];
+ struct timespec poll_time;
+ PF *hdl;
+ fde_t *F;
+
+ /*
+ * 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 = 0;
+ poll_time.tv_nsec = SELECT_DELAY * 1000000;
+ num = kevent(kqfd.fd, kq_fdlist, kqoff, ke, KE_LENGTH, &poll_time);
+ kqoff = 0;
+
+ set_time();
+
+ if (num < 0)
+ {
+#ifdef HAVE_USLEEP
+ usleep(50000); /* avoid 99% CPU in comm_select */
+#endif
+ return;
+ }
+
+ for (i = 0; i < num; i++)
+ {
+ F = lookup_fd(ke[i].ident);
+ if (F == NULL || !F->flags.open || (ke[i].flags & EV_ERROR))
+ continue;
+
+ if (ke[i].filter == EVFILT_READ)
+ if ((hdl = F->read_handler) != NULL)
+ {
+ F->read_handler = NULL;
+ hdl(F, F->read_data);
+ if (!F->flags.open)
+ continue;
+ }
+
+ if (ke[i].filter == EVFILT_WRITE)
+ if ((hdl = F->write_handler) != NULL)
+ {
+ F->write_handler = NULL;
+ hdl(F, F->write_data);
+ if (!F->flags.open)
+ continue;
+ }
+
+ comm_setselect(F, 0, NULL, NULL, 0);
+ }
+}
+#endif
diff --git a/src/s_bsd_poll.c b/src/s_bsd_poll.c
new file mode 100644
index 0000000..2692da5
--- /dev/null
+++ b/src/s_bsd_poll.c
@@ -0,0 +1,224 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * s_bsd_poll.c: POSIX poll() compatible network routines.
+ *
+ * Originally by Adrian Chadd <adrian@creative.net.au>
+ * 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$
+ */
+
+#include "stdinc.h"
+#if USE_IOPOLL_MECHANISM == __IOPOLL_MECHANISM_POLL
+#include <sys/poll.h>
+#include "fdlist.h"
+#include "list.h"
+#include "hook.h"
+#include "ircd.h"
+#include "s_bsd.h"
+#include "log.h"
+
+/* I hate linux -- adrian */
+#ifndef POLLRDNORM
+#define POLLRDNORM POLLIN
+#endif
+#ifndef POLLWRNORM
+#define POLLWRNORM POLLOUT
+#endif
+
+static struct pollfd *pollfds;
+static int pollmax = -1; /* highest FD number */
+static dlink_node *hookptr;
+
+/*
+ * changing_fdlimit
+ *
+ * Resize pollfds array if necessary.
+ */
+static void *
+changing_fdlimit(va_list args)
+{
+ int old_fdlimit = hard_fdlimit;
+
+ pass_callback(hookptr, va_arg(args, int));
+
+ if (hard_fdlimit != old_fdlimit)
+ pollfds = MyRealloc(pollfds, sizeof(struct pollfd) * hard_fdlimit);
+
+ return NULL;
+}
+
+/*
+ * init_netio
+ *
+ * This is a needed exported function which will be called to initialise
+ * the network loop code.
+ */
+void
+init_netio(void)
+{
+ int fd;
+
+ pollfds = MyMalloc(sizeof(struct pollfd) * hard_fdlimit);
+
+ for (fd = 0; fd < hard_fdlimit; fd++)
+ pollfds[fd].fd = -1;
+
+ hookptr = install_hook(fdlimit_cb, changing_fdlimit);
+}
+
+/*
+ * 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 < hard_fdlimit; i++)
+ if (pollfds[i].fd == -1)
+ {
+ /* MATCH!!#$*&$ */
+ return i;
+ }
+
+ assert(1 == 0);
+ /* NOTREACHED */
+ return -1;
+}
+
+/*
+ * 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(fde_t *F, unsigned int type, PF *handler,
+ void *client_data, time_t timeout)
+{
+ int new_events;
+
+ if ((type & COMM_SELECT_READ))
+ {
+ F->read_handler = handler;
+ F->read_data = client_data;
+ }
+
+ if ((type & COMM_SELECT_WRITE))
+ {
+ F->write_handler = handler;
+ F->write_data = client_data;
+ }
+
+ new_events = (F->read_handler ? POLLRDNORM : 0) |
+ (F->write_handler ? POLLWRNORM : 0);
+
+ if (timeout != 0)
+ F->timeout = CurrentTime + (timeout / 1000);
+
+ if (new_events != F->evcache)
+ {
+ if (new_events == 0)
+ {
+ pollfds[F->comm_index].fd = -1;
+ pollfds[F->comm_index].revents = 0;
+
+ if (pollmax == F->comm_index)
+ while (pollmax >= 0 && pollfds[pollmax].fd == -1)
+ pollmax--;
+ }
+ else
+ {
+ if (F->evcache == 0)
+ {
+ F->comm_index = poll_findslot();
+ if (F->comm_index > pollmax)
+ pollmax = F->comm_index;
+
+ pollfds[F->comm_index].fd = F->fd;
+ }
+ pollfds[F->comm_index].events = new_events;
+ pollfds[F->comm_index].revents = 0;
+ }
+
+ F->evcache = new_events;
+ }
+}
+
+/*
+ * comm_select
+ *
+ * Called to do the new-style IO, courtesy of 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.
+ */
+void
+comm_select(void)
+{
+ int num, ci, revents;
+ PF *hdl;
+ fde_t *F;
+
+ /* XXX kill that +1 later ! -- adrian */
+ num = poll(pollfds, pollmax + 1, SELECT_DELAY);
+
+ set_time();
+
+ if (num < 0)
+ {
+#ifdef HAVE_USLEEP
+ usleep(50000); /* avoid 99% CPU in comm_select */
+#endif
+ return;
+ }
+
+ for (ci = 0; ci <= pollmax && num > 0; ci++)
+ {
+ if ((revents = pollfds[ci].revents) == 0 || pollfds[ci].fd == -1)
+ continue;
+ num--;
+
+ F = lookup_fd(pollfds[ci].fd);
+ if (F == NULL || !F->flags.open)
+ continue;
+
+ if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR))
+ if ((hdl = F->read_handler) != NULL)
+ {
+ F->read_handler = NULL;
+ hdl(F, F->read_data);
+ if (!F->flags.open)
+ continue;
+ }
+
+ if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR))
+ if ((hdl = F->write_handler) != NULL)
+ {
+ F->write_handler = NULL;
+ hdl(F, F->write_data);
+ if (!F->flags.open)
+ continue;
+ }
+
+ comm_setselect(F, 0, NULL, NULL, 0);
+ }
+}
+#endif
diff --git a/src/s_bsd_select.c b/src/s_bsd_select.c
new file mode 100644
index 0000000..c0b327c
--- /dev/null
+++ b/src/s_bsd_select.c
@@ -0,0 +1,204 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * s_bsd_select.c: select() compatible network routines.
+ *
+ * Originally by Adrian Chadd <adrian@creative.net.au>
+ * 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$
+ */
+
+#include "stdinc.h"
+#if USE_IOPOLL_MECHANISM == __IOPOLL_MECHANISM_SELECT
+#include "list.h"
+#include "fdlist.h"
+#include "hook.h"
+#include "ircd.h"
+#include "s_bsd.h"
+#include "log.h"
+
+/*
+ * 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
+ */
+
+static fd_set select_readfds, tmpreadfds;
+static fd_set select_writefds, tmpwritefds;
+static int highest_fd = -1;
+static dlink_node *hookptr;
+
+/*
+ * changing_fdlimit
+ *
+ * Make sure hard_fdlimit doesn't go too big.
+ */
+static void *
+changing_fdlimit(va_list args)
+{
+ int fdmax = va_arg(args, int);
+
+ if (fdmax > FD_SETSIZE)
+ fdmax = FD_SETSIZE;
+
+ return pass_callback(hookptr, fdmax);
+}
+
+/*
+ * 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);
+
+ hookptr = install_hook(fdlimit_cb, changing_fdlimit);
+}
+
+/*
+ * 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(fde_t *F, unsigned int type, PF *handler,
+ void *client_data, time_t timeout)
+{
+ int new_events;
+
+ if ((type & COMM_SELECT_READ))
+ {
+ F->read_handler = handler;
+ F->read_data = client_data;
+ }
+
+ if ((type & COMM_SELECT_WRITE))
+ {
+ F->write_handler = handler;
+ F->write_data = client_data;
+ }
+
+ new_events = (F->read_handler ? COMM_SELECT_READ : 0) |
+ (F->write_handler ? COMM_SELECT_WRITE : 0);
+
+ if (timeout != 0)
+ F->timeout = CurrentTime + (timeout / 1000);
+
+ if (new_events != F->evcache)
+ {
+ if ((new_events & COMM_SELECT_READ))
+ FD_SET(F->fd, &select_readfds);
+ else
+ {
+ FD_CLR(F->fd, &select_readfds);
+ FD_CLR(F->fd, &tmpreadfds);
+ }
+
+ if ((new_events & COMM_SELECT_WRITE))
+ FD_SET(F->fd, &select_writefds);
+ else
+ {
+ FD_CLR(F->fd, &select_writefds);
+ FD_CLR(F->fd, &tmpwritefds);
+ }
+
+ if (new_events == 0)
+ {
+ if (highest_fd == F->fd)
+ while (highest_fd >= 0 && (FD_ISSET(highest_fd, &select_readfds) ||
+ FD_ISSET(highest_fd, &select_writefds)))
+ highest_fd--;
+ }
+ else if (F->evcache == 0)
+ if (F->fd > highest_fd)
+ highest_fd = F->fd;
+
+ F->evcache = new_events;
+ }
+}
+
+/*
+ * 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.
+ */
+void
+comm_select(void)
+{
+ struct timeval to;
+ int num, fd;
+ fde_t *F;
+ PF *hdl;
+
+ /* 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));
+
+ to.tv_sec = 0;
+ to.tv_usec = SELECT_DELAY * 1000;
+ num = select(highest_fd + 1, &tmpreadfds, &tmpwritefds, NULL, &to);
+
+ set_time();
+
+ if (num < 0)
+ {
+#ifdef HAVE_USLEEP
+ usleep(50000);
+#endif
+ return;
+ }
+
+ for (fd = 0; fd <= highest_fd && num > 0; fd++)
+ if (FD_ISSET(fd, &tmpreadfds) || FD_ISSET(fd, &tmpwritefds))
+ {
+ num--;
+
+ F = lookup_fd(fd);
+ if (F == NULL || !F->flags.open)
+ continue;
+
+ if (FD_ISSET(fd, &tmpreadfds))
+ if ((hdl = F->read_handler) != NULL)
+ {
+ F->read_handler = NULL;
+ hdl(F, F->read_data);
+ if (!F->flags.open)
+ continue;
+ }
+
+ if (FD_ISSET(fd, &tmpwritefds))
+ if ((hdl = F->write_handler) != NULL)
+ {
+ F->write_handler = NULL;
+ hdl(F, F->write_data);
+ if (!F->flags.open)
+ continue;
+ }
+
+ comm_setselect(F, 0, NULL, NULL, 0);
+ }
+}
+#endif
diff --git a/src/s_bsd_sigio.c b/src/s_bsd_sigio.c
new file mode 100644
index 0000000..6480393
--- /dev/null
+++ b/src/s_bsd_sigio.c
@@ -0,0 +1,318 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * s_bsd_sigio.c: Linux Realtime SIGIO compatible network routines.
+ *
+ * Originally by Aaron Sethman <androsyn@ratbox.org>
+ * based upon: s_bsd_poll.c by Adrian Chadd <adrian@creative.net.au>
+ * Copyright (C) 2001-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$
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1 /* Needed for F_SETSIG */
+#endif
+
+#include "stdinc.h"
+#if USE_IOPOLL_MECHANISM == __IOPOLL_MECHANISM_RTSIGIO
+#include <sys/poll.h>
+#include "list.h"
+#include "fdlist.h"
+#include "hook.h"
+#include "ircd.h"
+#include "s_bsd.h"
+#include "log.h"
+
+#define SIGIO_SIGNAL SIGRTMIN
+
+static pid_t my_pid;
+static sigset_t our_sigset;
+static struct pollfd *pollfds;
+static int pollmax = -1; /* highest FD number */
+static dlink_node *fdlim_hook, *setupfd_hook;
+
+/*
+ * static void mask_our_signal(int s)
+ *
+ * Input: None
+ * Output: None
+ * Side Effects: Block our signal
+ */
+static void
+mask_our_signal()
+{
+ sigemptyset(&our_sigset);
+ sigaddset(&our_sigset, SIGIO_SIGNAL);
+ sigaddset(&our_sigset, SIGIO);
+ sigprocmask(SIG_BLOCK, &our_sigset, NULL);
+}
+
+/*
+ * void setup_sigio_fd(int fd)
+ *
+ * Input: File descriptor
+ * Output: None
+ * Side Effect: Sets the FD up for SIGIO
+ */
+static void *
+setup_sigio_fd(va_list args)
+{
+ int fd = va_arg(args, int);
+
+ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_ASYNC);
+ fcntl(fd, F_SETSIG, SIGIO_SIGNAL);
+ fcntl(fd, F_SETOWN, my_pid);
+
+ return pass_callback(setupfd_hook, fd);
+}
+
+/*
+ * changing_fdlimit
+ *
+ * Resize pollfds array if necessary.
+ */
+static void *
+changing_fdlimit(va_list args)
+{
+ int old_fdlimit = hard_fdlimit;
+
+ pass_callback(fdlim_hook, va_arg(args, int));
+
+ if (hard_fdlimit != old_fdlimit)
+ pollfds = MyRealloc(pollfds, sizeof(struct pollfd) * hard_fdlimit);
+
+ return NULL;
+}
+
+/*
+ * void init_netio(void)
+ *
+ * Input: None
+ * Output: None
+ * Side Effects: This is a needed exported function which will
+ * be called to initialise the network loop code.
+ */
+void
+init_netio(void)
+{
+ int fd;
+
+ pollfds = MyMalloc(sizeof(struct pollfd) * hard_fdlimit);
+
+ for (fd = 0; fd < hard_fdlimit; fd++)
+ pollfds[fd].fd = -1;
+
+ setupfd_hook = install_hook(setup_socket_cb, setup_sigio_fd);
+ fdlim_hook = install_hook(fdlimit_cb, changing_fdlimit);
+
+ my_pid = getpid();
+ mask_our_signal(SIGIO_SIGNAL);
+}
+
+/*
+ * 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 < hard_fdlimit; i++)
+ {
+ if (pollfds[i].fd == -1)
+ {
+ /* MATCH!!#$*&$ */
+ return i;
+ }
+ }
+
+ assert(1 == 0);
+ /* NOTREACHED */
+ return -1;
+}
+
+/*
+ * 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(fde_t *F, unsigned int type, PF *handler,
+ void *client_data, time_t timeout)
+{
+ int new_events;
+
+ if ((type & COMM_SELECT_READ))
+ {
+ F->read_handler = handler;
+ F->read_data = client_data;
+ }
+
+ if ((type & COMM_SELECT_WRITE))
+ {
+ F->write_handler = handler;
+ F->write_data = client_data;
+ }
+
+ new_events = (F->read_handler ? POLLRDNORM : 0) |
+ (F->write_handler ? POLLWRNORM : 0);
+
+ if (timeout != 0)
+ F->timeout = CurrentTime + (timeout / 1000);
+
+ if (new_events != F->evcache)
+ {
+ if (new_events == 0)
+ {
+ pollfds[F->comm_index].fd = -1;
+ pollfds[F->comm_index].revents = 0;
+
+ if (pollmax == F->comm_index)
+ while (pollmax >= 0 && pollfds[pollmax].fd == -1)
+ pollmax--;
+ }
+ else
+ {
+ if (F->evcache == 0)
+ {
+ F->comm_index = poll_findslot();
+ if (F->comm_index > pollmax)
+ pollmax = F->comm_index;
+
+ pollfds[F->comm_index].fd = F->fd;
+ }
+ pollfds[F->comm_index].events = new_events;
+ pollfds[F->comm_index].revents = 0;
+ }
+
+ F->evcache = new_events;
+ }
+}
+
+/*
+ * 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.
+ */
+void
+comm_select(void)
+{
+ static time_t last_rtsigqo_warning = 0;
+ struct timespec timeout;
+ struct siginfo si;
+ int i, revents, num;
+ fde_t *F;
+ PF *hdl;
+
+ timeout.tv_sec = 0;
+ timeout.tv_nsec = 1000000 * SELECT_DELAY;
+ i = sigtimedwait(&our_sigset, &si, &timeout);
+
+ set_time();
+
+ if (i != SIGIO)
+ {
+ if (i > 0)
+ {
+ F = lookup_fd(si.si_fd);
+ if (F == NULL || !F->flags.open)
+ return;
+
+ if (si.si_band & (POLLRDNORM | POLLIN | POLLHUP | POLLERR))
+ if ((hdl = F->read_handler) != NULL)
+ {
+ F->read_handler = NULL;
+ hdl(F, F->read_data);
+ if (!F->flags.open)
+ return;
+ }
+
+ if (si.si_band & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR))
+ if ((hdl = F->write_handler) != NULL)
+ {
+ F->write_handler = NULL;
+ hdl(F, F->write_data);
+ if (!F->flags.open)
+ return;
+ }
+
+ comm_setselect(F, 0, NULL, NULL, 0);
+ }
+
+ return;
+ }
+
+ /* RT signal queue overflowed.. */
+
+ if (CurrentTime - last_rtsigqo_warning >= 30)
+ {
+ ilog(LOG_TYPE_IRCD, "Kernel RT Signal queue overflowed. "
+ "Is /proc/sys/kernel/rtsig-max too small?");
+ last_rtsigqo_warning = CurrentTime;
+ }
+
+ signal(SIGIO_SIGNAL, SIG_IGN);
+ signal(SIGIO_SIGNAL, SIG_DFL);
+
+ /* ..try polling instead */
+
+ while ((num = poll(pollfds, pollmax + 1, 0)) < 0 && ignoreErrno(errno))
+ ;
+
+ /* update current time again, eww.. */
+ set_time();
+
+ for (i = 0; i <= pollmax && num > 0; i++)
+ {
+ if ((revents = pollfds[i].revents) == 0 || pollfds[i].fd == -1)
+ continue;
+ num--;
+
+ F = lookup_fd(pollfds[i].fd);
+ if (F == NULL || !F->flags.open)
+ continue;
+
+ if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR))
+ if ((hdl = F->read_handler) != NULL)
+ {
+ F->read_handler = NULL;
+ hdl(F, F->read_data);
+ if (!F->flags.open)
+ continue;
+ }
+
+ if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR))
+ if ((hdl = F->write_handler) != NULL)
+ {
+ F->write_handler = NULL;
+ hdl(F, F->write_data);
+ if (!F->flags.open)
+ continue;
+ }
+
+ comm_setselect(F, 0, NULL, NULL, 0);
+ }
+
+ mask_our_signal(SIGIO_SIGNAL);
+}
+#endif
diff --git a/src/s_gline.c b/src/s_gline.c
new file mode 100644
index 0000000..aff7a05
--- /dev/null
+++ b/src/s_gline.c
@@ -0,0 +1,114 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * s_gline.c: GLine global ban functions.
+ *
+ * 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$
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "client.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "hostmask.h"
+#include "conf.h"
+#include "s_misc.h"
+#include "send.h"
+#include "s_serv.h"
+#include "s_gline.h"
+#include "event.h"
+#include "memory.h"
+
+dlink_list pending_glines[GLINE_PENDING_ADD_TYPE + 1] = { { NULL, NULL, 0 },
+ { NULL, NULL, 0 } };
+
+static void expire_pending_glines(struct gline_pending *);
+
+
+struct AccessItem *
+find_is_glined(const char *host, const char *user)
+{
+ struct irc_ssaddr iphost, *piphost;
+ struct AccessItem *aconf;
+ int t;
+
+ if ((t = parse_netmask(host, &iphost, &t)) != HM_HOST)
+ {
+#ifdef IPV6
+ if (t == HM_IPV6)
+ t = AF_INET6;
+ else
+#endif
+ t = AF_INET;
+ piphost = &iphost;
+ }
+ else
+ {
+ t = 0;
+ piphost = NULL;
+ }
+
+ aconf = find_conf_by_address(host, piphost, CONF_GLINE, t, user, NULL, 0);
+ return aconf;
+}
+
+/* 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_pending_glines(unused);
+}
+
+/* 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(struct gline_pending *in)
+{
+ dlink_node *ptr = NULL, *next_ptr = NULL;
+ unsigned int idx = 0;
+
+ for (; idx < GLINE_PENDING_ADD_TYPE + 1; ++idx)
+ {
+ DLINK_FOREACH_SAFE(ptr, next_ptr, pending_glines[idx].head)
+ {
+ struct gline_pending *glp_ptr = ptr->data;
+
+ if ((glp_ptr->last_gline_time + ConfigFileEntry.gline_request_time) <= CurrentTime ||
+ glp_ptr == in)
+ {
+ dlinkDelete(&glp_ptr->node, &pending_glines[idx]);
+ MyFree(glp_ptr);
+ }
+ }
+ }
+}
diff --git a/src/s_misc.c b/src/s_misc.c
new file mode 100644
index 0000000..1b6166b
--- /dev/null
+++ b/src/s_misc.c
@@ -0,0 +1,131 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * s_misc.c: Yet another miscellaneous functions file.
+ *
+ * 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$
+ */
+
+#include "stdinc.h"
+#include "s_misc.h"
+#include "client.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "irc_res.h"
+#include "fdlist.h"
+#include "s_bsd.h"
+#include "conf.h"
+#include "s_serv.h"
+#include "send.h"
+#include "memory.h"
+
+
+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"
+};
+
+char *
+date(time_t lclock)
+{
+ static char buf[80], plus;
+ struct tm *lt, *gm;
+ struct tm gmbuf;
+ int minswest;
+
+ if (!lclock)
+ lclock = CurrentTime;
+ gm = gmtime(&lclock);
+ memcpy(&gmbuf, gm, sizeof(gmbuf));
+ gm = &gmbuf;
+ lt = localtime(&lclock);
+
+ /*
+ * There is unfortunately no clean portable way to extract time zone
+ * offset information, so do ugly things.
+ */
+ minswest = (gm->tm_hour - lt->tm_hour) * 60 + (gm->tm_min - lt->tm_min);
+
+ if (lt->tm_yday != gm->tm_yday)
+ {
+ if ((lt->tm_yday > gm->tm_yday && lt->tm_year == gm->tm_year) ||
+ (lt->tm_yday < gm->tm_yday && lt->tm_year != gm->tm_year))
+ minswest -= 24 * 60;
+ else
+ minswest += 24 * 60;
+ }
+
+ plus = (minswest > 0) ? '-' : '+';
+ if (minswest < 0)
+ minswest = -minswest;
+
+ snprintf(buf, sizeof(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;
+}
+
+const char *
+smalldate(time_t lclock)
+{
+ static char buf[MAX_DATE_STRING];
+ struct tm *lt, *gm;
+ struct tm gmbuf;
+
+ if (!lclock)
+ lclock = CurrentTime;
+
+ gm = gmtime(&lclock);
+ memcpy(&gmbuf, gm, sizeof(gmbuf));
+ gm = &gmbuf;
+ lt = localtime(&lclock);
+
+ snprintf(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;
+}
+
+#ifdef HAVE_LIBCRYPTO
+char *
+ssl_get_cipher(const SSL *ssl)
+{
+ static char buffer[IRCD_BUFSIZE / 4];
+ int bits = 0;
+
+ SSL_CIPHER_get_bits(SSL_get_current_cipher(ssl), &bits);
+
+ snprintf(buffer, sizeof(buffer), "%s %s-%d", SSL_get_version(ssl),
+ SSL_get_cipher(ssl), bits);
+
+ return buffer;
+}
+#endif
diff --git a/src/s_serv.c b/src/s_serv.c
new file mode 100644
index 0000000..4d7dcd6
--- /dev/null
+++ b/src/s_serv.c
@@ -0,0 +1,1503 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * s_serv.c: Server related functions.
+ *
+ * Copyright (C) 2005 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$
+ */
+
+#include "stdinc.h"
+#ifdef HAVE_LIBCRYPTO
+#include <openssl/rsa.h>
+#include "rsa.h"
+#endif
+#include "list.h"
+#include "channel.h"
+#include "channel_mode.h"
+#include "client.h"
+#include "dbuf.h"
+#include "event.h"
+#include "fdlist.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "ircd_defs.h"
+#include "s_bsd.h"
+#include "numeric.h"
+#include "packet.h"
+#include "irc_res.h"
+#include "conf.h"
+#include "s_serv.h"
+#include "log.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+#include "memory.h"
+#include "channel.h" /* chcap_usage_counts stuff...*/
+#include "parse.h"
+
+#define MIN_CONN_FREQ 300
+
+static dlink_list cap_list = { NULL, NULL, 0 };
+static void server_burst(struct Client *);
+static void burst_all(struct Client *);
+static void send_tb(struct Client *client_p, struct Channel *chptr);
+
+static CNCB serv_connect_callback;
+
+static void burst_members(struct Client *, struct Channel *);
+
+/*
+ * write_links_file
+ *
+ * inputs - void pointer which is not used
+ * output - NONE
+ * side effects - called from an event, write out list of linked servers
+ * but in no particular order.
+ */
+void
+write_links_file(void* notused)
+{
+ MessageFileLine *next_mptr = NULL;
+ MessageFileLine *mptr = NULL;
+ MessageFileLine *currentMessageLine = NULL;
+ MessageFileLine *newMessageLine = NULL;
+ MessageFile *MessageFileptr = &ConfigFileEntry.linksfile;
+ FILE *file;
+ char buff[512];
+ dlink_node *ptr;
+
+ if ((file = fopen(MessageFileptr->fileName, "w")) == NULL)
+ return;
+
+ for (mptr = MessageFileptr->contentsOfFile; mptr; mptr = next_mptr)
+ {
+ next_mptr = mptr->next;
+ MyFree(mptr);
+ }
+
+ MessageFileptr->contentsOfFile = NULL;
+
+ DLINK_FOREACH(ptr, global_serv_list.head)
+ {
+ const struct Client *target_p = ptr->data;
+
+ /* skip ourselves, we send ourselves in /links */
+ if (IsMe(target_p))
+ continue;
+
+ /* skip hidden servers */
+ if (IsHidden(target_p))
+ continue;
+
+ newMessageLine = MyMalloc(sizeof(MessageFileLine));
+
+ /*
+ * Attempt to format the file in such a way it follows the usual links output
+ * ie "servername uplink :hops info"
+ * Mostly for aesthetic reasons - makes it look pretty in mIRC ;)
+ * - madmax
+ */
+ snprintf(newMessageLine->line, sizeof(newMessageLine->line), "%s %s :1 %s",
+ target_p->name, me.name, target_p->info);
+
+ if (MessageFileptr->contentsOfFile)
+ {
+ if (currentMessageLine)
+ currentMessageLine->next = newMessageLine;
+ currentMessageLine = newMessageLine;
+ }
+ else
+ {
+ MessageFileptr->contentsOfFile = newMessageLine;
+ currentMessageLine = newMessageLine;
+ }
+
+ snprintf(buff, sizeof(buff), "%s %s :1 %s\n",
+ target_p->name, me.name, target_p->info);
+ fputs(buff, file);
+ }
+
+ fclose(file);
+}
+
+/* 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, char *parv[])
+{
+ struct Client *target_p = NULL;
+ struct Client *target_tmp = NULL;
+ dlink_node *ptr;
+ int wilds;
+
+ /* Assume it's me, if no server */
+ if (parc <= server || EmptyString(parv[server]))
+ return HUNTED_ISME;
+
+ if (!strcmp(parv[server], me.id) || match(parv[server], me.name))
+ return HUNTED_ISME;
+
+ /* 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 = hash_find_client(parv[server]);
+ else
+ target_p = find_person(client_p, parv[server]);
+
+ if (target_p)
+ if (target_p->from == source_p->from && !MyConnect(target_p))
+ target_p = NULL;
+
+ if (target_p == NULL && (target_p = hash_find_server(parv[server])))
+ if (target_p->from == source_p->from && !MyConnect(target_p))
+ target_p = NULL;
+
+ collapse(parv[server]);
+ wilds = has_wildcards(parv[server]);
+
+ /* Again, if there are no wild cards involved in the server
+ * name, use the hash lookup
+ */
+ if (target_p == NULL)
+ {
+ if (!wilds)
+ {
+ if (!(target_p = hash_find_server(parv[server])))
+ {
+ sendto_one(source_p, form_str(ERR_NOSUCHSERVER),
+ me.name, source_p->name, parv[server]);
+ return(HUNTED_NOSUCH);
+ }
+ }
+ else
+ {
+ DLINK_FOREACH(ptr, global_client_list.head)
+ {
+ target_tmp = ptr->data;
+
+ if (match(parv[server], target_tmp->name))
+ {
+ if (target_tmp->from == source_p->from && !MyConnect(target_tmp))
+ continue;
+ target_p = ptr->data;
+
+ if (IsRegistered(target_p) && (target_p != client_p))
+ break;
+ }
+ }
+ }
+ }
+
+ if (target_p != NULL)
+ {
+ if(!IsRegistered(target_p))
+ {
+ sendto_one(source_p, form_str(ERR_NOSUCHSERVER),
+ me.name, source_p->name, parv[server]);
+ return HUNTED_NOSUCH;
+ }
+
+ if (IsMe(target_p) || MyClient(target_p))
+ return HUNTED_ISME;
+
+ if (!match(target_p->name, parv[server]))
+ parv[server] = target_p->name;
+
+ /* This is a little kludgy but should work... */
+ if (IsClient(source_p) &&
+ ((MyConnect(target_p) && IsCapable(target_p, CAP_TS6)) ||
+ (!MyConnect(target_p) && IsCapable(target_p->from, CAP_TS6))))
+ parv[0] = ID(source_p);
+
+ sendto_one(target_p, command, parv[0],
+ parv[1], parv[2], parv[3], parv[4],
+ parv[5], parv[6], parv[7], parv[8]);
+ return(HUNTED_PASS);
+ }
+
+ sendto_one(source_p, form_str(ERR_NOSUCHSERVER),
+ me.name, source_p->name, parv[server]);
+ return(HUNTED_NOSUCH);
+}
+
+/* try_connections()
+ *
+ * inputs - void pointer which is not used
+ * output - NONE
+ * side effects -
+ * 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)
+{
+ dlink_node *ptr;
+ struct ConfItem *conf;
+ struct AccessItem *aconf;
+ struct ClassItem *cltmp;
+ int confrq;
+
+ /* TODO: change this to set active flag to 0 when added to event! --Habeeb */
+ if (GlobalSetOptions.autoconn == 0)
+ return;
+
+ DLINK_FOREACH(ptr, server_items.head)
+ {
+ conf = ptr->data;
+ aconf = map_to_conf(conf);
+
+ /* Also when already connecting! (update holdtimes) --SRB
+ */
+ if (!(aconf->status & CONF_SERVER) || !aconf->port ||
+ !(IsConfAllowAutoConn(aconf)))
+ continue;
+
+ cltmp = map_to_conf(aconf->class_ptr);
+
+ /* 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 (aconf->hold > CurrentTime)
+ continue;
+
+ if (cltmp == NULL)
+ confrq = DEFAULT_CONNECTFREQUENCY;
+ else
+ {
+ confrq = cltmp->con_freq;
+ if (confrq < MIN_CONN_FREQ)
+ confrq = MIN_CONN_FREQ;
+ }
+
+ aconf->hold = CurrentTime + confrq;
+
+ /* Found a CONNECT config with port specified, scan clients
+ * and see if this server is already connected?
+ */
+ if (hash_find_server(conf->name) != NULL)
+ continue;
+
+ if (cltmp->curr_user_count < cltmp->max_total)
+ {
+ /* Go to the end of the list, if not already last */
+ if (ptr->next != NULL)
+ {
+ dlinkDelete(ptr, &server_items);
+ dlinkAddTail(conf, &conf->node, &server_items);
+ }
+
+ if (find_servconn_in_progress(conf->name))
+ return;
+
+ /* We used to only print this if serv_connect() actually
+ * succeeded, 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
+ */
+ if (ConfigServerHide.hide_server_ips)
+ sendto_realops_flags(UMODE_ALL, L_ALL, "Connection to %s activated.",
+ conf->name);
+ else
+ sendto_realops_flags(UMODE_ALL, L_ALL, "Connection to %s[%s] activated.",
+ conf->name, aconf->host);
+
+ serv_connect(aconf, NULL);
+ /* We connect only one at time... */
+ return;
+ }
+ }
+}
+
+int
+valid_servname(const char *name)
+{
+ unsigned int length = 0;
+ unsigned int dots = 0;
+ const char *p = name;
+
+ for (; *p; ++p)
+ {
+ if (!IsServChar(*p))
+ return 0;
+
+ ++length;
+
+ if (*p == '.')
+ ++dots;
+ }
+
+ return dots != 0 && length <= HOSTLEN;
+}
+
+int
+check_server(const char *name, struct Client *client_p)
+{
+ dlink_node *ptr;
+ struct ConfItem *conf = NULL;
+ struct ConfItem *server_conf = NULL;
+ struct AccessItem *server_aconf = NULL;
+ struct AccessItem *aconf = NULL;
+ int error = -1;
+
+ assert(client_p != NULL);
+
+ /* loop through looking for all possible connect items that might work */
+ DLINK_FOREACH(ptr, server_items.head)
+ {
+ conf = ptr->data;
+ aconf = map_to_conf(conf);
+
+ if (!match(name, conf->name))
+ continue;
+
+ error = -3;
+
+ /* XXX: Fix me for IPv6 */
+ /* XXX sockhost is the IPv4 ip as a string */
+ if (match(aconf->host, client_p->host) ||
+ match(aconf->host, client_p->sockhost))
+ {
+ error = -2;
+
+ if (!match_conf_password(client_p->localClient->passwd, aconf))
+ return -2;
+
+ server_conf = conf;
+ }
+ }
+
+ if (server_conf == NULL)
+ return(error);
+
+ attach_conf(client_p, server_conf);
+
+ server_aconf = map_to_conf(server_conf);
+
+ if (aconf != NULL)
+ {
+ struct sockaddr_in *v4;
+#ifdef IPV6
+ struct sockaddr_in6 *v6;
+#endif
+ switch (aconf->aftype)
+ {
+#ifdef IPV6
+ case AF_INET6:
+ v6 = (struct sockaddr_in6 *)&aconf->addr;
+
+ if (IN6_IS_ADDR_UNSPECIFIED(&v6->sin6_addr))
+ memcpy(&aconf->addr, &client_p->localClient->ip, sizeof(struct irc_ssaddr));
+ break;
+#endif
+ case AF_INET:
+ v4 = (struct sockaddr_in *)&aconf->addr;
+
+ if (v4->sin_addr.s_addr == INADDR_NONE)
+ memcpy(&aconf->addr, &client_p->localClient->ip, sizeof(struct irc_ssaddr));
+ break;
+ }
+ }
+
+ return(0);
+}
+
+/* add_capability()
+ *
+ * inputs - string name of CAPAB
+ * - int flag of capability
+ * output - NONE
+ * side effects - Adds given capability name and bit mask to
+ * current supported capabilities. This allows
+ * modules to dynamically add or subtract their capability.
+ */
+void
+add_capability(const char *capab_name, int cap_flag, int add_to_default)
+{
+ struct Capability *cap = MyMalloc(sizeof(*cap));
+
+ DupString(cap->name, capab_name);
+ cap->cap = cap_flag;
+ dlinkAdd(cap, &cap->node, &cap_list);
+
+ if (add_to_default)
+ default_server_capabs |= cap_flag;
+}
+
+/* delete_capability()
+ *
+ * inputs - string name of CAPAB
+ * output - NONE
+ * side effects - delete given capability from ones known.
+ */
+int
+delete_capability(const char *capab_name)
+{
+ dlink_node *ptr;
+ dlink_node *next_ptr;
+ struct Capability *cap;
+
+ DLINK_FOREACH_SAFE(ptr, next_ptr, cap_list.head)
+ {
+ cap = ptr->data;
+
+ if (cap->cap != 0)
+ {
+ if (irccmp(cap->name, capab_name) == 0)
+ {
+ default_server_capabs &= ~(cap->cap);
+ dlinkDelete(ptr, &cap_list);
+ MyFree(cap->name);
+ cap->name = NULL;
+ MyFree(cap);
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * find_capability()
+ *
+ * inputs - string name of capab to find
+ * output - 0 if not found CAPAB otherwise
+ * side effects - none
+ */
+int
+find_capability(const char *capab)
+{
+ const dlink_node *ptr = NULL;
+
+ DLINK_FOREACH(ptr, cap_list.head)
+ {
+ const struct Capability *cap = ptr->data;
+
+ if (cap->cap && !irccmp(cap->name, capab))
+ return cap->cap;
+ }
+
+ return 0;
+}
+
+/* send_capabilities()
+ *
+ * inputs - Client pointer to send to
+ * - Pointer to AccessItem (for crypt)
+ * - int flag of capabilities that this server can send
+ * output - NONE
+ * side effects - send the CAPAB line to a server -orabidoo
+ *
+ */
+void
+send_capabilities(struct Client *client_p, struct AccessItem *aconf,
+ int cap_can_send)
+{
+ struct Capability *cap=NULL;
+ char msgbuf[IRCD_BUFSIZE];
+ char *t;
+ int tl;
+ dlink_node *ptr;
+
+ t = msgbuf;
+
+ DLINK_FOREACH(ptr, cap_list.head)
+ {
+ cap = ptr->data;
+
+ if (cap->cap & (cap_can_send|default_server_capabs))
+ {
+ tl = ircsprintf(t, "%s ", cap->name);
+ t += tl;
+ }
+ }
+
+ *(t - 1) = '\0';
+ sendto_one(client_p, "CAPAB :%s", msgbuf);
+}
+
+/* sendnick_TS()
+ *
+ * inputs - client (server) to send nick towards
+ * - client to send nick for
+ * output - NONE
+ * side effects - NICK message is sent towards given client_p
+ */
+void
+sendnick_TS(struct Client *client_p, struct Client *target_p)
+{
+ static char ubuf[12];
+
+ if (!IsClient(target_p))
+ return;
+
+ send_umode(NULL, target_p, 0, SEND_UMODES, ubuf);
+
+ if (ubuf[0] == '\0')
+ {
+ ubuf[0] = '+';
+ ubuf[1] = '\0';
+ }
+
+ if (IsCapable(client_p, CAP_SVS))
+ {
+ if (HasID(target_p) && IsCapable(client_p, CAP_TS6))
+ sendto_one(client_p, ":%s UID %s %d %lu %s %s %s %s %s %s :%s",
+ target_p->servptr->id,
+ target_p->name, target_p->hopcount + 1,
+ (unsigned long) target_p->tsinfo,
+ ubuf, target_p->username, target_p->host,
+ (MyClient(target_p) && IsIPSpoof(target_p)) ?
+ "0" : target_p->sockhost, target_p->id,
+ target_p->svid, target_p->info);
+ else
+ sendto_one(client_p, "NICK %s %d %lu %s %s %s %s %s :%s",
+ target_p->name, target_p->hopcount + 1,
+ (unsigned long) target_p->tsinfo,
+ ubuf, target_p->username, target_p->host,
+ target_p->servptr->name, target_p->svid,
+ target_p->info);
+ }
+ else
+ {
+ if (HasID(target_p) && IsCapable(client_p, CAP_TS6))
+ sendto_one(client_p, ":%s UID %s %d %lu %s %s %s %s %s :%s",
+ target_p->servptr->id,
+ target_p->name, target_p->hopcount + 1,
+ (unsigned long) target_p->tsinfo,
+ ubuf, target_p->username, target_p->host,
+ (MyClient(target_p) && IsIPSpoof(target_p)) ?
+ "0" : target_p->sockhost, target_p->id, target_p->info);
+ else
+ sendto_one(client_p, "NICK %s %d %lu %s %s %s %s :%s",
+ target_p->name, target_p->hopcount + 1,
+ (unsigned long) target_p->tsinfo,
+ ubuf, target_p->username, target_p->host,
+ target_p->servptr->name, target_p->info);
+ }
+
+ if (target_p->away[0])
+ sendto_one(client_p, ":%s AWAY :%s", ID_or_name(target_p, client_p),
+ target_p->away);
+
+}
+
+/*
+ * show_capabilities - show current server capabilities
+ *
+ * inputs - pointer to a 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[IRCD_BUFSIZE];
+ char *t = msgbuf;
+ dlink_node *ptr;
+
+ t += ircsprintf(msgbuf, "TS ");
+
+ DLINK_FOREACH(ptr, cap_list.head)
+ {
+ const struct Capability *cap = ptr->data;
+
+ if (IsCapable(target_p, cap->cap))
+ t += ircsprintf(t, "%s ", cap->name);
+ }
+
+ *(t - 1) = '\0';
+ return msgbuf;
+}
+
+/* make_server()
+ *
+ * inputs - pointer to client struct
+ * output - pointer to struct Server
+ * side effects - add's an Server information block to a client
+ * if it was not previously allocated.
+ */
+struct Server *
+make_server(struct Client *client_p)
+{
+ if (client_p->serv == NULL)
+ client_p->serv = MyMalloc(sizeof(struct Server));
+
+ return client_p->serv;
+}
+
+/* server_estab()
+ *
+ * inputs - pointer to a struct Client
+ * output -
+ * side effects -
+ */
+void
+server_estab(struct Client *client_p)
+{
+ struct Client *target_p;
+ struct ConfItem *conf;
+ struct AccessItem *aconf=NULL;
+ char *host;
+ const char *inpath;
+ static char inpath_ip[HOSTLEN * 2 + USERLEN + 6];
+ dlink_node *ptr;
+#ifdef HAVE_LIBCRYPTO
+ const COMP_METHOD *compression = NULL, *expansion = NULL;
+#endif
+
+ assert(client_p != NULL);
+
+ strlcpy(inpath_ip, get_client_name(client_p, SHOW_IP), sizeof(inpath_ip));
+
+ inpath = get_client_name(client_p, MASK_IP); /* "refresh" inpath with host */
+ host = client_p->name;
+
+ if ((conf = find_conf_name(&client_p->localClient->confs, host, SERVER_TYPE))
+ == NULL)
+ {
+ /* This shouldn't happen, better tell the ops... -A1kmm */
+ sendto_realops_flags(UMODE_ALL, L_ALL, "Warning: Lost connect{} block "
+ "for server %s(this shouldn't happen)!", host);
+ exit_client(client_p, &me, "Lost connect{} block!");
+ return;
+ }
+
+ 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");
+ exit_client(client_p, &me, "I'm a leaf");
+ return;
+ }
+ }
+
+ aconf = map_to_conf(conf);
+
+ if (IsUnknown(client_p))
+ {
+ /* jdc -- 1. Use EmptyString(), not [0] index reference.
+ * 2. Check aconf->spasswd, not aconf->passwd.
+ */
+ if (!EmptyString(aconf->spasswd))
+ sendto_one(client_p, "PASS %s TS %d %s",
+ aconf->spasswd, TS_CURRENT, me.id);
+
+ /* Pass my info to the new server
+ *
+ * Pass on ZIP if supported
+ * Pass on TB if supported.
+ * - Dianora
+ */
+
+ send_capabilities(client_p, aconf, 0);
+
+ sendto_one(client_p, "SERVER %s 1 :%s%s",
+ me.name, ConfigServerHide.hidden ? "(H) " : "", me.info);
+ }
+
+ sendto_one(client_p, "SVINFO %d %d 0 :%lu", TS_CURRENT, TS_MIN,
+ (unsigned long)CurrentTime);
+
+ /* assumption here is if they passed the correct TS version, they also passed an SID */
+ if (IsCapable(client_p, CAP_TS6))
+ hash_add_id(client_p);
+
+ /* XXX Does this ever happen? I don't think so -db */
+ detach_conf(client_p, OPER_TYPE);
+
+ /* *WARNING*
+ ** In the following code in place of plain server's
+ ** name we send what is returned by get_client_name
+ ** which may add the "sockhost" after the name. It's
+ ** *very* *important* that there is a SPACE between
+ ** the name and sockhost (if present). The receiving
+ ** server will start the information field from this
+ ** first blank and thus puts the sockhost into info.
+ ** ...a bit tricky, but you have been warned, besides
+ ** code is more neat this way... --msa
+ */
+ client_p->servptr = &me;
+
+ if (IsClosing(client_p))
+ return;
+
+ SetServer(client_p);
+
+ /* Update the capability combination usage counts. -A1kmm */
+ set_chcap_usage_counts(client_p);
+
+ /* Some day, all these lists will be consolidated *sigh* */
+ dlinkAdd(client_p, &client_p->lnode, &me.serv->server_list);
+
+ assert(dlinkFind(&unknown_list, client_p));
+
+ dlink_move_node(&client_p->localClient->lclient_node,
+ &unknown_list, &serv_list);
+
+ Count.myserver++;
+
+ dlinkAdd(client_p, make_dlink_node(), &global_serv_list);
+ hash_add_client(client_p);
+
+ /* doesnt duplicate client_p->serv if allocated this struct already */
+ make_server(client_p);
+
+ /* fixing eob timings.. -gnp */
+ client_p->localClient->firsttime = CurrentTime;
+
+ if (find_matching_name_conf(SERVICE_TYPE, client_p->name, NULL, NULL, 0))
+ AddFlag(client_p, FLAGS_SERVICE);
+
+ /* Show the real host/IP to admins */
+#ifdef HAVE_LIBCRYPTO
+ if (client_p->localClient->fd.ssl)
+ {
+ compression = SSL_get_current_compression(client_p->localClient->fd.ssl);
+ expansion = SSL_get_current_expansion(client_p->localClient->fd.ssl);
+
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "Link with %s established: [SSL: %s, Compression/Expansion method: %s/%s] (Capabilities: %s)",
+ inpath_ip, ssl_get_cipher(client_p->localClient->fd.ssl),
+ compression ? SSL_COMP_get_name(compression) : "NONE",
+ expansion ? SSL_COMP_get_name(expansion) : "NONE",
+ show_capabilities(client_p));
+ /* Now show the masked hostname/IP to opers */
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "Link with %s established: [SSL: %s, Compression/Expansion method: %s/%s] (Capabilities: %s)",
+ inpath, ssl_get_cipher(client_p->localClient->fd.ssl),
+ compression ? SSL_COMP_get_name(compression) : "NONE",
+ expansion ? SSL_COMP_get_name(expansion) : "NONE",
+ show_capabilities(client_p));
+ ilog(LOG_TYPE_IRCD, "Link with %s established: [SSL: %s, Compression/Expansion method: %s/%s] (Capabilities: %s)",
+ inpath_ip, ssl_get_cipher(client_p->localClient->fd.ssl),
+ compression ? SSL_COMP_get_name(compression) : "NONE",
+ expansion ? SSL_COMP_get_name(expansion) : "NONE",
+ show_capabilities(client_p));
+ }
+ else
+#endif
+ {
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "Link with %s established: (Capabilities: %s)",
+ inpath_ip,show_capabilities(client_p));
+ /* Now show the masked hostname/IP to opers */
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "Link with %s established: (Capabilities: %s)",
+ inpath,show_capabilities(client_p));
+ ilog(LOG_TYPE_IRCD, "Link with %s established: (Capabilities: %s)",
+ inpath_ip, show_capabilities(client_p));
+ }
+
+ fd_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 (IsCapable(target_p, CAP_TS6) && HasID(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);
+ else
+ sendto_one(target_p,":%s SERVER %s 2 :%s%s",
+ me.name, client_p->name,
+ IsHidden(client_p) ? "(H) " : "",
+ client_p->info);
+ }
+
+ /* 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_PREV(ptr, global_serv_list.tail)
+ {
+ target_p = ptr->data;
+
+ /* target_p->from == target_p for target_p == client_p */
+ if (IsMe(target_p) || target_p->from == client_p)
+ continue;
+
+ if (IsCapable(client_p, CAP_TS6))
+ {
+ if (HasID(target_p))
+ sendto_one(client_p, ":%s SID %s %d %s :%s%s",
+ ID(target_p->servptr), target_p->name, target_p->hopcount+1,
+ target_p->id, IsHidden(target_p) ? "(H) " : "",
+ target_p->info);
+ else /* introducing non-ts6 server */
+ sendto_one(client_p, ":%s SERVER %s %d :%s%s",
+ ID(target_p->servptr), target_p->name, target_p->hopcount+1,
+ IsHidden(target_p) ? "(H) " : "", target_p->info);
+ }
+ else
+ sendto_one(client_p, ":%s SERVER %s %d :%s%s",
+ target_p->servptr->name, target_p->name, target_p->hopcount+1,
+ IsHidden(target_p) ? "(H) " : "", target_p->info);
+ }
+
+ server_burst(client_p);
+}
+
+/* server_burst()
+ *
+ * inputs - struct Client pointer server
+ * -
+ * output - none
+ * side effects - send a server burst
+ * bugs - still too long
+ */
+static void
+server_burst(struct Client *client_p)
+{
+ /* Send it in the shortened format with the TS, if
+ ** it's a TS server; walk the list of channels, sending
+ ** all the nicks that haven't been sent yet for each
+ ** channel, then send the channel itself -- it's less
+ ** obvious than sending all nicks first, but on the
+ ** receiving side memory will be allocated more nicely
+ ** saving a few seconds in the handling of a split
+ ** -orabidoo
+ */
+
+ burst_all(client_p);
+
+ /* EOB stuff is now in burst_all */
+ /* Always send a PING after connect burst is done */
+ sendto_one(client_p, "PING :%s", ID_or_name(&me, client_p));
+}
+
+/* burst_all()
+ *
+ * inputs - pointer to server to send burst to
+ * output - NONE
+ * side effects - complete burst of channels/nicks is sent to client_p
+ */
+static void
+burst_all(struct Client *client_p)
+{
+ dlink_node *ptr = NULL;
+
+ DLINK_FOREACH(ptr, global_channel_list.head)
+ {
+ struct Channel *chptr = ptr->data;
+
+ if (dlink_list_length(&chptr->members) != 0)
+ {
+ burst_members(client_p, chptr);
+ send_channel_modes(client_p, chptr);
+
+ if (IsCapable(client_p, CAP_TBURST))
+ send_tb(client_p, chptr);
+ }
+ }
+
+ /* also send out those that are not on any channel
+ */
+ DLINK_FOREACH(ptr, global_client_list.head)
+ {
+ struct Client *target_p = ptr->data;
+
+ if (!HasFlag(target_p, FLAGS_BURSTED) && target_p->from != client_p)
+ sendnick_TS(client_p, target_p);
+
+ DelFlag(target_p, FLAGS_BURSTED);
+ }
+
+ /* We send the time we started the burst, and let the remote host determine an EOB time,
+ ** as otherwise we end up sending a EOB of 0 Sending here means it gets sent last -- fl
+ */
+ /* Its simpler to just send EOB and use the time its been connected.. --fl_ */
+ if (IsCapable(client_p, CAP_EOB))
+ sendto_one(client_p, ":%s EOB", ID_or_name(&me, client_p));
+}
+
+/*
+ * send_tb
+ *
+ * inputs - pointer to Client
+ * - pointer to channel
+ * output - NONE
+ * side effects - Called on a server burst when
+ * server is CAP_TBURST capable
+ */
+static void
+send_tb(struct Client *client_p, struct Channel *chptr)
+{
+ /*
+ * We may also send an empty topic here, but only if topic_time isn't 0,
+ * i.e. if we had a topic that got unset. This is required for syncing
+ * topics properly.
+ *
+ * Imagine the following scenario: Our downlink introduces a channel
+ * to us with a TS that is equal to ours, but the channel topic on
+ * their side got unset while the servers were in splitmode, which means
+ * their 'topic' is newer. They simply wanted to unset it, so we have to
+ * deal with it in a more sophisticated fashion instead of just resetting
+ * it to their old topic they had before. Read m_tburst.c:ms_tburst
+ * for further information -Michael
+ */
+ if (chptr->topic_time != 0)
+ sendto_one(client_p, ":%s TBURST %lu %s %lu %s :%s",
+ ID_or_name(&me, client_p),
+ (unsigned long)chptr->channelts, chptr->chname,
+ (unsigned long)chptr->topic_time,
+ chptr->topic_info,
+ chptr->topic);
+}
+
+/* burst_members()
+ *
+ * inputs - pointer to server to send members to
+ * - dlink_list pointer to membership list to send
+ * output - NONE
+ * side effects -
+ */
+static void
+burst_members(struct Client *client_p, struct Channel *chptr)
+{
+ struct Client *target_p;
+ struct Membership *ms;
+ dlink_node *ptr;
+
+ DLINK_FOREACH(ptr, chptr->members.head)
+ {
+ ms = ptr->data;
+ target_p = ms->client_p;
+
+ if (!HasFlag(target_p, FLAGS_BURSTED))
+ {
+ AddFlag(target_p, FLAGS_BURSTED);
+
+ if (target_p->from != client_p)
+ sendnick_TS(client_p, target_p);
+ }
+ }
+}
+
+/* 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 connect
+ * 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 AccessItem *aconf, struct Client *by)
+{
+ struct ConfItem *conf;
+ struct Client *client_p;
+ char buf[HOSTIPLEN + 1];
+
+ /* conversion structs */
+ struct sockaddr_in *v4;
+ /* Make sure aconf is useful */
+ assert(aconf != NULL);
+
+ /* XXX should be passing struct ConfItem in the first place */
+ conf = unmap_conf_item(aconf);
+
+ /* log */
+ getnameinfo((struct sockaddr *)&aconf->addr, aconf->addr.ss_len,
+ buf, sizeof(buf), NULL, 0, NI_NUMERICHOST);
+ ilog(LOG_TYPE_IRCD, "Connect to %s[%s] @%s", conf->name, aconf->host,
+ buf);
+
+ /* Still processing a DNS lookup? -> exit */
+ if (aconf->dns_pending)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Error connecting to %s: DNS lookup for connect{} in progress.",
+ conf->name);
+ return (0);
+ }
+
+ if (aconf->dns_failed)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Error connecting to %s: DNS lookup for connect{} failed.",
+ conf->name);
+ return (0);
+ }
+
+ /* Make sure this server isn't already connected
+ * Note: aconf should ALWAYS be a valid C: line
+ */
+ if ((client_p = hash_find_server(conf->name)) != NULL)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "Server %s already present from %s",
+ conf->name, get_client_name(client_p, SHOW_IP));
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "Server %s already present from %s",
+ conf->name, get_client_name(client_p, MASK_IP));
+ if (by && IsClient(by) && !MyClient(by))
+ sendto_one(by, ":%s NOTICE %s :Server %s already present from %s",
+ me.name, by->name, conf->name,
+ get_client_name(client_p, MASK_IP));
+ return (0);
+ }
+
+ /* Create a local client */
+ client_p = make_client(NULL);
+
+ /* Copy in the server, hostname, fd */
+ strlcpy(client_p->name, conf->name, sizeof(client_p->name));
+ strlcpy(client_p->host, aconf->host, sizeof(client_p->host));
+
+ /* We already converted the ip once, so lets use it - stu */
+ strlcpy(client_p->sockhost, buf, sizeof(client_p->sockhost));
+
+ /* create a socket for the server connection */
+ if (comm_open(&client_p->localClient->fd, aconf->addr.ss.ss_family,
+ SOCK_STREAM, 0, NULL) < 0)
+ {
+ /* Eek, failure to create the socket */
+ report_error(L_ALL,
+ "opening stream socket to %s: %s", conf->name, errno);
+ SetDead(client_p);
+ exit_client(client_p, &me, "Connection failed");
+ return (0);
+ }
+
+ /* servernames are always guaranteed under HOSTLEN chars */
+ fd_note(&client_p->localClient->fd, "Server: %s", conf->name);
+
+ /* Attach config entries to client here rather than in
+ * serv_connect_callback(). This to avoid null pointer references.
+ */
+ if (!attach_connect_block(client_p, conf->name, aconf->host))
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Host %s is not enabled for connecting:no C/N-line",
+ conf->name);
+ if (by && IsClient(by) && !MyClient(by))
+ sendto_one(by, ":%s NOTICE %s :Connect to host %s failed.",
+ me.name, by->name, client_p->name);
+ SetDead(client_p);
+ exit_client(client_p, client_p, "Connection failed");
+ return (0);
+ }
+
+ /* 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 && IsClient(by))
+ strlcpy(client_p->serv->by, by->name, sizeof(client_p->serv->by));
+ else
+ strlcpy(client_p->serv->by, "AutoConn.", sizeof(client_p->serv->by));
+
+ SetConnecting(client_p);
+ dlinkAdd(client_p, &client_p->node, &global_client_list);
+ /* from def_fam */
+ client_p->localClient->aftype = aconf->aftype;
+
+ /* Now, initiate the connection */
+ /* XXX assume that a non 0 type means a specific bind address
+ * for this connect.
+ */
+ switch (aconf->aftype)
+ {
+ case AF_INET:
+ v4 = (struct sockaddr_in*)&aconf->bind;
+ if (v4->sin_addr.s_addr != 0)
+ {
+ struct irc_ssaddr ipn;
+ memset(&ipn, 0, sizeof(struct irc_ssaddr));
+ ipn.ss.ss_family = AF_INET;
+ ipn.ss_port = 0;
+ memcpy(&ipn, &aconf->bind, sizeof(struct irc_ssaddr));
+ comm_connect_tcp(&client_p->localClient->fd, aconf->host, aconf->port,
+ (struct sockaddr *)&ipn, ipn.ss_len,
+ serv_connect_callback, client_p, aconf->aftype,
+ CONNECTTIMEOUT);
+ }
+ else if (ServerInfo.specific_ipv4_vhost)
+ {
+ struct irc_ssaddr ipn;
+ memset(&ipn, 0, sizeof(struct irc_ssaddr));
+ ipn.ss.ss_family = AF_INET;
+ ipn.ss_port = 0;
+ memcpy(&ipn, &ServerInfo.ip, sizeof(struct irc_ssaddr));
+ comm_connect_tcp(&client_p->localClient->fd, aconf->host, aconf->port,
+ (struct sockaddr *)&ipn, ipn.ss_len,
+ serv_connect_callback, client_p, aconf->aftype,
+ CONNECTTIMEOUT);
+ }
+ else
+ comm_connect_tcp(&client_p->localClient->fd, aconf->host, aconf->port,
+ NULL, 0, serv_connect_callback, client_p, aconf->aftype,
+ CONNECTTIMEOUT);
+ break;
+#ifdef IPV6
+ case AF_INET6:
+ {
+ struct irc_ssaddr ipn;
+ struct sockaddr_in6 *v6;
+ struct sockaddr_in6 *v6conf;
+
+ memset(&ipn, 0, sizeof(struct irc_ssaddr));
+ v6conf = (struct sockaddr_in6 *)&aconf->bind;
+ v6 = (struct sockaddr_in6 *)&ipn;
+
+ if (memcmp(&v6conf->sin6_addr, &v6->sin6_addr,
+ sizeof(struct in6_addr)) != 0)
+ {
+ memcpy(&ipn, &aconf->bind, sizeof(struct irc_ssaddr));
+ ipn.ss.ss_family = AF_INET6;
+ ipn.ss_port = 0;
+ comm_connect_tcp(&client_p->localClient->fd,
+ aconf->host, aconf->port,
+ (struct sockaddr *)&ipn, ipn.ss_len,
+ serv_connect_callback, client_p,
+ aconf->aftype, CONNECTTIMEOUT);
+ }
+ else if (ServerInfo.specific_ipv6_vhost)
+ {
+ memcpy(&ipn, &ServerInfo.ip6, sizeof(struct irc_ssaddr));
+ ipn.ss.ss_family = AF_INET6;
+ ipn.ss_port = 0;
+ comm_connect_tcp(&client_p->localClient->fd,
+ aconf->host, aconf->port,
+ (struct sockaddr *)&ipn, ipn.ss_len,
+ serv_connect_callback, client_p,
+ aconf->aftype, CONNECTTIMEOUT);
+ }
+ else
+ comm_connect_tcp(&client_p->localClient->fd,
+ aconf->host, aconf->port,
+ NULL, 0, serv_connect_callback, client_p,
+ aconf->aftype, CONNECTTIMEOUT);
+ }
+#endif
+ }
+ return (1);
+}
+
+#ifdef HAVE_LIBCRYPTO
+static void
+finish_ssl_server_handshake(struct Client *client_p)
+{
+ struct ConfItem *conf=NULL;
+ struct AccessItem *aconf=NULL;
+
+ conf = find_conf_name(&client_p->localClient->confs,
+ client_p->name, SERVER_TYPE);
+ if (conf == NULL)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "Lost connect{} block for %s", get_client_name(client_p, HIDE_IP));
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "Lost connect{} block for %s", get_client_name(client_p, MASK_IP));
+
+ exit_client(client_p, &me, "Lost connect{} block");
+ return;
+ }
+
+ aconf = map_to_conf(conf);
+
+ /* jdc -- Check and send spasswd, not passwd. */
+ if (!EmptyString(aconf->spasswd))
+ sendto_one(client_p, "PASS %s TS %d %s",
+ aconf->spasswd, TS_CURRENT, me.id);
+
+ send_capabilities(client_p, aconf, 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 (IsDead(client_p))
+ {
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "%s[%s] went dead during handshake",
+ client_p->name,
+ client_p->host);
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "%s went dead during handshake", client_p->name);
+ 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 */
+ comm_setselect(&client_p->localClient->fd, COMM_SELECT_READ, read_packet, client_p, 0);
+}
+
+static void
+ssl_server_handshake(fde_t *fd, struct Client *client_p)
+{
+ int ret;
+ int err;
+
+ ret = SSL_connect(client_p->localClient->fd.ssl);
+
+ if (ret <= 0)
+ {
+ switch ((err = SSL_get_error(client_p->localClient->fd.ssl, ret)))
+ {
+ case SSL_ERROR_WANT_WRITE:
+ comm_setselect(&client_p->localClient->fd, COMM_SELECT_WRITE,
+ (PF *)ssl_server_handshake, client_p, 0);
+ return;
+ case SSL_ERROR_WANT_READ:
+ comm_setselect(&client_p->localClient->fd, COMM_SELECT_READ,
+ (PF *)ssl_server_handshake, client_p, 0);
+ return;
+ default:
+ {
+ const char *sslerr = ERR_error_string(ERR_get_error(), NULL);
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Error connecting to %s: %s", client_p->name,
+ sslerr ? sslerr : "unknown SSL error");
+ exit_client(client_p, client_p, "Error during SSL handshake");
+ return;
+ }
+ }
+ }
+
+ finish_ssl_server_handshake(client_p);
+}
+
+static void
+ssl_connect_init(struct Client *client_p, struct AccessItem *aconf, fde_t *fd)
+{
+ if ((client_p->localClient->fd.ssl = SSL_new(ServerInfo.client_ctx)) == NULL)
+ {
+ ilog(LOG_TYPE_IRCD, "SSL_new() ERROR! -- %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ SetDead(client_p);
+ exit_client(client_p, client_p, "SSL_new failed");
+ return;
+ }
+
+ SSL_set_fd(fd->ssl, fd->fd);
+
+ if (!EmptyString(aconf->cipher_list))
+ SSL_set_cipher_list(client_p->localClient->fd.ssl, aconf->cipher_list);
+
+ ssl_server_handshake(NULL, client_p);
+}
+#endif
+
+/* 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(fde_t *fd, int status, void *data)
+{
+ struct Client *client_p = data;
+ struct ConfItem *conf=NULL;
+ struct AccessItem *aconf=NULL;
+
+ /* First, make sure its a real client! */
+ assert(client_p != NULL);
+ assert(&client_p->localClient->fd == fd);
+
+ /* Next, for backward purposes, record the ip of the server */
+ memcpy(&client_p->localClient->ip, &fd->connect.hostaddr,
+ sizeof(struct irc_ssaddr));
+ /* Check the status */
+ if (status != COMM_OK)
+ {
+ /* We have an error, so report it and quit
+ * Admins get to see any IP, mere opers don't *sigh*
+ */
+ if (ConfigServerHide.hide_server_ips)
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "Error connecting to %s: %s",
+ client_p->name, comm_errstr(status));
+ else
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "Error connecting to %s[%s]: %s", client_p->name,
+ client_p->host, comm_errstr(status));
+
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "Error connecting to %s: %s",
+ client_p->name, comm_errstr(status));
+
+ /* If a fd goes bad, call dead_link() the socket is no
+ * longer valid for reading or writing.
+ */
+ dead_link_on_write(client_p, 0);
+ return;
+ }
+
+ /* COMM_OK, so continue the connection procedure */
+ /* Get the C/N lines */
+ conf = find_conf_name(&client_p->localClient->confs,
+ client_p->name, SERVER_TYPE);
+ if (conf == NULL)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "Lost connect{} block for %s", get_client_name(client_p, HIDE_IP));
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "Lost connect{} block for %s", get_client_name(client_p, MASK_IP));
+
+ exit_client(client_p, &me, "Lost connect{} block");
+ return;
+ }
+
+ aconf = map_to_conf(conf);
+ /* Next, send the initial handshake */
+ SetHandshake(client_p);
+
+#ifdef HAVE_LIBCRYPTO
+ if (IsConfSSL(aconf))
+ {
+ ssl_connect_init(client_p, aconf, fd);
+ return;
+ }
+#endif
+
+ /* jdc -- Check and send spasswd, not passwd. */
+ if (!EmptyString(aconf->spasswd))
+ sendto_one(client_p, "PASS %s TS %d %s",
+ aconf->spasswd, TS_CURRENT, me.id);
+
+ send_capabilities(client_p, aconf, 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 (IsDead(client_p))
+ {
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "%s[%s] went dead during handshake",
+ client_p->name,
+ client_p->host);
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "%s went dead during handshake", client_p->name);
+ 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 */
+ comm_setselect(fd, COMM_SELECT_READ, read_packet, client_p, 0);
+}
+
+struct Client *
+find_servconn_in_progress(const char *name)
+{
+ dlink_node *ptr;
+ struct Client *cptr;
+
+ DLINK_FOREACH(ptr, unknown_list.head)
+ {
+ cptr = ptr->data;
+
+ if (cptr && cptr->name[0])
+ if (match(name, cptr->name))
+ return cptr;
+ }
+
+ return NULL;
+}
diff --git a/src/s_user.c b/src/s_user.c
new file mode 100644
index 0000000..1973bfa
--- /dev/null
+++ b/src/s_user.c
@@ -0,0 +1,1484 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * s_user.c: User related functions.
+ *
+ * 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$
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "s_user.h"
+#include "s_misc.h"
+#include "channel.h"
+#include "channel_mode.h"
+#include "client.h"
+#include "fdlist.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "s_bsd.h"
+#include "ircd.h"
+#include "listener.h"
+#include "motd.h"
+#include "numeric.h"
+#include "conf.h"
+#include "log.h"
+#include "s_serv.h"
+#include "send.h"
+#include "supported.h"
+#include "whowas.h"
+#include "memory.h"
+#include "packet.h"
+#include "rng_mt.h"
+#include "userhost.h"
+#include "hook.h"
+#include "s_misc.h"
+#include "parse.h"
+#include "watch.h"
+
+
+struct Callback *entering_umode_cb = NULL;
+struct Callback *umode_cb = NULL;
+
+static char umode_buffer[IRCD_BUFSIZE];
+
+static void user_welcome(struct Client *);
+static void report_and_set_user_flags(struct Client *, const struct AccessItem *);
+static int check_xline(struct Client *);
+static void introduce_client(struct Client *);
+static const char *uid_get(void);
+
+/* Used for building up the isupport string,
+ * used with init_isupport, add_isupport, delete_isupport
+ */
+
+struct Isupport
+{
+ dlink_node node;
+ char *name;
+ char *options;
+ int number;
+};
+
+static dlink_list support_list = { NULL, NULL, 0 };
+MessageFile *isupportFile;
+
+/* memory is cheap. map 0-255 to equivalent mode */
+unsigned 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 */
+ UMODE_CCONN_FULL, /* C */
+ UMODE_DEAF, /* D */
+ 0, /* E */
+ 0, /* F */
+ UMODE_SOFTCALLERID, /* G */
+ UMODE_HIDDEN, /* H */
+ 0, /* I */
+ 0, /* J */
+ 0, /* K */
+ 0, /* L */
+ 0, /* M */
+ 0, /* N */
+ 0, /* O */
+ 0, /* P */
+ 0, /* Q */
+ UMODE_REGONLY, /* R */
+ 0, /* S */
+ 0, /* T */
+ 0, /* U */
+ 0, /* V */
+ 0, /* W */
+ 0, /* X */
+ 0, /* Y */
+ 0, /* Z 0x5A */
+ 0, 0, 0, 0, 0, /* 0x5F */
+ 0, /* 0x60 */
+ UMODE_ADMIN, /* a */
+ UMODE_BOTS, /* b */
+ UMODE_CCONN, /* c */
+ UMODE_DEBUG, /* d */
+ 0, /* e */
+ UMODE_FULL, /* f */
+ UMODE_CALLERID, /* g */
+ 0, /* h */
+ UMODE_INVISIBLE, /* i */
+ UMODE_REJ, /* j */
+ UMODE_SKILL, /* k */
+ UMODE_LOCOPS, /* l */
+ 0, /* m */
+ UMODE_NCHANGE, /* n */
+ UMODE_OPER, /* o */
+ 0, /* p */
+ 0, /* q */
+ UMODE_REGISTERED, /* r */
+ UMODE_SERVNOTICE, /* s */
+ 0, /* t */
+ UMODE_UNAUTH, /* u */
+ 0, /* v */
+ UMODE_WALLOP, /* w */
+ UMODE_EXTERNAL, /* x */
+ UMODE_SPY, /* y */
+ UMODE_OPERWALL, /* z 0x7A */
+ 0,0,0,0,0, /* 0x7B - 0x7F */
+
+ /* 0x80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x8F */
+ /* 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 */
+};
+
+void
+assemble_umode_buffer(void)
+{
+ unsigned int idx = 0;
+ char *umode_buffer_ptr = umode_buffer;
+
+ for (; idx < (sizeof(user_modes) / sizeof(user_modes[0])); ++idx)
+ if (user_modes[idx])
+ *umode_buffer_ptr++ = idx;
+
+ *umode_buffer_ptr = '\0';
+}
+
+/* show_lusers()
+ *
+ * inputs - pointer to client
+ * output - NONE
+ * side effects - display to client user counts etc.
+ */
+void
+show_lusers(struct Client *source_p)
+{
+ const char *from, *to;
+
+ if (!MyConnect(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
+ {
+ from = me.id;
+ to = source_p->id;
+ }
+ else
+ {
+ from = me.name;
+ to = source_p->name;
+ }
+
+ if (!ConfigServerHide.hide_servers || HasUMode(source_p, UMODE_OPER))
+ sendto_one(source_p, form_str(RPL_LUSERCLIENT),
+ from, to, (Count.total-Count.invisi),
+ Count.invisi, dlink_list_length(&global_serv_list));
+ else
+ sendto_one(source_p, form_str(RPL_LUSERCLIENT), from, to,
+ (Count.total-Count.invisi), Count.invisi, 1);
+
+ if (Count.oper > 0)
+ sendto_one(source_p, form_str(RPL_LUSEROP),
+ from, to, Count.oper);
+
+ if (dlink_list_length(&unknown_list) > 0)
+ sendto_one(source_p, form_str(RPL_LUSERUNKNOWN),
+ from, to, dlink_list_length(&unknown_list));
+
+ if (dlink_list_length(&global_channel_list) > 0)
+ sendto_one(source_p, form_str(RPL_LUSERCHANNELS),
+ from, to, dlink_list_length(&global_channel_list));
+
+ if (!ConfigServerHide.hide_servers || HasUMode(source_p, UMODE_OPER))
+ {
+ sendto_one(source_p, form_str(RPL_LUSERME),
+ from, to, Count.local, Count.myserver);
+ sendto_one(source_p, form_str(RPL_LOCALUSERS),
+ from, to, Count.local, Count.max_loc,
+ Count.local, Count.max_loc);
+ }
+ else
+ {
+ sendto_one(source_p, form_str(RPL_LUSERME),
+ from, to, Count.total, 0);
+ sendto_one(source_p, form_str(RPL_LOCALUSERS),
+ from, to, Count.total, Count.max_tot,
+ Count.total, Count.max_tot);
+ }
+
+ sendto_one(source_p, form_str(RPL_GLOBALUSERS),
+ from, to, Count.total, Count.max_tot,
+ Count.total, Count.max_tot);
+
+ if (!ConfigServerHide.hide_servers || HasUMode(source_p, UMODE_OPER))
+ sendto_one(source_p, form_str(RPL_STATSCONN), from, to,
+ Count.max_loc_con, Count.max_loc_cli, Count.totalrestartcount);
+
+ if (Count.local > Count.max_loc_cli)
+ Count.max_loc_cli = Count.local;
+
+ if ((Count.local + Count.myserver) > Count.max_loc_con)
+ Count.max_loc_con = Count.local + Count.myserver;
+}
+
+/* show_isupport()
+ *
+ * inputs - pointer to client
+ * output - NONE
+ * side effects - display to client what we support (for them)
+ */
+void
+show_isupport(struct Client *source_p)
+{
+ send_message_file(source_p, isupportFile);
+}
+
+/*
+** 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...
+*/
+void
+register_local_user(struct Client *source_p)
+{
+ const char *id = NULL;
+ const struct AccessItem *aconf = NULL;
+ dlink_node *ptr = NULL;
+
+ assert(source_p != NULL);
+ assert(source_p == source_p->from);
+ assert(MyConnect(source_p));
+ assert(!source_p->localClient->registration);
+
+ ClearCap(source_p, CAP_TS6);
+
+ if (ConfigFileEntry.ping_cookie)
+ {
+ if (!IsPingSent(source_p) && source_p->localClient->random_ping == 0)
+ {
+ do
+ source_p->localClient->random_ping = genrand_int32();
+ while (!source_p->localClient->random_ping);
+
+ sendto_one(source_p, "PING :%u",
+ source_p->localClient->random_ping);
+ SetPingSent(source_p);
+ return;
+ }
+
+ if (!HasPingCookie(source_p))
+ return;
+ }
+
+ source_p->localClient->last_privmsg = CurrentTime;
+ /* Straight up the maximum rate of flooding... */
+ source_p->localClient->allow_read = MAX_FLOOD_BURST;
+
+ if (!execute_callback(client_check_cb, source_p, source_p->username))
+ return;
+
+ if (valid_hostname(source_p->host) == 0)
+ {
+ 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));
+ }
+
+ ptr = source_p->localClient->confs.head;
+ aconf = map_to_conf(ptr->data);
+
+ if (!IsGotId(source_p))
+ {
+ char username[USERLEN + 1];
+ const char *p = username;
+ unsigned 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, source_p->name);
+ exit_client(source_p, &me, "Install identd");
+ return;
+ }
+
+ strlcpy(username, source_p->username, sizeof(username));
+
+ if (!IsNoTilde(aconf))
+ source_p->username[i++] = '~';
+
+ for (; *p && i < USERLEN; ++p)
+ if (*p != '[')
+ source_p->username[i++] = *p;
+
+ source_p->username[i] = '\0';
+ }
+
+ /* password check */
+ if (!EmptyString(aconf->passwd))
+ {
+ const char *pass = source_p->localClient->passwd;
+
+ if (!match_conf_password(pass, aconf))
+ {
+ ++ServerStats.is_ref;
+ sendto_one(source_p, form_str(ERR_PASSWDMISMATCH),
+ me.name, source_p->name);
+ exit_client(source_p, &me, "Bad Password");
+ return;
+ }
+ }
+
+ /* don't free source_p->localClient->passwd here - it can be required
+ * by masked /stats I if there are auth{} blocks with need_password = no;
+ * --adx
+ */
+
+ /* report if user has &^>= etc. and set flags as needed in source_p */
+ report_and_set_user_flags(source_p, aconf);
+
+ if (IsDead(source_p))
+ return;
+
+ /* 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 ((Count.local >= ServerInfo.max_clients + MAX_BUFFER) ||
+ (Count.local >= ServerInfo.max_clients && !IsExemptLimits(source_p)))
+ {
+ sendto_realops_flags(UMODE_FULL, L_ALL,
+ "Too many clients, rejecting %s[%s].",
+ source_p->name, source_p->host);
+ ++ServerStats.is_ref;
+ exit_client(source_p, &me, "Sorry, server is full - try later");
+ return;
+ }
+
+ /* valid user name check */
+ if (valid_username(source_p->username) == 0)
+ {
+ char tmpstr2[IRCD_BUFSIZE];
+
+ sendto_realops_flags(UMODE_REJ, L_ALL, "Invalid username: %s (%s@%s)",
+ source_p->name, source_p->username, source_p->host);
+ ++ServerStats.is_ref;
+ snprintf(tmpstr2, sizeof(tmpstr2), "Invalid username [%s]",
+ source_p->username);
+ exit_client(source_p, &me, tmpstr2);
+ return;
+ }
+
+ if (check_xline(source_p))
+ return;
+
+ while (hash_find_id((id = uid_get())) != NULL)
+ ;
+
+ strlcpy(source_p->id, id, sizeof(source_p->id));
+ hash_add_id(source_p);
+
+ sendto_realops_flags(UMODE_CCONN, L_ALL,
+ "Client connecting: %s (%s@%s) [%s] {%s} [%s] <%s>",
+ source_p->name, source_p->username, source_p->host,
+ ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ?
+ "255.255.255.255" : source_p->sockhost,
+ get_client_class(source_p),
+ source_p->info, source_p->id);
+
+ sendto_realops_flags(UMODE_CCONN_FULL, L_ALL,
+ "CLICONN %s %s %s %s %s %s %s 0 %s",
+ source_p->name, source_p->username, source_p->host,
+ ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ?
+ "255.255.255.255" : source_p->sockhost,
+ get_client_class(source_p),
+ ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ?
+ "<hidden>" : source_p->localClient->client_host,
+ ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ?
+ "<hidden>" : source_p->localClient->client_server,
+ source_p->info);
+
+
+ if (ConfigFileEntry.invisible_on_connect)
+ {
+ AddUMode(source_p, UMODE_INVISIBLE);
+ ++Count.invisi;
+ }
+
+ if ((++Count.local) > Count.max_loc)
+ {
+ Count.max_loc = Count.local;
+
+ if (!(Count.max_loc % 10))
+ sendto_realops_flags(UMODE_ALL, L_ALL, "New Max Local Clients: %d",
+ Count.max_loc);
+ }
+
+ /* Increment our total user count here */
+ if (++Count.total > Count.max_tot)
+ Count.max_tot = Count.total;
+ ++Count.totalrestartcount;
+
+ assert(source_p->servptr == &me);
+ SetClient(source_p);
+ dlinkAdd(source_p, &source_p->lnode, &source_p->servptr->serv->client_list);
+
+ source_p->localClient->allow_read = MAX_FLOOD_BURST;
+
+ assert(dlinkFind(&unknown_list, source_p));
+
+ dlink_move_node(&source_p->localClient->lclient_node,
+ &unknown_list, &local_client_list);
+
+ user_welcome(source_p);
+ add_user_host(source_p->username, source_p->host, 0);
+ SetUserHost(source_p);
+
+ introduce_client(source_p);
+}
+
+/* register_remote_user()
+ *
+ * inputs - source_p remote or directly connected client
+ * - username to register as
+ * - host name to register as
+ * - server name
+ * - realname (gecos)
+ * output - NONE
+ * side effects - This function is called when a remote client
+ * is introduced by a server.
+ */
+void
+register_remote_user(struct Client *source_p,
+ const char *username, const char *host, const char *server,
+ const char *realname)
+{
+ struct Client *target_p = NULL;
+
+ assert(source_p != NULL);
+ assert(source_p->username != username);
+
+ strlcpy(source_p->host, host, sizeof(source_p->host));
+ strlcpy(source_p->username, username, sizeof(source_p->username));
+
+ /*
+ * coming from another server, take the servers word for it
+ */
+ source_p->servptr = hash_find_server(server);
+
+ /* Super GhostDetect:
+ * If we can't find the server the user is supposed to be on,
+ * then simply blow the user away. -Taner
+ */
+ if (source_p->servptr == NULL)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "No server %s for user %s[%s@%s] from %s",
+ server, source_p->name, source_p->username,
+ source_p->host, source_p->from->name);
+ kill_client(source_p->from, source_p, "%s (Server doesn't exist)", me.name);
+
+ AddFlag(source_p, FLAGS_KILLED);
+ exit_client(source_p, &me, "Ghosted Client");
+ return;
+ }
+
+ if ((target_p = source_p->servptr) && target_p->from != source_p->from)
+ {
+ sendto_realops_flags(UMODE_DEBUG, L_ALL,
+ "Bad User [%s] :%s USER %s@%s %s, != %s[%s]",
+ source_p->from->name, source_p->name, source_p->username,
+ source_p->host, source_p->servptr->name,
+ target_p->name, target_p->from->name);
+ kill_client(source_p->from, source_p,
+ "%s (NICK from wrong direction (%s != %s))",
+ me.name, source_p->servptr->name, target_p->from->name);
+ AddFlag(source_p, FLAGS_KILLED);
+ exit_client(source_p, &me, "USER server wrong direction");
+ return;
+ }
+
+ /*
+ * If the nick has been introduced by a services server,
+ * make it a service as well.
+ */
+ if (HasFlag(source_p->servptr, FLAGS_SERVICE))
+ AddFlag(source_p, FLAGS_SERVICE);
+
+ /* Increment our total user count here */
+ if (++Count.total > Count.max_tot)
+ Count.max_tot = Count.total;
+
+ SetClient(source_p);
+ dlinkAdd(source_p, &source_p->lnode, &source_p->servptr->serv->client_list);
+ add_user_host(source_p->username, source_p->host, 1);
+ SetUserHost(source_p);
+
+ introduce_client(source_p);
+}
+
+/* introduce_client()
+ *
+ * inputs - source_p
+ * output - NONE
+ * 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.
+ */
+static void
+introduce_client(struct Client *source_p)
+{
+ dlink_node *server_node = NULL;
+ static char ubuf[12];
+
+ if (MyClient(source_p))
+ send_umode(source_p, source_p, 0, SEND_UMODES, ubuf);
+ else
+ send_umode(NULL, source_p, 0, SEND_UMODES, ubuf);
+
+ watch_check_hash(source_p, RPL_LOGON);
+
+ if (*ubuf == '\0')
+ {
+ ubuf[0] = '+';
+ ubuf[1] = '\0';
+ }
+
+ DLINK_FOREACH(server_node, serv_list.head)
+ {
+ struct Client *server = server_node->data;
+
+ if (server == source_p->from)
+ continue;
+
+ if (IsCapable(server, CAP_SVS))
+ {
+ if (IsCapable(server, CAP_TS6) && HasID(source_p))
+ sendto_one(server, ":%s UID %s %d %lu %s %s %s %s %s %s :%s",
+ source_p->servptr->id,
+ source_p->name, source_p->hopcount+1,
+ (unsigned long)source_p->tsinfo,
+ ubuf, source_p->username, source_p->host,
+ (MyClient(source_p) && IsIPSpoof(source_p)) ?
+ "0" : source_p->sockhost, source_p->id,
+ source_p->svid,
+ source_p->info);
+ else
+ sendto_one(server, "NICK %s %d %lu %s %s %s %s %s :%s",
+ source_p->name, source_p->hopcount+1,
+ (unsigned long)source_p->tsinfo,
+ ubuf, source_p->username, source_p->host,
+ source_p->servptr->name, source_p->svid,
+ source_p->info);
+
+ }
+ else
+ {
+ if (IsCapable(server, CAP_TS6) && HasID(source_p))
+ sendto_one(server, ":%s UID %s %d %lu %s %s %s %s %s :%s",
+ source_p->servptr->id,
+ source_p->name, source_p->hopcount+1,
+ (unsigned long)source_p->tsinfo,
+ ubuf, source_p->username, source_p->host,
+ (MyClient(source_p) && IsIPSpoof(source_p)) ?
+ "0" : source_p->sockhost, source_p->id, source_p->info);
+ else
+ sendto_one(server, "NICK %s %d %lu %s %s %s %s :%s",
+ source_p->name, source_p->hopcount+1,
+ (unsigned long)source_p->tsinfo,
+ ubuf, source_p->username, source_p->host,
+ source_p->servptr->name, source_p->info);
+ }
+ }
+}
+
+/* valid_hostname()
+ *
+ * Inputs - pointer to hostname
+ * Output - 1 if valid, 0 if not
+ * Side effects - check hostname for validity
+ *
+ * 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;
+
+ assert(p != NULL);
+
+ if (*p == '.' || *p == ':')
+ return 0;
+
+ for (; *p; ++p)
+ if (!IsHostChar(*p))
+ return 0;
+
+ return 1;
+}
+
+/* valid_username()
+ *
+ * Inputs - pointer to user
+ * Output - 1 if valid, 0 if not
+ * Side effects - check username for validity
+ *
+ * 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;
+
+ assert(p != NULL);
+
+ 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 0;
+
+ while (*++p)
+ {
+ if ((*p == '.') && ConfigFileEntry.dots_in_ident)
+ {
+ if (++dots > ConfigFileEntry.dots_in_ident)
+ return 0;
+ if (!IsUserChar(*(p + 1)))
+ return 0;
+ }
+ else if (!IsUserChar(*p))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* clean_nick_name()
+ *
+ * input - nickname
+ * - whether it's a local nick (1) or remote (0)
+ * output - none
+ * side effects - walks through the nickname, returning 0 if erroneous
+ */
+int
+valid_nickname(const char *nickname, const int local)
+{
+ const char *p = nickname;
+ assert(nickname && *nickname);
+
+ /* nicks can't start with a digit or - or be 0 length */
+ /* This closer duplicates behaviour of hybrid-6 */
+ if (*p == '-' || (IsDigit(*p) && local) || *p == '\0')
+ return 0;
+
+ for (; *p; ++p)
+ if (!IsNickChar(*p))
+ return 0;
+
+ return p - nickname <= NICKLEN;
+}
+
+/* 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, const struct AccessItem *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 lines. congrats.",
+ me.name, source_p->name);
+ }
+
+ /* The else here is to make sure that G line exempt users
+ * do not get noticed twice.
+ */
+ else if (IsConfExemptGline(aconf))
+ {
+ SetExemptGline(source_p);
+ sendto_one(source_p, ":%s NOTICE %s :*** You are exempt from G lines.",
+ 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 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 (IsConfCanFlood(aconf))
+ {
+ SetCanFlood(source_p);
+ sendto_one(source_p, ":%s NOTICE %s :*** You are exempt from flood "
+ "protection, aren't you fearsome.",
+ me.name, source_p->name);
+ }
+}
+
+/* change_simple_umode()
+ *
+ * this callback can be hooked to allow special handling of
+ * certain usermodes
+ */
+static void *
+change_simple_umode(va_list args)
+{
+ struct Client *client_p;
+ struct Client *source_p;
+ int what;
+ unsigned int flag;
+
+ client_p = va_arg(args, struct Client *);
+ source_p = va_arg(args, struct Client *);
+ what = va_arg(args, int);
+ flag = va_arg(args, unsigned int);
+
+ if (what == MODE_ADD)
+ AddUMode(source_p, flag);
+ else
+ DelUMode(source_p, flag);
+
+ return NULL;
+}
+
+/* set_user_mode()
+ *
+ * added 15/10/91 By Darren Reed.
+ * parv[0] - sender
+ * parv[1] - username to change mode for
+ * parv[2] - modes to change
+ */
+void
+set_user_mode(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ unsigned int flag, setflags;
+ char **p, *m, buf[IRCD_BUFSIZE];
+ struct Client *target_p;
+ int what = MODE_ADD, badflag = 0, i;
+
+ assert(!(parc < 2));
+
+ if ((target_p = find_person(client_p, parv[1])) == NULL)
+ {
+ if (MyConnect(source_p))
+ sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
+ me.name, source_p->name, parv[1]);
+ return;
+ }
+
+ if (IsServer(source_p))
+ {
+ sendto_realops_flags(UMODE_ALL, L_ADMIN, "*** Mode for User %s from %s",
+ parv[1], source_p->name);
+ return;
+ }
+
+ if (source_p != target_p)
+ {
+ sendto_one(source_p, form_str(ERR_USERSDONTMATCH),
+ me.name, source_p->name);
+ return;
+ }
+
+ if (parc < 3)
+ {
+ m = buf;
+ *m++ = '+';
+
+ for (i = 0; i < 128; i++)
+ if (HasUMode(source_p, user_modes[i]))
+ *m++ = (char)i;
+ *m = '\0';
+
+ sendto_one(source_p, form_str(RPL_UMODEIS),
+ me.name, source_p->name, buf);
+ return;
+ }
+
+ execute_callback(entering_umode_cb, client_p, source_p);
+
+ /* find flags already set for user */
+ setflags = source_p->umodes;
+
+ /* parse mode change string(s) */
+ for (p = &parv[2]; p && *p; p++)
+ {
+ for (m = *p; *m; m++)
+ {
+ switch (*m)
+ {
+ case '+':
+ what = MODE_ADD;
+ break;
+ case '-':
+ what = MODE_DEL;
+ break;
+ case 'o':
+ if (what == MODE_ADD)
+ {
+ if (IsServer(client_p) && !HasUMode(source_p, UMODE_OPER))
+ {
+ ++Count.oper;
+ SetOper(source_p);
+ }
+ }
+ else
+ {
+ /* Only decrement the oper counts if an oper to begin with
+ * found by Pat Szuta, Perly , perly@xnet.com
+ */
+ if (!HasUMode(source_p, UMODE_OPER))
+ break;
+
+ ClearOper(source_p);
+ Count.oper--;
+
+ if (MyConnect(source_p))
+ {
+ dlink_node *dm;
+
+ detach_conf(source_p, OPER_TYPE);
+ ClrOFlag(source_p);
+ DelUMode(source_p, ConfigFileEntry.oper_only_umodes);
+
+ if ((dm = dlinkFindDelete(&oper_list, source_p)) != NULL)
+ free_dlink_node(dm);
+ }
+ }
+
+ break;
+
+ /* we may not get these,
+ * but they shouldnt be in default
+ */
+ case 'r':
+ case ' ' :
+ case '\n':
+ case '\r':
+ case '\t':
+ break;
+
+ default:
+ if ((flag = user_modes[(unsigned char)*m]))
+ {
+ if (MyConnect(source_p) && !HasUMode(source_p, UMODE_OPER) &&
+ (ConfigFileEntry.oper_only_umodes & flag))
+ {
+ badflag = 1;
+ }
+ else
+ execute_callback(umode_cb, client_p, source_p, what, flag);
+ }
+ else
+ {
+ if (MyConnect(source_p))
+ badflag = 1;
+ }
+
+ break;
+ }
+ }
+ }
+
+ if (badflag)
+ sendto_one(source_p, form_str(ERR_UMODEUNKNOWNFLAG),
+ me.name, source_p->name);
+
+ if (HasUMode(source_p, UMODE_NCHANGE) && !HasOFlag(source_p, OPER_FLAG_N))
+ {
+ sendto_one(source_p, ":%s NOTICE %s :*** You have no nchange flag;",
+ me.name, source_p->name);
+ DelUMode(source_p, UMODE_NCHANGE);
+ }
+
+ if (MyConnect(source_p) && HasUMode(source_p, UMODE_ADMIN) &&
+ !HasOFlag(source_p, OPER_FLAG_ADMIN))
+ {
+ sendto_one(source_p, ":%s NOTICE %s :*** You have no admin flag;",
+ me.name, source_p->name);
+ DelUMode(source_p, UMODE_ADMIN);
+ }
+
+ if (!(setflags & UMODE_INVISIBLE) && HasUMode(source_p, UMODE_INVISIBLE))
+ ++Count.invisi;
+ if ((setflags & UMODE_INVISIBLE) && !HasUMode(source_p, UMODE_INVISIBLE))
+ --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);
+}
+
+/* send_umode()
+ * send the MODE string for user (user) to connection client_p
+ * -avalon
+ *
+ * inputs - client_p
+ * - source_p
+ * - int old
+ * - sendmask mask of modes to send
+ * - suplied umode_buf
+ * output - NONE
+ */
+void
+send_umode(struct Client *client_p, struct Client *source_p,
+ unsigned int old, unsigned int sendmask, char *umode_buf)
+{
+ char *m = umode_buf;
+ int what = 0;
+ unsigned int i;
+ unsigned int flag;
+
+ /*
+ * build a string in umode_buf to represent the change in the user's
+ * mode between the new (source_p->umodes) and 'old'.
+ */
+ for (i = 0; i < 128; i++)
+ {
+ flag = user_modes[i];
+ if (!flag)
+ continue;
+
+ if (MyClient(source_p) && !(flag & sendmask))
+ continue;
+
+ if ((flag & old) && !HasUMode(source_p, flag))
+ {
+ if (what == MODE_DEL)
+ *m++ = (char)i;
+ else
+ {
+ what = MODE_DEL;
+ *m++ = '-';
+ *m++ = (char)i;
+ }
+ }
+ else if (!(flag & old) && HasUMode(source_p, 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!%s@%s MODE %s :%s",
+ source_p->name, source_p->username,
+ source_p->host, source_p->name, umode_buf);
+}
+
+/* send_umode_out()
+ *
+ * inputs -
+ * output - NONE
+ * side effects - Only send ubuf out to servers that know about this client
+ */
+void
+send_umode_out(struct Client *client_p, struct Client *source_p,
+ unsigned int old)
+{
+ char buf[IRCD_BUFSIZE] = { '\0' };
+ dlink_node *ptr = NULL;
+
+ send_umode(NULL, source_p, old, SEND_UMODES, buf);
+
+ if (buf[0])
+ {
+ DLINK_FOREACH(ptr, serv_list.head)
+ {
+ struct Client *target_p = ptr->data;
+
+ if ((target_p != client_p) && (target_p != source_p))
+ sendto_one(target_p, ":%s MODE %s :%s",
+ ID_or_name(source_p, target_p),
+ ID_or_name(source_p, target_p), buf);
+ }
+ }
+
+ if (client_p && MyClient(client_p))
+ send_umode(client_p, source_p, old, 0xffffffff, buf);
+}
+
+/* user_welcome()
+ *
+ * inputs - client pointer to client to welcome
+ * output - NONE
+ * side effects -
+ */
+static void
+user_welcome(struct Client *source_p)
+{
+#if defined(__TIME__) && defined(__DATE__)
+ static const char built_date[] = __DATE__ " at " __TIME__;
+#else
+ static const char built_date[] = "unknown";
+#endif
+
+#ifdef HAVE_LIBCRYPTO
+ if (source_p->localClient->fd.ssl != NULL)
+ sendto_one(source_p, ":%s NOTICE %s :*** Connected securely via %s",
+ me.name, source_p->name,
+ ssl_get_cipher(source_p->localClient->fd.ssl));
+#endif
+
+ 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, built_date);
+ sendto_one(source_p, form_str(RPL_MYINFO),
+ me.name, source_p->name, me.name, ircd_version, umode_buffer);
+ show_isupport(source_p);
+
+ if (source_p->id[0] != '\0')
+ sendto_one(source_p, form_str(RPL_YOURID), me.name,
+ source_p->name, source_p->id);
+
+ show_lusers(source_p);
+
+ if (ConfigFileEntry.short_motd)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :*** Notice -- motd was last changed at %s",
+ me.name, source_p->name, ConfigFileEntry.motd.lastChangedDate);
+ sendto_one(source_p,
+ ":%s NOTICE %s :*** Notice -- Please read the motd if you haven't "
+ "read it", me.name, 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_message_file(source_p, &ConfigFileEntry.motd);
+}
+
+/* check_xline()
+ *
+ * inputs - pointer to client to test
+ * outupt - 1 if exiting 0 if ok
+ * side effects -
+ */
+static int
+check_xline(struct Client *source_p)
+{
+ struct ConfItem *conf = NULL;
+ const char *reason = NULL;
+
+ if ((conf = find_matching_name_conf(XLINE_TYPE, source_p->info, NULL, NULL, 0)) ||
+ (conf = find_matching_name_conf(RXLINE_TYPE, source_p->info, NULL, NULL, 0)))
+ {
+ struct MatchItem *reg = map_to_conf(conf);
+
+ ++reg->count;
+
+ if (reg->reason != NULL)
+ reason = reg->reason;
+ else
+ reason = "No Reason";
+
+ sendto_realops_flags(UMODE_REJ, L_ALL,
+ "X-line Rejecting [%s] [%s], user %s [%s]",
+ source_p->info, reason,
+ get_client_name(source_p, HIDE_IP),
+ source_p->sockhost);
+
+ ++ServerStats.is_ref;
+ exit_client(source_p, &me, "Bad user info");
+ return 1;
+ }
+
+ return 0;
+}
+
+/* oper_up()
+ *
+ * inputs - pointer to given client to oper
+ * output - NONE
+ * side effects - Blindly opers up given source_p, using aconf info
+ * all checks on passwords have already been done.
+ * This could also be used by rsa oper routines.
+ */
+void
+oper_up(struct Client *source_p)
+{
+ const unsigned int old = source_p->umodes;
+ const struct AccessItem *oconf = NULL;
+
+ assert(source_p->localClient->confs.head);
+ oconf = map_to_conf((source_p->localClient->confs.head)->data);
+
+ ++Count.oper;
+ SetOper(source_p);
+
+ if (oconf->modes)
+ AddUMode(source_p, oconf->modes);
+ else if (ConfigFileEntry.oper_umodes)
+ AddUMode(source_p, ConfigFileEntry.oper_umodes);
+
+ if (!(old & UMODE_INVISIBLE) && HasUMode(source_p, UMODE_INVISIBLE))
+ ++Count.invisi;
+ if ((old & UMODE_INVISIBLE) && !HasUMode(source_p, UMODE_INVISIBLE))
+ --Count.invisi;
+
+ assert(dlinkFind(&oper_list, source_p) == NULL);
+ dlinkAdd(source_p, make_dlink_node(), &oper_list);
+
+ AddOFlag(source_p, oconf->port);
+
+ if (HasOFlag(source_p, OPER_FLAG_ADMIN))
+ AddUMode(source_p, UMODE_ADMIN);
+ if (!HasOFlag(source_p, OPER_FLAG_N))
+ DelUMode(source_p, UMODE_NCHANGE);
+
+ sendto_realops_flags(UMODE_ALL, L_ALL, "%s is now an operator",
+ get_oper_name(source_p));
+ send_umode_out(source_p, source_p, old);
+ sendto_one(source_p, form_str(RPL_YOUREOPER), me.name, source_p->name);
+}
+
+static char new_uid[TOTALSIDUID + 1]; /* allow for \0 */
+
+int
+valid_sid(const char *sid)
+{
+ if (strlen(sid) == IRC_MAXSID)
+ if (IsDigit(*sid))
+ if (IsAlNum(*(sid + 1)) && IsAlNum(*(sid + 2)))
+ return 1;
+
+ return 0;
+}
+
+/*
+ * init_uid()
+ *
+ * inputs - NONE
+ * output - NONE
+ * side effects - new_uid is filled in with server id portion (sid)
+ * (first 3 bytes) or defaulted to 'A'.
+ * Rest is filled in with 'A'
+ */
+void
+init_uid(void)
+{
+ int i;
+
+ memset(new_uid, 0, sizeof(new_uid));
+
+ if (!EmptyString(ServerInfo.sid))
+ strlcpy(new_uid, ServerInfo.sid, sizeof(new_uid));
+
+ for (i = 0; i < IRC_MAXSID; ++i)
+ if (new_uid[i] == '\0')
+ new_uid[i] = 'A';
+
+ /* NOTE: if IRC_MAXUID != 6, this will have to be rewritten */
+ /* Yes nenolod, I have known it was off by one ever since I wrote it
+ * But *JUST* for you, though, it really doesn't look as *pretty*
+ * -Dianora
+ */
+ memcpy(new_uid + IRC_MAXSID, "AAAAA@", IRC_MAXUID);
+
+ entering_umode_cb = register_callback("entering_umode", NULL);
+ umode_cb = register_callback("changing_umode", change_simple_umode);
+}
+
+/*
+ * add_one_to_uid
+ *
+ * inputs - index number into new_uid
+ * output - NONE
+ * side effects - new_uid is incremented by one
+ * note this is a recursive function
+ */
+static void
+add_one_to_uid(int i)
+{
+ if (i != IRC_MAXSID) /* Not reached server SID portion yet? */
+ {
+ if (new_uid[i] == 'Z')
+ new_uid[i] = '0';
+ else if (new_uid[i] == '9')
+ {
+ new_uid[i] = 'A';
+ add_one_to_uid(i-1);
+ }
+ else
+ ++new_uid[i];
+ }
+ else
+ {
+ /* NOTE: if IRC_MAXUID != 6, this will have to be rewritten */
+ if (new_uid[i] == 'Z')
+ memcpy(new_uid + IRC_MAXSID, "AAAAAA", IRC_MAXUID);
+ else
+ ++new_uid[i];
+ }
+}
+
+/*
+ * uid_get
+ *
+ * inputs - struct Client *
+ * output - new UID is returned to caller
+ * side effects - new_uid is incremented by one.
+ */
+static const char *
+uid_get(void)
+{
+ add_one_to_uid(TOTALSIDUID - 1); /* index from 0 */
+ return new_uid;
+}
+
+/*
+ * init_isupport()
+ *
+ * input - NONE
+ * output - NONE
+ * side effects - Must be called before isupport is enabled
+ */
+void
+init_isupport(void)
+{
+ isupportFile = init_MessageLine();
+
+ add_isupport("CALLERID", NULL, -1);
+ add_isupport("CASEMAPPING", CASEMAP, -1);
+ add_isupport("DEAF", "D", -1);
+ add_isupport("KICKLEN", NULL, KICKLEN);
+ add_isupport("MODES", NULL, MAXMODEPARAMS);
+ add_isupport("NICKLEN", NULL, NICKLEN);
+#ifdef HALFOPS
+ add_isupport("PREFIX", "(ohv)@%+", -1);
+ add_isupport("STATUSMSG", "@%+", -1);
+#else
+ add_isupport("PREFIX", "(ov)@+", -1);
+ add_isupport("STATUSMSG", "@+", -1);
+#endif
+ add_isupport("TOPICLEN", NULL, TOPICLEN);
+}
+
+/*
+ * add_isupport()
+ *
+ * input - name of supported function
+ * - options if any
+ * - number if any
+ * output - NONE
+ * side effects - Each supported item must call this when activated
+ */
+void
+add_isupport(const char *name, const char *options, int n)
+{
+ dlink_node *ptr;
+ struct Isupport *support;
+
+ DLINK_FOREACH(ptr, support_list.head)
+ {
+ support = ptr->data;
+ if (irccmp(support->name, name) == 0)
+ {
+ MyFree(support->name);
+ MyFree(support->options);
+ break;
+ }
+ }
+
+ if (ptr == NULL)
+ {
+ support = MyMalloc(sizeof(*support));
+ dlinkAddTail(support, &support->node, &support_list);
+ }
+
+ DupString(support->name, name);
+ if (options != NULL)
+ DupString(support->options, options);
+ support->number = n;
+
+ rebuild_isupport_message_line();
+}
+
+/*
+ * delete_isupport()
+ *
+ * input - name of supported function
+ * output - NONE
+ * side effects - Each supported item must call this when deactivated
+ */
+void
+delete_isupport(const char *name)
+{
+ dlink_node *ptr;
+ struct Isupport *support;
+
+ DLINK_FOREACH(ptr, support_list.head)
+ {
+ support = ptr->data;
+ if (irccmp(support->name, name) == 0)
+ {
+ dlinkDelete(ptr, &support_list);
+ MyFree(support->name);
+ MyFree(support->options);
+ MyFree(support);
+ break;
+ }
+ }
+
+ rebuild_isupport_message_line();
+}
+
+/*
+ * rebuild_isupport_message_line
+ *
+ * input - NONE
+ * output - NONE
+ * side effects - Destroy the isupport MessageFile lines, and rebuild.
+ */
+void
+rebuild_isupport_message_line(void)
+{
+ char isupportbuffer[IRCD_BUFSIZE];
+ char *p = isupportbuffer;
+ dlink_node *ptr = NULL;
+ int n = 0;
+ int tokens = 0;
+ size_t len = 0;
+ size_t reserve = strlen(me.name) + HOSTLEN + strlen(form_str(RPL_ISUPPORT));
+
+ destroy_MessageLine(isupportFile);
+
+ DLINK_FOREACH(ptr, support_list.head)
+ {
+ struct Isupport *support = ptr->data;
+
+ p += (n = ircsprintf(p, "%s", support->name));
+ len += n;
+
+ if (support->options != NULL)
+ {
+ p += (n = ircsprintf(p, "=%s", support->options));
+ len += n;
+ }
+
+ if (support->number > 0)
+ {
+ p += (n = ircsprintf(p, "=%d", support->number));
+ len += n;
+ }
+
+ *p++ = ' ';
+ len++;
+ *p = '\0';
+
+ if (++tokens == (MAXPARA-2) || len >= (sizeof(isupportbuffer)-reserve))
+ { /* arbritrary for now */
+ if (*--p == ' ')
+ *p = '\0';
+
+ addto_MessageLine(isupportFile, isupportbuffer);
+ p = isupportbuffer;
+ len = 0;
+ n = tokens = 0;
+ }
+ }
+
+ if (len != 0)
+ {
+ if (*--p == ' ')
+ *p = '\0';
+ addto_MessageLine(isupportFile, isupportbuffer);
+ }
+}
diff --git a/src/send.c b/src/send.c
new file mode 100644
index 0000000..afa684e
--- /dev/null
+++ b/src/send.c
@@ -0,0 +1,1111 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * send.c: Functions for sending messages.
+ *
+ * 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$
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "send.h"
+#include "channel.h"
+#include "client.h"
+#include "dbuf.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "fdlist.h"
+#include "s_bsd.h"
+#include "s_serv.h"
+#include "sprintf_irc.h"
+#include "conf.h"
+#include "log.h"
+#include "memory.h"
+#include "hook.h"
+#include "packet.h"
+
+
+struct Callback *iosend_cb = NULL;
+static unsigned int current_serial = 0;
+
+
+/* send_format()
+ *
+ * inputs - buffer to format into
+ * - size of the buffer
+ * - format pattern to use
+ * - var args
+ * output - number of bytes formatted output
+ * side effects - modifies sendbuf
+ */
+static inline int
+send_format(char *lsendbuf, int bufsize, const char *pattern, va_list args)
+{
+ int len;
+
+ /*
+ * from rfc1459
+ *
+ * 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.
+ */
+ len = vsnprintf(lsendbuf, bufsize - 1, pattern, args);
+ if (len > bufsize - 2)
+ len = bufsize - 2; /* required by some versions of vsnprintf */
+
+ lsendbuf[len++] = '\r';
+ lsendbuf[len++] = '\n';
+ return len;
+}
+
+/*
+ * iosend_default - append a packet to the client's sendq.
+ */
+void *
+iosend_default(va_list args)
+{
+ struct Client *to = va_arg(args, struct Client *);
+ int length = va_arg(args, int);
+ char *buf = va_arg(args, char *);
+
+ dbuf_put(&to->localClient->buf_sendq, buf, length);
+ return NULL;
+}
+
+/*
+ ** send_message
+ ** Internal utility which appends given buffer to the sockets
+ ** sendq.
+ */
+static void
+send_message(struct Client *to, char *buf, int len)
+{
+ assert(!IsMe(to));
+ assert(to != &me);
+
+ if (dbuf_length(&to->localClient->buf_sendq) + len > get_sendq(to))
+ {
+ if (IsServer(to))
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Max SendQ limit exceeded for %s: %lu > %lu",
+ get_client_name(to, HIDE_IP),
+ (unsigned long)(dbuf_length(&to->localClient->buf_sendq) + len),
+ get_sendq(to));
+ if (IsClient(to))
+ SetSendQExceeded(to);
+ dead_link_on_write(to, 0);
+ return;
+ }
+
+ execute_callback(iosend_cb, to, len, buf);
+
+ /*
+ ** 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->send.messages;
+ ++me.localClient->send.messages;
+
+ if (dbuf_length(&to->localClient->buf_sendq) >
+ (IsServer(to) ? (unsigned int) 1024 : (unsigned int) 4096))
+ send_queued_write(to);
+}
+
+/* send_message_remote()
+ *
+ * inputs - pointer to client from message is being sent
+ * - pointer to client to send to
+ * - pointer to preformatted buffer
+ * - length of input buffer
+ * output - none
+ * side effects - Despite the function name, this only sends to directly
+ * connected clients.
+ *
+ */
+static void
+send_message_remote(struct Client *to, struct Client *from,
+ char *buf, int len)
+{
+ if (!MyConnect(to))
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "server send message to %s [%s] dropped from %s(Not local server)",
+ to->name, to->from->name, from->name);
+ return;
+ }
+
+ /* Optimize by checking if (from && to) before everything */
+ /* we set to->from up there.. */
+
+ if (!MyClient(from) && IsClient(to) && (to == from->from))
+ {
+ if (IsServer(from))
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Send message to %s [%s] dropped from %s(Fake Dir)",
+ to->name, to->from->name, from->name);
+ return;
+ }
+
+ sendto_realops_flags(UMODE_ALL, 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);
+
+ sendto_server(NULL, CAP_TS6, NOCAPS,
+ ":%s KILL %s :%s (%s[%s@%s] Ghosted %s)",
+ me.id, to->name, me.name, to->name,
+ to->username, to->host, to->from->name);
+ sendto_server(NULL, NOCAPS, CAP_TS6,
+ ":%s KILL %s :%s (%s[%s@%s] Ghosted %s)",
+ me.name, to->name, me.name, to->name,
+ to->username, to->host, to->from->name);
+
+ AddFlag(to, FLAGS_KILLED);
+
+ if (IsClient(from))
+ sendto_one(from, form_str(ERR_GHOSTEDCLIENT),
+ me.name, from->name, to->name, to->username,
+ to->host, to->from);
+
+ exit_client(to, &me, "Ghosted client");
+
+ return;
+ }
+
+ send_message(to, buf, len);
+}
+
+/*
+ ** sendq_unblocked
+ ** Called when a socket is ready for writing.
+ */
+void
+sendq_unblocked(fde_t *fd, struct Client *client_p)
+{
+ ClearSendqBlocked(client_p);
+ /* let send_queued_write be executed by send_queued_all */
+
+#ifdef HAVE_LIBCRYPTO
+ if (fd->flags.pending_read)
+ {
+ fd->flags.pending_read = 0;
+ read_packet(fd, client_p);
+ }
+#endif
+}
+
+/*
+ ** send_queued_write
+ ** This is called when there is a chance that some output would
+ ** be possible. This attempts to empty the send queue as far as
+ ** possible, and then if any data is left, a write is rescheduled.
+ */
+void
+send_queued_write(struct Client *to)
+{
+ int retlen;
+ struct dbuf_block *first;
+
+ /*
+ ** Once socket is marked dead, we cannot start writing to it,
+ ** even if the error is removed...
+ */
+ if (IsDead(to) || IsSendqBlocked(to))
+ return; /* no use calling send() now */
+
+ /* Next, lets try to write some data */
+
+ if (dbuf_length(&to->localClient->buf_sendq))
+ {
+ do {
+ first = to->localClient->buf_sendq.blocks.head->data;
+
+#ifdef HAVE_LIBCRYPTO
+ if (to->localClient->fd.ssl)
+ {
+ retlen = SSL_write(to->localClient->fd.ssl, first->data, first->size);
+
+ /* translate openssl error codes, sigh */
+ if (retlen < 0)
+ switch (SSL_get_error(to->localClient->fd.ssl, retlen))
+ {
+ case SSL_ERROR_WANT_READ:
+ return; /* retry later, don't register for write events */
+
+ case SSL_ERROR_WANT_WRITE:
+ errno = EWOULDBLOCK;
+ case SSL_ERROR_SYSCALL:
+ break;
+ case SSL_ERROR_SSL:
+ if (errno == EAGAIN)
+ break;
+ default:
+ retlen = errno = 0; /* either an SSL-specific error or EOF */
+ }
+ }
+ else
+#endif
+ retlen = send(to->localClient->fd.fd, first->data, first->size, 0);
+
+ if (retlen <= 0)
+ break;
+
+ dbuf_delete(&to->localClient->buf_sendq, retlen);
+
+ /* We have some data written .. update counters */
+ to->localClient->send.bytes += retlen;
+ me.localClient->send.bytes += retlen;
+ } while (dbuf_length(&to->localClient->buf_sendq));
+
+ if ((retlen < 0) && (ignoreErrno(errno)))
+ {
+ /* we have a non-fatal error, reschedule a write */
+ SetSendqBlocked(to);
+ comm_setselect(&to->localClient->fd, COMM_SELECT_WRITE,
+ (PF *)sendq_unblocked, (void *)to, 0);
+ }
+ else if (retlen <= 0)
+ {
+ dead_link_on_write(to, errno);
+ return;
+ }
+ }
+}
+
+/* send_queued_all()
+ *
+ * input - NONE
+ * output - NONE
+ * side effects - try to flush sendq of each client
+ */
+void
+send_queued_all(void)
+{
+ dlink_node *ptr;
+
+ /* Servers are processed first, mainly because this can generate
+ * a notice to opers, which is to be delivered by this function.
+ */
+ DLINK_FOREACH(ptr, serv_list.head)
+ send_queued_write((struct Client *) ptr->data);
+
+ DLINK_FOREACH(ptr, unknown_list.head)
+ send_queued_write((struct Client *) ptr->data);
+
+ DLINK_FOREACH(ptr, local_client_list.head)
+ send_queued_write((struct Client *) ptr->data);
+
+ /* NOTE: This can still put clients on aborted_list; unfortunately,
+ * exit_aborted_clients takes precedence over send_queued_all,
+ * because exiting clients can generate server/oper traffic.
+ * The easiest approach is dealing with aborted clients in the next I/O lap.
+ * -adx
+ */
+}
+
+/* sendto_one()
+ *
+ * inputs - pointer to destination client
+ * - var args message
+ * output - NONE
+ * side effects - send message to single client
+ */
+void
+sendto_one(struct Client *to, const char *pattern, ...)
+{
+ va_list args;
+ char buffer[IRCD_BUFSIZE];
+ int len;
+
+ if (to->from != NULL)
+ to = to->from;
+ if (IsDead(to))
+ return; /* This socket has already been marked as dead */
+
+ va_start(args, pattern);
+ len = send_format(buffer, IRCD_BUFSIZE, pattern, args);
+ va_end(args);
+
+ send_message(to, buffer, len);
+}
+
+/* sendto_channel_butone()
+ *
+ * inputs - pointer to client(server) to NOT send message to
+ * - pointer to client that is sending this message
+ * - pointer to channel being sent to
+ * - vargs message
+ * output - NONE
+ * side effects - message as given is sent to given channel members.
+ *
+ * WARNING - +D clients are ignored
+ */
+void
+sendto_channel_butone(struct Client *one, struct Client *from,
+ struct Channel *chptr, unsigned int type,
+ const char *pattern, ...)
+{
+ va_list alocal, aremote, auid;
+ char local_buf[IRCD_BUFSIZE];
+ char remote_buf[IRCD_BUFSIZE];
+ char uid_buf[IRCD_BUFSIZE];
+ int local_len, remote_len, uid_len;
+ dlink_node *ptr = NULL, *ptr_next = NULL;
+
+ if (IsServer(from))
+ local_len = ircsprintf(local_buf, ":%s ",
+ from->name);
+ else
+ local_len = ircsprintf(local_buf, ":%s!%s@%s ",
+ from->name, from->username, from->host);
+ remote_len = ircsprintf(remote_buf, ":%s ",
+ from->name);
+ uid_len = ircsprintf(uid_buf, ":%s ",
+ ID(from));
+
+ va_start(alocal, pattern);
+ va_start(aremote, pattern);
+ va_start(auid, pattern);
+ local_len += send_format(&local_buf[local_len], IRCD_BUFSIZE - local_len,
+ pattern, alocal);
+ remote_len += send_format(&remote_buf[remote_len], IRCD_BUFSIZE - remote_len,
+ pattern, aremote);
+ uid_len += send_format(&uid_buf[uid_len], IRCD_BUFSIZE - uid_len, pattern,
+ auid);
+ va_end(auid);
+ va_end(aremote);
+ va_end(alocal);
+
+ ++current_serial;
+
+ DLINK_FOREACH_SAFE(ptr, ptr_next, chptr->members.head)
+ {
+ struct Membership *ms = ptr->data;
+ struct Client *target_p = ms->client_p;
+
+ assert(IsClient(target_p));
+
+ if (IsDefunct(target_p) || HasUMode(target_p, UMODE_DEAF) || target_p->from == one)
+ continue;
+
+ if (type != 0 && (ms->flags & type) == 0)
+ continue;
+
+ if (MyConnect(target_p))
+ {
+ if (target_p->localClient->serial != current_serial)
+ {
+ send_message(target_p, local_buf, local_len);
+ target_p->localClient->serial = current_serial;
+ }
+ }
+ else
+ {
+ /* Now check whether a message has been sent to this
+ * remote link already
+ */
+ if (target_p->from->localClient->serial != current_serial)
+ {
+ if (IsCapable(target_p->from, CAP_TS6))
+ send_message_remote(target_p->from, from, uid_buf, uid_len);
+ else
+ send_message_remote(target_p->from, from, remote_buf, remote_len);
+ target_p->from->localClient->serial = current_serial;
+ }
+ }
+ }
+}
+
+/* sendto_server()
+ *
+ * inputs - pointer to client to NOT send to
+ * - pointer to channel
+ * - 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,
+ * lazylinks, uids, etc.
+ * -davidt
+ */
+void
+sendto_server(struct Client *one,
+ const unsigned int caps,
+ const unsigned int nocaps,
+ const char *format, ...)
+{
+ va_list args;
+ dlink_node *ptr = NULL;
+ char buffer[IRCD_BUFSIZE];
+ int len = 0;
+
+ va_start(args, format);
+ len = send_format(buffer, IRCD_BUFSIZE, format, args);
+ va_end(args);
+
+ DLINK_FOREACH(ptr, serv_list.head)
+ {
+ struct Client *client_p = ptr->data;
+
+ /* If dead already skip */
+ if (IsDead(client_p))
+ continue;
+ /* check against 'one' */
+ if (one != NULL && (client_p == one->from))
+ continue;
+ /* check we have required capabs */
+ if ((client_p->localClient->caps & caps) != caps)
+ continue;
+ /* check we don't have any forbidden capabs */
+ if ((client_p->localClient->caps & nocaps) != 0)
+ continue;
+
+ send_message(client_p, buffer, len);
+ }
+}
+
+/* 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, int touser,
+ const char *pattern, ...)
+{
+ va_list args;
+ dlink_node *uptr;
+ dlink_node *cptr;
+ struct Channel *chptr;
+ struct Membership *ms;
+ struct Client *target_p;
+ char buffer[IRCD_BUFSIZE];
+ int len;
+
+ va_start(args, pattern);
+ len = send_format(buffer, IRCD_BUFSIZE, pattern, args);
+ va_end(args);
+
+ ++current_serial;
+
+ DLINK_FOREACH(cptr, user->channel.head)
+ {
+ chptr = ((struct Membership *) cptr->data)->chptr;
+ assert(chptr != NULL);
+
+ DLINK_FOREACH(uptr, chptr->members.head)
+ {
+ ms = uptr->data;
+ target_p = ms->client_p;
+ assert(target_p != NULL);
+
+ if (!MyConnect(target_p) || target_p == user || IsDefunct(target_p) ||
+ target_p->localClient->serial == current_serial)
+ continue;
+
+ target_p->localClient->serial = current_serial;
+ send_message(target_p, buffer, len);
+ }
+ }
+
+ if (touser && MyConnect(user) && !IsDead(user) &&
+ user->localClient->serial != current_serial)
+ send_message(user, buffer, len);
+}
+
+/* sendto_channel_local()
+ *
+ * inputs - member status mask, e.g. CHFL_CHANOP | CHFL_VOICE
+ * - whether to ignore +D clients (YES/NO)
+ * - pointer to channel to send to
+ * - var args pattern
+ * output - NONE
+ * side effects - Send a message to all members of a channel that are
+ * locally connected to this server.
+ */
+void
+sendto_channel_local(int type, int nodeaf, struct Channel *chptr,
+ const char *pattern, ...)
+{
+ va_list args;
+ char buffer[IRCD_BUFSIZE];
+ int len;
+ dlink_node *ptr;
+ struct Membership *ms;
+ struct Client *target_p;
+
+ va_start(args, pattern);
+ len = send_format(buffer, IRCD_BUFSIZE, pattern, args);
+ va_end(args);
+
+ DLINK_FOREACH(ptr, chptr->members.head)
+ {
+ ms = ptr->data;
+ target_p = ms->client_p;
+
+ if (type != 0 && (ms->flags & type) == 0)
+ continue;
+
+ if (!MyConnect(target_p) || IsDefunct(target_p) ||
+ (nodeaf && HasUMode(target_p, UMODE_DEAF)))
+ continue;
+
+ send_message(target_p, buffer, len);
+ }
+}
+
+/* sendto_channel_local_butone()
+ *
+ * inputs - pointer to client to NOT send message to
+ * - member status mask, e.g. CHFL_CHANOP | CHFL_VOICE
+ * - pointer to channel to send to
+ * - var args pattern
+ * output - NONE
+ * side effects - Send a message to all members of a channel that are
+ * locally connected to this server except one.
+ *
+ * WARNING - +D clients are omitted
+ */
+void
+sendto_channel_local_butone(struct Client *one, int type,
+ struct Channel *chptr, const char *pattern, ...)
+{
+ va_list args;
+ char buffer[IRCD_BUFSIZE];
+ int len;
+ struct Client *target_p;
+ struct Membership *ms;
+ dlink_node *ptr;
+
+ va_start(args, pattern);
+ len = send_format(buffer, IRCD_BUFSIZE, pattern, args);
+ va_end(args);
+
+ DLINK_FOREACH(ptr, chptr->members.head)
+ {
+ ms = ptr->data;
+ target_p = ms->client_p;
+
+ if (type != 0 && (ms->flags & type) == 0)
+ continue;
+
+ if (!MyConnect(target_p) || target_p == one ||
+ IsDefunct(target_p) || HasUMode(target_p, UMODE_DEAF))
+ continue;
+ send_message(target_p, buffer, len);
+ }
+}
+
+
+/* sendto_channel_remote()
+ *
+ * inputs - Client not to send towards
+ * - Client from whom message is from
+ * - member status mask, e.g. CHFL_CHANOP | CHFL_VOICE
+ * - pointer to channel to send to
+ * - var args pattern
+ * output - NONE
+ * side effects - Send a message to all members of a channel that are
+ * remote to this server.
+ */
+void
+sendto_channel_remote(struct Client *one, struct Client *from, int type,
+ const unsigned int caps, const unsigned int nocaps,
+ struct Channel *chptr, const char *pattern, ...)
+{
+ va_list args;
+ char buffer[IRCD_BUFSIZE];
+ int len;
+ dlink_node *ptr;
+ struct Client *target_p;
+ struct Membership *ms;
+
+ va_start(args, pattern);
+ len = send_format(buffer, IRCD_BUFSIZE, pattern, args);
+ va_end(args);
+
+ ++current_serial;
+
+ DLINK_FOREACH(ptr, chptr->members.head)
+ {
+ ms = ptr->data;
+ target_p = ms->client_p;
+
+ if (type != 0 && (ms->flags & type) == 0)
+ continue;
+
+ if (MyConnect(target_p))
+ continue;
+ target_p = target_p->from;
+
+ if (target_p == one->from ||
+ ((target_p->from->localClient->caps & caps) != caps) ||
+ ((target_p->from->localClient->caps & nocaps) != 0))
+ continue;
+ if (target_p->from->localClient->serial != current_serial)
+ {
+ send_message(target_p, buffer, len);
+ target_p->from->localClient->serial = current_serial;
+ }
+ }
+}
+
+/*
+ ** match_it() and sendto_match_butone() ARE only used
+ ** to send a msg to all ppl on servers/hosts that match a specified mask
+ ** (used for enhanced PRIVMSGs) for opers
+ **
+ ** addition -- Armin, 8jun90 (gruner@informatik.tu-muenchen.de)
+ **
+ */
+
+/* match_it()
+ *
+ * inputs - client pointer to match on
+ * - actual mask to match
+ * - what to match on, HOST or SERVER
+ * output - 1 or 0 if match or not
+ * side effects - NONE
+ */
+static int
+match_it(const struct Client *one, const char *mask, int what)
+{
+ if (what == MATCH_HOST)
+ return match(mask, one->host);
+
+ return match(mask, one->servptr->name);
+}
+
+/* sendto_match_butone()
+ *
+ * Send to all clients which match the mask in a way defined on 'what';
+ * either by user hostname or user servername.
+ *
+ * ugh. ONLY used by m_message.c to send an "oper magic" message. ugh.
+ */
+void
+sendto_match_butone(struct Client *one, struct Client *from, char *mask,
+ int what, const char *pattern, ...)
+{
+ va_list alocal, aremote;
+ struct Client *client_p;
+ dlink_node *ptr, *ptr_next;
+ char local_buf[IRCD_BUFSIZE], remote_buf[IRCD_BUFSIZE];
+ int local_len = ircsprintf(local_buf, ":%s!%s@%s ", from->name,
+ from->username, from->host);
+ int remote_len = ircsprintf(remote_buf, ":%s ", from->name);
+
+ va_start(alocal, pattern);
+ va_start(aremote, pattern);
+ local_len += send_format(&local_buf[local_len], IRCD_BUFSIZE - local_len,
+ pattern, alocal);
+ remote_len += send_format(&remote_buf[remote_len], IRCD_BUFSIZE - remote_len,
+ pattern, aremote);
+ va_end(aremote);
+ va_end(alocal);
+
+ /* scan the local clients */
+ DLINK_FOREACH(ptr, local_client_list.head)
+ {
+ client_p = ptr->data;
+
+ if (client_p != one && !IsDefunct(client_p) &&
+ match_it(client_p, mask, what))
+ send_message(client_p, local_buf, local_len);
+ }
+
+ /* Now scan servers */
+ DLINK_FOREACH_SAFE(ptr, ptr_next, serv_list.head)
+ {
+ client_p = ptr->data;
+
+ /*
+ * The old code looped through every client on the
+ * network for each server to check if the
+ * server (client_p) has at least 1 client matching
+ * the mask, using something like:
+ *
+ * for (target_p = GlobalClientList; target_p; target_p = target_p->next)
+ * if (IsRegisteredUser(target_p) &&
+ * match_it(target_p, mask, what) &&
+ * (target_p->from == client_p))
+ * vsendto_prefix_one(client_p, from, pattern, args);
+ *
+ * That way, we wouldn't send the message to
+ * a server who didn't have a matching client.
+ * However, on a network such as EFNet, that
+ * code would have looped through about 50
+ * servers, and in each loop, loop through
+ * about 50k clients as well, calling match()
+ * in each nested loop. That is a very bad
+ * thing cpu wise - just send the message
+ * to every connected server and let that
+ * server deal with it.
+ * -wnder
+ */
+ if (client_p != one && !IsDefunct(client_p))
+ send_message_remote(client_p, from, remote_buf, remote_len);
+ }
+}
+
+/* sendto_match_servs()
+ *
+ * inputs - source client
+ * - mask to send to
+ * - capab needed
+ * - data
+ * outputs - none
+ * side effects - data sent to servers matching with capab
+ */
+void
+sendto_match_servs(struct Client *source_p, const char *mask, int cap,
+ const char *pattern, ...)
+{
+ va_list args;
+ struct Client *target_p;
+ dlink_node *ptr;
+ char buffer[IRCD_BUFSIZE];
+ int found = 0;
+
+ va_start(args, pattern);
+ vsnprintf(buffer, sizeof(buffer), pattern, args);
+ va_end(args);
+
+ ++current_serial;
+
+ DLINK_FOREACH(ptr, global_serv_list.head)
+ {
+ target_p = ptr->data;
+
+ /* Do not attempt to send to ourselves, or the source */
+ if (IsMe(target_p) || target_p->from == source_p->from)
+ continue;
+
+ if (target_p->from->localClient->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->localClient->serial = current_serial;
+ found++;
+
+ if (!IsCapable(target_p->from, cap))
+ continue;
+
+ sendto_anywhere(target_p, source_p, "%s", buffer);
+ }
+ }
+}
+
+/* sendto_anywhere()
+ *
+ * inputs - pointer to dest client
+ * - pointer to from client
+ * - varags
+ * output - NONE
+ * side effects - less efficient than sendto_remote and sendto_one
+ * but useful when one does not know where target "lives"
+ */
+void
+sendto_anywhere(struct Client *to, struct Client *from,
+ const char *pattern, ...)
+{
+ va_list args;
+ char buffer[IRCD_BUFSIZE];
+ int len;
+ struct Client *send_to = (to->from != NULL ? to->from : to);
+
+ if (IsDead(send_to))
+ return;
+
+ if (MyClient(to))
+ {
+ if (IsServer(from))
+ {
+ if (IsCapable(to, CAP_TS6) && HasID(from))
+ len = ircsprintf(buffer, ":%s ", from->id);
+ else
+ len = ircsprintf(buffer, ":%s ", from->name);
+ }
+ else
+ len = ircsprintf(buffer, ":%s!%s@%s ",
+ from->name, from->username, from->host);
+ }
+ else len = ircsprintf(buffer, ":%s ", ID_or_name(from, send_to));
+
+ va_start(args, pattern);
+ len += send_format(&buffer[len], IRCD_BUFSIZE - len, pattern, args);
+ va_end(args);
+
+ if(MyClient(to))
+ send_message(send_to, buffer, len);
+ else
+ send_message_remote(send_to, from, buffer, len);
+}
+
+/* sendto_realops_flags()
+ *
+ * inputs - flag types of messages to show to real opers
+ * - flag indicating opers/admins
+ * - var args input message
+ * output - NONE
+ * side effects - Send to *local* ops only but NOT +s nonopers.
+ */
+void
+sendto_realops_flags(unsigned int flags, int level, const char *pattern, ...)
+{
+ dlink_node *ptr = NULL;
+ char nbuf[IRCD_BUFSIZE];
+ va_list args;
+
+ va_start(args, pattern);
+ vsnprintf(nbuf, IRCD_BUFSIZE, pattern, args);
+ va_end(args);
+
+ DLINK_FOREACH(ptr, oper_list.head)
+ {
+ struct Client *client_p = ptr->data;
+ assert(HasUMode(client_p, UMODE_OPER));
+
+ /* 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) && !HasUMode(client_p, UMODE_ADMIN)) ||
+ ((level == L_OPER) && HasUMode(client_p, UMODE_ADMIN)))
+ continue;
+
+ if (HasUMode(client_p, flags))
+ sendto_one(client_p, ":%s NOTICE %s :*** Notice -- %s",
+ me.name, client_p->name, nbuf);
+ }
+}
+
+void
+sendto_globops_flags(unsigned int flags, int level, const char *pattern, ...)
+{
+ dlink_node *ptr = NULL;
+ char nbuf[IRCD_BUFSIZE];
+ va_list args;
+
+ va_start(args, pattern);
+ vsnprintf(nbuf, IRCD_BUFSIZE, pattern, args);
+ va_end(args);
+
+ DLINK_FOREACH(ptr, oper_list.head)
+ {
+ struct Client *client_p = ptr->data;
+ assert(client_p->umodes & UMODE_OPER);
+
+ /* 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) && !HasUMode(client_p, UMODE_ADMIN)) ||
+ ((level == L_OPER) && HasUMode(client_p, UMODE_ADMIN)))
+ continue;
+
+ if (HasUMode(client_p, flags))
+ sendto_one(client_p, ":%s NOTICE %s :*** Global -- %s",
+ me.name, client_p->name, nbuf);
+ }
+}
+
+/* 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(unsigned int flags, struct Client *source_p,
+ const char *pattern, ...)
+{
+ dlink_node *ptr = NULL;
+ va_list args;
+ char buffer[IRCD_BUFSIZE];
+ int len;
+
+ if (IsClient(source_p))
+ len = ircsprintf(buffer, ":%s!%s@%s WALLOPS :",
+ source_p->name, source_p->username, source_p->host);
+ else
+ len = ircsprintf(buffer, ":%s WALLOPS :", source_p->name);
+
+ va_start(args, pattern);
+ len += send_format(&buffer[len], IRCD_BUFSIZE - len, pattern, args);
+ va_end(args);
+
+ DLINK_FOREACH(ptr, oper_list.head)
+ {
+ struct Client *client_p = ptr->data;
+ assert(client_p->umodes & UMODE_OPER);
+
+ if (HasUMode(client_p, flags) && !IsDefunct(client_p))
+ send_message(client_p, buffer, len);
+ }
+}
+
+/* ts_warn()
+ *
+ * inputs - var args message
+ * output - NONE
+ * side effects - Call sendto_realops_flags, with some flood checking
+ * (at most 5 warnings every 5 seconds)
+ */
+void
+ts_warn(const char *pattern, ...)
+{
+ va_list args;
+ char buffer[IRCD_BUFSIZE];
+ static time_t last = 0;
+ static int warnings = 0;
+
+ /*
+ ** if we're running with TS_WARNINGS enabled and someone does
+ ** something silly like (remotely) connecting a nonTS server,
+ ** we'll get a ton of warnings, so we make sure we don't send
+ ** more than 5 every 5 seconds. -orabidoo
+ */
+
+ if (CurrentTime - last < 5)
+ {
+ if (++warnings > 5)
+ return;
+ }
+ else
+ {
+ last = CurrentTime;
+ warnings = 0;
+ }
+
+ va_start(args, pattern);
+ vsnprintf(buffer, sizeof(buffer), pattern, args);
+ va_end(args);
+
+ sendto_realops_flags(UMODE_ALL, L_ALL, "%s", buffer);
+ ilog(LOG_TYPE_IRCD, "%s", buffer);
+}
+
+/* kill_client()
+ *
+ * inputs - client to send kill towards
+ * - pointer to client to kill
+ * - reason for kill
+ * output - NONE
+ * side effects - NONE
+ */
+void
+kill_client(struct Client *client_p, struct Client *diedie,
+ const char *pattern, ...)
+{
+ va_list args;
+ char buffer[IRCD_BUFSIZE];
+ int len;
+
+ if (client_p->from != NULL)
+ client_p = client_p->from;
+ if (IsDead(client_p))
+ return;
+
+ len = ircsprintf(buffer, ":%s KILL %s :", ID_or_name(&me, client_p->from),
+ ID_or_name(diedie, client_p));
+
+ va_start(args, pattern);
+ len += send_format(&buffer[len], IRCD_BUFSIZE - len, pattern, args);
+ va_end(args);
+
+ send_message(client_p, buffer, len);
+}
+
+/* kill_client_ll_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_ll_serv_butone(struct Client *one, struct Client *source_p,
+ const char *pattern, ...)
+{
+ va_list args;
+ int have_uid = 0;
+ dlink_node *ptr = NULL;
+ char buf_uid[IRCD_BUFSIZE], buf_nick[IRCD_BUFSIZE];
+ int len_uid = 0, len_nick = 0;
+
+ if (HasID(source_p))
+ {
+ have_uid = 1;
+ va_start(args, pattern);
+ len_uid = ircsprintf(buf_uid, ":%s KILL %s :", me.id, ID(source_p));
+ len_uid += send_format(&buf_uid[len_uid], IRCD_BUFSIZE - len_uid, pattern,
+ args);
+ va_end(args);
+ }
+
+ va_start(args, pattern);
+ len_nick = ircsprintf(buf_nick, ":%s KILL %s :", me.name, source_p->name);
+ len_nick += send_format(&buf_nick[len_nick], IRCD_BUFSIZE - len_nick, pattern,
+ args);
+ va_end(args);
+
+ DLINK_FOREACH(ptr, serv_list.head)
+ {
+ struct Client *client_p = ptr->data;
+
+ if (one != NULL && (client_p == one->from))
+ continue;
+ if (IsDefunct(client_p))
+ continue;
+
+ if (have_uid && IsCapable(client_p, CAP_TS6))
+ send_message(client_p, buf_uid, len_uid);
+ else
+ send_message(client_p, buf_nick, len_nick);
+ }
+}
diff --git a/src/sprintf_irc.c b/src/sprintf_irc.c
new file mode 100644
index 0000000..8a3ea56
--- /dev/null
+++ b/src/sprintf_irc.c
@@ -0,0 +1,472 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * sprintf_irc.c: Functions for printing to a string.
+ *
+ * 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$
+ */
+
+#include "stdinc.h"
+#include "sprintf_irc.h"
+#include "irc_string.h"
+
+
+static const char atoi_tab[4000] = {
+ '0','0','0',0, '0','0','1',0, '0','0','2',0, '0','0','3',0, '0','0','4',0,
+ '0','0','5',0, '0','0','6',0, '0','0','7',0, '0','0','8',0, '0','0','9',0,
+ '0','1','0',0, '0','1','1',0, '0','1','2',0, '0','1','3',0, '0','1','4',0,
+ '0','1','5',0, '0','1','6',0, '0','1','7',0, '0','1','8',0, '0','1','9',0,
+ '0','2','0',0, '0','2','1',0, '0','2','2',0, '0','2','3',0, '0','2','4',0,
+ '0','2','5',0, '0','2','6',0, '0','2','7',0, '0','2','8',0, '0','2','9',0,
+ '0','3','0',0, '0','3','1',0, '0','3','2',0, '0','3','3',0, '0','3','4',0,
+ '0','3','5',0, '0','3','6',0, '0','3','7',0, '0','3','8',0, '0','3','9',0,
+ '0','4','0',0, '0','4','1',0, '0','4','2',0, '0','4','3',0, '0','4','4',0,
+ '0','4','5',0, '0','4','6',0, '0','4','7',0, '0','4','8',0, '0','4','9',0,
+ '0','5','0',0, '0','5','1',0, '0','5','2',0, '0','5','3',0, '0','5','4',0,
+ '0','5','5',0, '0','5','6',0, '0','5','7',0, '0','5','8',0, '0','5','9',0,
+ '0','6','0',0, '0','6','1',0, '0','6','2',0, '0','6','3',0, '0','6','4',0,
+ '0','6','5',0, '0','6','6',0, '0','6','7',0, '0','6','8',0, '0','6','9',0,
+ '0','7','0',0, '0','7','1',0, '0','7','2',0, '0','7','3',0, '0','7','4',0,
+ '0','7','5',0, '0','7','6',0, '0','7','7',0, '0','7','8',0, '0','7','9',0,
+ '0','8','0',0, '0','8','1',0, '0','8','2',0, '0','8','3',0, '0','8','4',0,
+ '0','8','5',0, '0','8','6',0, '0','8','7',0, '0','8','8',0, '0','8','9',0,
+ '0','9','0',0, '0','9','1',0, '0','9','2',0, '0','9','3',0, '0','9','4',0,
+ '0','9','5',0, '0','9','6',0, '0','9','7',0, '0','9','8',0, '0','9','9',0,
+ '1','0','0',0, '1','0','1',0, '1','0','2',0, '1','0','3',0, '1','0','4',0,
+ '1','0','5',0, '1','0','6',0, '1','0','7',0, '1','0','8',0, '1','0','9',0,
+ '1','1','0',0, '1','1','1',0, '1','1','2',0, '1','1','3',0, '1','1','4',0,
+ '1','1','5',0, '1','1','6',0, '1','1','7',0, '1','1','8',0, '1','1','9',0,
+ '1','2','0',0, '1','2','1',0, '1','2','2',0, '1','2','3',0, '1','2','4',0,
+ '1','2','5',0, '1','2','6',0, '1','2','7',0, '1','2','8',0, '1','2','9',0,
+ '1','3','0',0, '1','3','1',0, '1','3','2',0, '1','3','3',0, '1','3','4',0,
+ '1','3','5',0, '1','3','6',0, '1','3','7',0, '1','3','8',0, '1','3','9',0,
+ '1','4','0',0, '1','4','1',0, '1','4','2',0, '1','4','3',0, '1','4','4',0,
+ '1','4','5',0, '1','4','6',0, '1','4','7',0, '1','4','8',0, '1','4','9',0,
+ '1','5','0',0, '1','5','1',0, '1','5','2',0, '1','5','3',0, '1','5','4',0,
+ '1','5','5',0, '1','5','6',0, '1','5','7',0, '1','5','8',0, '1','5','9',0,
+ '1','6','0',0, '1','6','1',0, '1','6','2',0, '1','6','3',0, '1','6','4',0,
+ '1','6','5',0, '1','6','6',0, '1','6','7',0, '1','6','8',0, '1','6','9',0,
+ '1','7','0',0, '1','7','1',0, '1','7','2',0, '1','7','3',0, '1','7','4',0,
+ '1','7','5',0, '1','7','6',0, '1','7','7',0, '1','7','8',0, '1','7','9',0,
+ '1','8','0',0, '1','8','1',0, '1','8','2',0, '1','8','3',0, '1','8','4',0,
+ '1','8','5',0, '1','8','6',0, '1','8','7',0, '1','8','8',0, '1','8','9',0,
+ '1','9','0',0, '1','9','1',0, '1','9','2',0, '1','9','3',0, '1','9','4',0,
+ '1','9','5',0, '1','9','6',0, '1','9','7',0, '1','9','8',0, '1','9','9',0,
+ '2','0','0',0, '2','0','1',0, '2','0','2',0, '2','0','3',0, '2','0','4',0,
+ '2','0','5',0, '2','0','6',0, '2','0','7',0, '2','0','8',0, '2','0','9',0,
+ '2','1','0',0, '2','1','1',0, '2','1','2',0, '2','1','3',0, '2','1','4',0,
+ '2','1','5',0, '2','1','6',0, '2','1','7',0, '2','1','8',0, '2','1','9',0,
+ '2','2','0',0, '2','2','1',0, '2','2','2',0, '2','2','3',0, '2','2','4',0,
+ '2','2','5',0, '2','2','6',0, '2','2','7',0, '2','2','8',0, '2','2','9',0,
+ '2','3','0',0, '2','3','1',0, '2','3','2',0, '2','3','3',0, '2','3','4',0,
+ '2','3','5',0, '2','3','6',0, '2','3','7',0, '2','3','8',0, '2','3','9',0,
+ '2','4','0',0, '2','4','1',0, '2','4','2',0, '2','4','3',0, '2','4','4',0,
+ '2','4','5',0, '2','4','6',0, '2','4','7',0, '2','4','8',0, '2','4','9',0,
+ '2','5','0',0, '2','5','1',0, '2','5','2',0, '2','5','3',0, '2','5','4',0,
+ '2','5','5',0, '2','5','6',0, '2','5','7',0, '2','5','8',0, '2','5','9',0,
+ '2','6','0',0, '2','6','1',0, '2','6','2',0, '2','6','3',0, '2','6','4',0,
+ '2','6','5',0, '2','6','6',0, '2','6','7',0, '2','6','8',0, '2','6','9',0,
+ '2','7','0',0, '2','7','1',0, '2','7','2',0, '2','7','3',0, '2','7','4',0,
+ '2','7','5',0, '2','7','6',0, '2','7','7',0, '2','7','8',0, '2','7','9',0,
+ '2','8','0',0, '2','8','1',0, '2','8','2',0, '2','8','3',0, '2','8','4',0,
+ '2','8','5',0, '2','8','6',0, '2','8','7',0, '2','8','8',0, '2','8','9',0,
+ '2','9','0',0, '2','9','1',0, '2','9','2',0, '2','9','3',0, '2','9','4',0,
+ '2','9','5',0, '2','9','6',0, '2','9','7',0, '2','9','8',0, '2','9','9',0,
+ '3','0','0',0, '3','0','1',0, '3','0','2',0, '3','0','3',0, '3','0','4',0,
+ '3','0','5',0, '3','0','6',0, '3','0','7',0, '3','0','8',0, '3','0','9',0,
+ '3','1','0',0, '3','1','1',0, '3','1','2',0, '3','1','3',0, '3','1','4',0,
+ '3','1','5',0, '3','1','6',0, '3','1','7',0, '3','1','8',0, '3','1','9',0,
+ '3','2','0',0, '3','2','1',0, '3','2','2',0, '3','2','3',0, '3','2','4',0,
+ '3','2','5',0, '3','2','6',0, '3','2','7',0, '3','2','8',0, '3','2','9',0,
+ '3','3','0',0, '3','3','1',0, '3','3','2',0, '3','3','3',0, '3','3','4',0,
+ '3','3','5',0, '3','3','6',0, '3','3','7',0, '3','3','8',0, '3','3','9',0,
+ '3','4','0',0, '3','4','1',0, '3','4','2',0, '3','4','3',0, '3','4','4',0,
+ '3','4','5',0, '3','4','6',0, '3','4','7',0, '3','4','8',0, '3','4','9',0,
+ '3','5','0',0, '3','5','1',0, '3','5','2',0, '3','5','3',0, '3','5','4',0,
+ '3','5','5',0, '3','5','6',0, '3','5','7',0, '3','5','8',0, '3','5','9',0,
+ '3','6','0',0, '3','6','1',0, '3','6','2',0, '3','6','3',0, '3','6','4',0,
+ '3','6','5',0, '3','6','6',0, '3','6','7',0, '3','6','8',0, '3','6','9',0,
+ '3','7','0',0, '3','7','1',0, '3','7','2',0, '3','7','3',0, '3','7','4',0,
+ '3','7','5',0, '3','7','6',0, '3','7','7',0, '3','7','8',0, '3','7','9',0,
+ '3','8','0',0, '3','8','1',0, '3','8','2',0, '3','8','3',0, '3','8','4',0,
+ '3','8','5',0, '3','8','6',0, '3','8','7',0, '3','8','8',0, '3','8','9',0,
+ '3','9','0',0, '3','9','1',0, '3','9','2',0, '3','9','3',0, '3','9','4',0,
+ '3','9','5',0, '3','9','6',0, '3','9','7',0, '3','9','8',0, '3','9','9',0,
+ '4','0','0',0, '4','0','1',0, '4','0','2',0, '4','0','3',0, '4','0','4',0,
+ '4','0','5',0, '4','0','6',0, '4','0','7',0, '4','0','8',0, '4','0','9',0,
+ '4','1','0',0, '4','1','1',0, '4','1','2',0, '4','1','3',0, '4','1','4',0,
+ '4','1','5',0, '4','1','6',0, '4','1','7',0, '4','1','8',0, '4','1','9',0,
+ '4','2','0',0, '4','2','1',0, '4','2','2',0, '4','2','3',0, '4','2','4',0,
+ '4','2','5',0, '4','2','6',0, '4','2','7',0, '4','2','8',0, '4','2','9',0,
+ '4','3','0',0, '4','3','1',0, '4','3','2',0, '4','3','3',0, '4','3','4',0,
+ '4','3','5',0, '4','3','6',0, '4','3','7',0, '4','3','8',0, '4','3','9',0,
+ '4','4','0',0, '4','4','1',0, '4','4','2',0, '4','4','3',0, '4','4','4',0,
+ '4','4','5',0, '4','4','6',0, '4','4','7',0, '4','4','8',0, '4','4','9',0,
+ '4','5','0',0, '4','5','1',0, '4','5','2',0, '4','5','3',0, '4','5','4',0,
+ '4','5','5',0, '4','5','6',0, '4','5','7',0, '4','5','8',0, '4','5','9',0,
+ '4','6','0',0, '4','6','1',0, '4','6','2',0, '4','6','3',0, '4','6','4',0,
+ '4','6','5',0, '4','6','6',0, '4','6','7',0, '4','6','8',0, '4','6','9',0,
+ '4','7','0',0, '4','7','1',0, '4','7','2',0, '4','7','3',0, '4','7','4',0,
+ '4','7','5',0, '4','7','6',0, '4','7','7',0, '4','7','8',0, '4','7','9',0,
+ '4','8','0',0, '4','8','1',0, '4','8','2',0, '4','8','3',0, '4','8','4',0,
+ '4','8','5',0, '4','8','6',0, '4','8','7',0, '4','8','8',0, '4','8','9',0,
+ '4','9','0',0, '4','9','1',0, '4','9','2',0, '4','9','3',0, '4','9','4',0,
+ '4','9','5',0, '4','9','6',0, '4','9','7',0, '4','9','8',0, '4','9','9',0,
+ '5','0','0',0, '5','0','1',0, '5','0','2',0, '5','0','3',0, '5','0','4',0,
+ '5','0','5',0, '5','0','6',0, '5','0','7',0, '5','0','8',0, '5','0','9',0,
+ '5','1','0',0, '5','1','1',0, '5','1','2',0, '5','1','3',0, '5','1','4',0,
+ '5','1','5',0, '5','1','6',0, '5','1','7',0, '5','1','8',0, '5','1','9',0,
+ '5','2','0',0, '5','2','1',0, '5','2','2',0, '5','2','3',0, '5','2','4',0,
+ '5','2','5',0, '5','2','6',0, '5','2','7',0, '5','2','8',0, '5','2','9',0,
+ '5','3','0',0, '5','3','1',0, '5','3','2',0, '5','3','3',0, '5','3','4',0,
+ '5','3','5',0, '5','3','6',0, '5','3','7',0, '5','3','8',0, '5','3','9',0,
+ '5','4','0',0, '5','4','1',0, '5','4','2',0, '5','4','3',0, '5','4','4',0,
+ '5','4','5',0, '5','4','6',0, '5','4','7',0, '5','4','8',0, '5','4','9',0,
+ '5','5','0',0, '5','5','1',0, '5','5','2',0, '5','5','3',0, '5','5','4',0,
+ '5','5','5',0, '5','5','6',0, '5','5','7',0, '5','5','8',0, '5','5','9',0,
+ '5','6','0',0, '5','6','1',0, '5','6','2',0, '5','6','3',0, '5','6','4',0,
+ '5','6','5',0, '5','6','6',0, '5','6','7',0, '5','6','8',0, '5','6','9',0,
+ '5','7','0',0, '5','7','1',0, '5','7','2',0, '5','7','3',0, '5','7','4',0,
+ '5','7','5',0, '5','7','6',0, '5','7','7',0, '5','7','8',0, '5','7','9',0,
+ '5','8','0',0, '5','8','1',0, '5','8','2',0, '5','8','3',0, '5','8','4',0,
+ '5','8','5',0, '5','8','6',0, '5','8','7',0, '5','8','8',0, '5','8','9',0,
+ '5','9','0',0, '5','9','1',0, '5','9','2',0, '5','9','3',0, '5','9','4',0,
+ '5','9','5',0, '5','9','6',0, '5','9','7',0, '5','9','8',0, '5','9','9',0,
+ '6','0','0',0, '6','0','1',0, '6','0','2',0, '6','0','3',0, '6','0','4',0,
+ '6','0','5',0, '6','0','6',0, '6','0','7',0, '6','0','8',0, '6','0','9',0,
+ '6','1','0',0, '6','1','1',0, '6','1','2',0, '6','1','3',0, '6','1','4',0,
+ '6','1','5',0, '6','1','6',0, '6','1','7',0, '6','1','8',0, '6','1','9',0,
+ '6','2','0',0, '6','2','1',0, '6','2','2',0, '6','2','3',0, '6','2','4',0,
+ '6','2','5',0, '6','2','6',0, '6','2','7',0, '6','2','8',0, '6','2','9',0,
+ '6','3','0',0, '6','3','1',0, '6','3','2',0, '6','3','3',0, '6','3','4',0,
+ '6','3','5',0, '6','3','6',0, '6','3','7',0, '6','3','8',0, '6','3','9',0,
+ '6','4','0',0, '6','4','1',0, '6','4','2',0, '6','4','3',0, '6','4','4',0,
+ '6','4','5',0, '6','4','6',0, '6','4','7',0, '6','4','8',0, '6','4','9',0,
+ '6','5','0',0, '6','5','1',0, '6','5','2',0, '6','5','3',0, '6','5','4',0,
+ '6','5','5',0, '6','5','6',0, '6','5','7',0, '6','5','8',0, '6','5','9',0,
+ '6','6','0',0, '6','6','1',0, '6','6','2',0, '6','6','3',0, '6','6','4',0,
+ '6','6','5',0, '6','6','6',0, '6','6','7',0, '6','6','8',0, '6','6','9',0,
+ '6','7','0',0, '6','7','1',0, '6','7','2',0, '6','7','3',0, '6','7','4',0,
+ '6','7','5',0, '6','7','6',0, '6','7','7',0, '6','7','8',0, '6','7','9',0,
+ '6','8','0',0, '6','8','1',0, '6','8','2',0, '6','8','3',0, '6','8','4',0,
+ '6','8','5',0, '6','8','6',0, '6','8','7',0, '6','8','8',0, '6','8','9',0,
+ '6','9','0',0, '6','9','1',0, '6','9','2',0, '6','9','3',0, '6','9','4',0,
+ '6','9','5',0, '6','9','6',0, '6','9','7',0, '6','9','8',0, '6','9','9',0,
+ '7','0','0',0, '7','0','1',0, '7','0','2',0, '7','0','3',0, '7','0','4',0,
+ '7','0','5',0, '7','0','6',0, '7','0','7',0, '7','0','8',0, '7','0','9',0,
+ '7','1','0',0, '7','1','1',0, '7','1','2',0, '7','1','3',0, '7','1','4',0,
+ '7','1','5',0, '7','1','6',0, '7','1','7',0, '7','1','8',0, '7','1','9',0,
+ '7','2','0',0, '7','2','1',0, '7','2','2',0, '7','2','3',0, '7','2','4',0,
+ '7','2','5',0, '7','2','6',0, '7','2','7',0, '7','2','8',0, '7','2','9',0,
+ '7','3','0',0, '7','3','1',0, '7','3','2',0, '7','3','3',0, '7','3','4',0,
+ '7','3','5',0, '7','3','6',0, '7','3','7',0, '7','3','8',0, '7','3','9',0,
+ '7','4','0',0, '7','4','1',0, '7','4','2',0, '7','4','3',0, '7','4','4',0,
+ '7','4','5',0, '7','4','6',0, '7','4','7',0, '7','4','8',0, '7','4','9',0,
+ '7','5','0',0, '7','5','1',0, '7','5','2',0, '7','5','3',0, '7','5','4',0,
+ '7','5','5',0, '7','5','6',0, '7','5','7',0, '7','5','8',0, '7','5','9',0,
+ '7','6','0',0, '7','6','1',0, '7','6','2',0, '7','6','3',0, '7','6','4',0,
+ '7','6','5',0, '7','6','6',0, '7','6','7',0, '7','6','8',0, '7','6','9',0,
+ '7','7','0',0, '7','7','1',0, '7','7','2',0, '7','7','3',0, '7','7','4',0,
+ '7','7','5',0, '7','7','6',0, '7','7','7',0, '7','7','8',0, '7','7','9',0,
+ '7','8','0',0, '7','8','1',0, '7','8','2',0, '7','8','3',0, '7','8','4',0,
+ '7','8','5',0, '7','8','6',0, '7','8','7',0, '7','8','8',0, '7','8','9',0,
+ '7','9','0',0, '7','9','1',0, '7','9','2',0, '7','9','3',0, '7','9','4',0,
+ '7','9','5',0, '7','9','6',0, '7','9','7',0, '7','9','8',0, '7','9','9',0,
+ '8','0','0',0, '8','0','1',0, '8','0','2',0, '8','0','3',0, '8','0','4',0,
+ '8','0','5',0, '8','0','6',0, '8','0','7',0, '8','0','8',0, '8','0','9',0,
+ '8','1','0',0, '8','1','1',0, '8','1','2',0, '8','1','3',0, '8','1','4',0,
+ '8','1','5',0, '8','1','6',0, '8','1','7',0, '8','1','8',0, '8','1','9',0,
+ '8','2','0',0, '8','2','1',0, '8','2','2',0, '8','2','3',0, '8','2','4',0,
+ '8','2','5',0, '8','2','6',0, '8','2','7',0, '8','2','8',0, '8','2','9',0,
+ '8','3','0',0, '8','3','1',0, '8','3','2',0, '8','3','3',0, '8','3','4',0,
+ '8','3','5',0, '8','3','6',0, '8','3','7',0, '8','3','8',0, '8','3','9',0,
+ '8','4','0',0, '8','4','1',0, '8','4','2',0, '8','4','3',0, '8','4','4',0,
+ '8','4','5',0, '8','4','6',0, '8','4','7',0, '8','4','8',0, '8','4','9',0,
+ '8','5','0',0, '8','5','1',0, '8','5','2',0, '8','5','3',0, '8','5','4',0,
+ '8','5','5',0, '8','5','6',0, '8','5','7',0, '8','5','8',0, '8','5','9',0,
+ '8','6','0',0, '8','6','1',0, '8','6','2',0, '8','6','3',0, '8','6','4',0,
+ '8','6','5',0, '8','6','6',0, '8','6','7',0, '8','6','8',0, '8','6','9',0,
+ '8','7','0',0, '8','7','1',0, '8','7','2',0, '8','7','3',0, '8','7','4',0,
+ '8','7','5',0, '8','7','6',0, '8','7','7',0, '8','7','8',0, '8','7','9',0,
+ '8','8','0',0, '8','8','1',0, '8','8','2',0, '8','8','3',0, '8','8','4',0,
+ '8','8','5',0, '8','8','6',0, '8','8','7',0, '8','8','8',0, '8','8','9',0,
+ '8','9','0',0, '8','9','1',0, '8','9','2',0, '8','9','3',0, '8','9','4',0,
+ '8','9','5',0, '8','9','6',0, '8','9','7',0, '8','9','8',0, '8','9','9',0,
+ '9','0','0',0, '9','0','1',0, '9','0','2',0, '9','0','3',0, '9','0','4',0,
+ '9','0','5',0, '9','0','6',0, '9','0','7',0, '9','0','8',0, '9','0','9',0,
+ '9','1','0',0, '9','1','1',0, '9','1','2',0, '9','1','3',0, '9','1','4',0,
+ '9','1','5',0, '9','1','6',0, '9','1','7',0, '9','1','8',0, '9','1','9',0,
+ '9','2','0',0, '9','2','1',0, '9','2','2',0, '9','2','3',0, '9','2','4',0,
+ '9','2','5',0, '9','2','6',0, '9','2','7',0, '9','2','8',0, '9','2','9',0,
+ '9','3','0',0, '9','3','1',0, '9','3','2',0, '9','3','3',0, '9','3','4',0,
+ '9','3','5',0, '9','3','6',0, '9','3','7',0, '9','3','8',0, '9','3','9',0,
+ '9','4','0',0, '9','4','1',0, '9','4','2',0, '9','4','3',0, '9','4','4',0,
+ '9','4','5',0, '9','4','6',0, '9','4','7',0, '9','4','8',0, '9','4','9',0,
+ '9','5','0',0, '9','5','1',0, '9','5','2',0, '9','5','3',0, '9','5','4',0,
+ '9','5','5',0, '9','5','6',0, '9','5','7',0, '9','5','8',0, '9','5','9',0,
+ '9','6','0',0, '9','6','1',0, '9','6','2',0, '9','6','3',0, '9','6','4',0,
+ '9','6','5',0, '9','6','6',0, '9','6','7',0, '9','6','8',0, '9','6','9',0,
+ '9','7','0',0, '9','7','1',0, '9','7','2',0, '9','7','3',0, '9','7','4',0,
+ '9','7','5',0, '9','7','6',0, '9','7','7',0, '9','7','8',0, '9','7','9',0,
+ '9','8','0',0, '9','8','1',0, '9','8','2',0, '9','8','3',0, '9','8','4',0,
+ '9','8','5',0, '9','8','6',0, '9','8','7',0, '9','8','8',0, '9','8','9',0,
+ '9','9','0',0, '9','9','1',0, '9','9','2',0, '9','9','3',0, '9','9','4',0,
+ '9','9','5',0, '9','9','6',0, '9','9','7',0, '9','9','8',0, '9','9','9',0
+};
+
+static char scratch_buffer[32];
+
+/*
+ * sprintf_irc
+ *
+ * sprintf_irc is optimized for the formats: %c, %s, %lu, %d and %u.
+ * Where %lu actually equals %l09u (for printing time_t timestamps).
+ *
+ * sprintf_irc is NOT optimized for any other format and resorts to using
+ * the normal sprintf when it encounters a format it doesn't understand
+ * (including padding, width, precision etc).
+ *
+ * The following benchmark was measured on a PPro200 with linux 2.0.30,
+ * libc 5.4.28, compiled with gcc-2.7.2.1 with -O3.
+ *
+ * Format sprintf sprintf_irc Speed up factor
+ *
+ * "12345678901234567890" 3.385 us 0.859 us 3.94
+ * "%s", buffer (20 chars) 3.780 us 0.547 us 6.91
+ * "%c%c%c", c1, c2, c3 3.640 us 0.376 us 9.68
+ * "%lu", (time_t)t 5.851 us 0.842 us 6.95
+ *
+ * Less important:
+ * "%d", 31337 4.487 us 0.852 us 5.27
+ * "%u.%u.%u.%u", 9.069 us 2.431 us 3.73
+ *
+ * Not used:
+ * "%03d", 401 4.348 us
+ * "%N" 0.216 us 20.13
+ *
+ * --Run
+ */
+
+int
+vsprintf_irc(char *str, const char *format, va_list args)
+{
+ char c;
+ int bytes = 0;
+
+ while ((c = *format++))
+ {
+ if (c == '%')
+ {
+ c = *format++; /* May never be '\0' ! */
+
+ if (c == 's')
+ {
+ const char *p1 = va_arg(args, const char *);
+ if ((*str = *p1))
+ {
+ ++bytes;
+ while ((*++str = *++p1))
+ ++bytes;
+ }
+
+ continue;
+ }
+
+ if (c == 'c')
+ {
+ *str++ = (char) va_arg(args, int);
+ ++bytes;
+
+ continue;
+ }
+
+ /*
+ * Prints time_t value in interval
+ * [ 100000000 , 4294967295 ]
+ * Actually prints like "%09lu"
+ */
+ if (c == 'l' && *format == 'u')
+ {
+ unsigned long v1, v2;
+ const char *ap;
+
+ ++format;
+ v1 = va_arg(args, unsigned long);
+ if (v1 == 0)
+ {
+ *str++ = '0';
+ ++bytes;
+ continue;
+ }
+ if (v1 > 999999999L)
+ {
+ v2 = v1 / 1000000000;
+ v1 -= v2 * 1000000000;
+ *str++ = '0' + v2;
+ ++bytes;
+ }
+
+ v2 = v1 / 1000000;
+ v1 -= v2 * 1000000;
+ ap = atoi_tab + (v2 << 2);
+ *str++ = *ap++;
+ *str++ = *ap++;
+ *str++ = *ap;
+ v2 = v1 / 1000;
+ v1 -= v2 * 1000;
+ ap = atoi_tab + (v2 << 2);
+ *str++ = *ap++;
+ *str++ = *ap++;
+ *str++ = *ap;
+ ap = atoi_tab + (v1 << 2);
+ *str++ = *ap++;
+ *str++ = *ap++;
+ *str++ = *ap;
+
+ bytes += 9;
+
+ continue;
+ }
+ if (c == 't')
+ {
+ unsigned int v1;
+
+ v1 = va_arg(args,int);
+
+ *str++ = (v1/10) + '0';
+ *str++ = v1%10 + '0';
+
+ bytes += 2;
+
+ continue;
+ }
+
+ if (c == 'd')
+ {
+ unsigned int v1, v2;
+ const char *ap;
+ char *s = &scratch_buffer[sizeof(scratch_buffer) - 2];
+
+ v1 = va_arg(args, int);
+ if ((int)v1 <= 0)
+ {
+ if (v1 == 0)
+ {
+ *str++ = '0';
+ ++bytes;
+ continue;
+ }
+ *str++ = '-';
+ ++bytes;
+ v1 = -v1;
+ }
+
+ do
+ {
+ v2 = v1 / 1000;
+ ap = atoi_tab + 2 + ((v1 - 1000 * v2) << 2);
+ *s-- = *ap--;
+ *s-- = *ap--;
+ *s-- = *ap;
+ }
+ while ((v1 = v2) > 0);
+
+ while ('0' == *++s);
+
+ *str = *s;
+ ++bytes;
+
+ while ((*++str = *++s))
+ ++bytes;
+
+ continue;
+ }
+
+ if (c == 'u')
+ {
+ unsigned int v1, v2;
+ const char *ap;
+ char *s = &scratch_buffer[sizeof(scratch_buffer) - 2];
+
+ v1 = va_arg(args, unsigned int);
+ if (v1 == 0)
+ {
+ *str++ = '0';
+ ++bytes;
+ continue;
+ }
+
+ do
+ {
+ v2 = v1 / 1000;
+ ap = atoi_tab + 2 + ((v1 - 1000 * v2) << 2);
+ *s-- = *ap--;
+ *s-- = *ap--;
+ *s-- = *ap;
+ }
+ while ((v1 = v2) > 0);
+
+ while ('0' == *++s);
+
+ *str = *s;
+ ++bytes;
+
+ while ((*++str = *++s))
+ ++bytes;
+
+ continue;
+ }
+
+ if (c != '%')
+ {
+ int ret;
+
+ format -= 2;
+ ret = vsprintf(str, format, args);
+ str += ret;
+ bytes += ret;
+
+ break;
+ }
+ }
+
+ *str++ = c;
+ ++bytes;
+ }
+
+ *str = '\0';
+
+ return(bytes);
+} /* vsprintf_irc() */
+
+int
+ircsprintf(char *str, const char *format, ...)
+{
+ va_list args;
+ int bytes;
+
+ va_start(args, format);
+
+ bytes = vsprintf_irc(str, format, args);
+
+ va_end(args);
+
+ return(bytes);
+} /* ircsprintf() */
+
diff --git a/src/version.c b/src/version.c
new file mode 100644
index 0000000..f80cca5
--- /dev/null
+++ b/src/version.c
@@ -0,0 +1,105 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ *
+ * 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$
+ */
+
+#include "patchlevel.h"
+#include "serno.h"
+#include "ircd.h"
+
+const char *ircd_version = PATCHLEVEL;
+const char *serno = SERIALNUM;
+
+const char *infotext[] =
+{
+ "IRC --",
+ "Based on the original code written by Jarkko Oikarinen",
+ "Copyright 1988, 1989, 1990, 1991 University of Oulu, Computing Center",
+ "Copyright (c) 1997-2012 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, or",
+ "(at your option) any later version.",
+ "",
+ "",
+ "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:",
+ "",
+ "billy-jon, William Bierman III <bill@mu.org>",
+ "cryogen, Stuart Walsh <stu@ipng.org.uk>",
+ "Dianora, Diane Bruce <db@db.net>",
+ "metalrock, Jack Low <jclow@csupomona.edu>",
+ "Michael, Michael Wobst <michael@wobst.at>",
+ "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>",
+ "adx, Piotr Nizynski <nizynski@sysplex.pl>",
+ "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>",
+ "fgeek, Henri Salo <henri@nerv.fi>",
+ "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>",
+ "joshk, Joshua Kwan <joshk@triplehelix.org>",
+ "jv, Jakub Vlasek <jv@pilsedu.cz>",
+ "k9, Jeremy Chadwick <ircd@jdc.parodius.com>",
+ "kire, Erik Small <smalle@hawaii.edu>",
+ "knight, Alan LeVee <alan.levee@prometheus-designs.net>",
+ "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.",
+ "", 0
+};
diff --git a/src/watch.c b/src/watch.c
new file mode 100644
index 0000000..ba7db13
--- /dev/null
+++ b/src/watch.c
@@ -0,0 +1,235 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ *
+ * Copyright (C) 1997 Jukka Santala (Donwulff)
+ * Copyright (C) 2005 by the 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
+ */
+
+/*! \file watch.c
+ * \brief File including functions for WATCH support
+ * \version $Id$
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "balloc.h"
+#include "s_user.h"
+#include "s_misc.h"
+#include "client.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "conf.h"
+#include "s_serv.h"
+#include "send.h"
+#include "supported.h"
+#include "whowas.h"
+#include "memory.h"
+#include "packet.h"
+#include "watch.h"
+
+#define WATCH_HEAP_SIZE 32
+
+static dlink_list watchTable[HASHSIZE];
+
+static BlockHeap *watch_heap = NULL;
+
+/*! \brief Initializes the watch table
+ */
+void
+watch_init(void)
+{
+ watch_heap = BlockHeapCreate("watch", sizeof(struct Watch), WATCH_HEAP_SIZE);
+}
+
+/*
+ * Rough figure of the datastructures for watch:
+ *
+ * NOTIFY HASH client_p1
+ * | |- nick1
+ * nick1-|- client_p1 |- nick2
+ * | |- client_p2 client_p3
+ * | |- client_p3 client_p2 |- nick1
+ * | |- nick1
+ * nick2-|- client_p2 |- nick2
+ * |- client_p1
+ */
+
+/*! \brief Counts up memory used by watch list headers
+ */
+void
+watch_count_memory(unsigned int *const count, uint64_t *const memory)
+{
+ unsigned int idx;
+
+ for (idx = 0; idx < HASHSIZE; ++idx)
+ *count += dlink_list_length(&watchTable[idx]);
+
+ *memory = *count * sizeof(struct Watch);
+}
+
+/*! \brief Notifies all clients that have client_p's nick name on
+ * their watch list.
+ * \param client_p pointer to Client struct
+ * \param reply numeric to send. Either RPL_LOGON or RPL_LOGOFF
+ */
+void
+watch_check_hash(struct Client *client_p, int reply)
+{
+ struct Watch *anptr = NULL;
+ dlink_node *ptr = NULL;
+ assert(IsClient(client_p));
+ if ((anptr = watch_find_hash(client_p->name)) == NULL)
+ return; /* This nick isn't on watch */
+
+ /* Update the time of last change to item */
+ anptr->lasttime = CurrentTime;
+
+ /* Send notifies out to everybody on the list in header */
+ DLINK_FOREACH(ptr, anptr->watched_by.head)
+ {
+ struct Client *target_p = ptr->data;
+
+ sendto_one(target_p, form_str(reply),
+ me.name, target_p->name, client_p->name,
+ client_p->username, client_p->host,
+ anptr->lasttime, client_p->info);
+ }
+}
+
+/*! \brief Looks up the watch table for a given nick
+ * \param name nick name to look up
+ */
+struct Watch *
+watch_find_hash(const char *name)
+{
+ dlink_node *ptr = NULL;
+
+ DLINK_FOREACH(ptr, watchTable[strhash(name)].head)
+ {
+ struct Watch *anptr = ptr->data;
+
+ if (!irccmp(anptr->nick, name))
+ return anptr;
+ }
+
+ return NULL;
+}
+
+/*! \brief Adds a watch entry to client_p's watch list
+ * \param nick nick name to add
+ * \param client_p Pointer to Client struct
+ */
+void
+watch_add_to_hash_table(const char *nick, struct Client *client_p)
+{
+ struct Watch *anptr = NULL;
+ dlink_node *ptr = NULL;
+
+ /* If found NULL (no header for this nick), make one... */
+ if ((anptr = watch_find_hash(nick)) == NULL)
+ {
+ anptr = BlockHeapAlloc(watch_heap);
+ anptr->lasttime = CurrentTime;
+ strlcpy(anptr->nick, nick, sizeof(anptr->nick));
+
+ dlinkAdd(anptr, &anptr->node, &watchTable[strhash(nick)]);
+ }
+ else
+ {
+ /* Is this client already on the watch-list? */
+ ptr = dlinkFind(&anptr->watched_by, client_p);
+ }
+
+ if (ptr == NULL)
+ {
+ /* No it isn't, so add it in the bucket and client addint it */
+ dlinkAdd(client_p, make_dlink_node(), &anptr->watched_by);
+ dlinkAdd(anptr, make_dlink_node(), &client_p->localClient->watches);
+ }
+}
+
+/*! \brief Removes a single entry from client_p's watch list
+ * \param nick nick name to remove
+ * \param client_p Pointer to Client struct
+ */
+void
+watch_del_from_hash_table(const char *nick, struct Client *client_p)
+{
+ struct Watch *anptr = NULL;
+ dlink_node *ptr = NULL;
+
+ if ((anptr = watch_find_hash(nick)) == NULL)
+ return; /* No header found for that nick. i.e. it's not being watched */
+
+ if ((ptr = dlinkFind(&anptr->watched_by, client_p)) == NULL)
+ return; /* This nick isn't being watched by client_p */
+
+ dlinkDelete(ptr, &anptr->watched_by);
+ free_dlink_node(ptr);
+
+ if ((ptr = dlinkFindDelete(&client_p->localClient->watches, anptr)))
+ free_dlink_node(ptr);
+
+ /* In case this header is now empty of notices, remove it */
+ if (anptr->watched_by.head == NULL)
+ {
+ assert(dlinkFind(&watchTable[strhash(nick)], anptr) != NULL);
+ dlinkDelete(&anptr->node, &watchTable[strhash(nick)]);
+ BlockHeapFree(watch_heap, anptr);
+ }
+}
+
+/*! \brief Removes all entries from client_p's watch list
+ * and deletes headers that are no longer being watched.
+ * \param client_p Pointer to Client struct
+ */
+void
+watch_del_watch_list(struct Client *client_p)
+{
+ dlink_node *ptr = NULL, *ptr_next = NULL;
+ dlink_node *tmp = NULL;
+
+ DLINK_FOREACH_SAFE(ptr, ptr_next, client_p->localClient->watches.head)
+ {
+ struct Watch *anptr = ptr->data;
+
+ assert(anptr);
+
+ assert(dlinkFind(&anptr->watched_by, client_p) != NULL);
+ if ((tmp = dlinkFindDelete(&anptr->watched_by, client_p)))
+ free_dlink_node(tmp);
+
+ /* If this leaves a header without notifies, remove it. */
+ if (anptr->watched_by.head == NULL)
+ {
+ assert(dlinkFind(&watchTable[strhash(anptr->nick)], anptr) != NULL);
+ dlinkDelete(&anptr->node, &watchTable[strhash(anptr->nick)]);
+
+ BlockHeapFree(watch_heap, anptr);
+ }
+
+ dlinkDelete(ptr, &client_p->localClient->watches);
+ free_dlink_node(ptr);
+ }
+
+ assert(client_p->localClient->watches.head == NULL);
+ assert(client_p->localClient->watches.tail == NULL);
+}
diff --git a/src/whowas.c b/src/whowas.c
new file mode 100644
index 0000000..7d0e087
--- /dev/null
+++ b/src/whowas.c
@@ -0,0 +1,142 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * whowas.c: WHOWAS user cache.
+ *
+ * Copyright (C) 2005 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$
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "whowas.h"
+#include "client.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+
+
+static struct Whowas WHOWAS[NICKNAMEHISTORYLENGTH];
+dlink_list WHOWASHASH[HASHSIZE];
+
+
+void
+add_history(struct Client *client_p, int online)
+{
+ static unsigned int whowas_next = 0;
+ struct Whowas *who = &WHOWAS[whowas_next];
+
+ assert(client_p && client_p->servptr);
+
+ if (++whowas_next == NICKNAMEHISTORYLENGTH)
+ whowas_next = 0;
+
+ if (who->hashv != -1)
+ {
+ if (who->online)
+ dlinkDelete(&who->cnode, &who->online->whowas);
+
+ dlinkDelete(&who->tnode, &WHOWASHASH[who->hashv]);
+ }
+
+ who->hashv = strhash(client_p->name);
+ who->logoff = CurrentTime;
+
+ strlcpy(who->name, client_p->name, sizeof(who->name));
+ strlcpy(who->username, client_p->username, sizeof(who->username));
+ strlcpy(who->hostname, client_p->host, sizeof(who->hostname));
+ strlcpy(who->realname, client_p->info, sizeof(who->realname));
+ strlcpy(who->servername, client_p->servptr->name, sizeof(who->servername));
+
+ if (online)
+ {
+ who->online = client_p;
+ dlinkAdd(who, &who->cnode, &client_p->whowas);
+ }
+ else
+ who->online = NULL;
+
+ dlinkAdd(who, &who->tnode, &WHOWASHASH[who->hashv]);
+}
+
+void
+off_history(struct Client *client_p)
+{
+ dlink_node *ptr = NULL, *ptr_next = NULL;
+
+ DLINK_FOREACH_SAFE(ptr, ptr_next, client_p->whowas.head)
+ {
+ struct Whowas *temp = ptr->data;
+
+ temp->online = NULL;
+ dlinkDelete(&temp->cnode, &client_p->whowas);
+ }
+}
+
+struct Client *
+get_history(const char *nick, time_t timelimit)
+{
+ dlink_node *ptr = NULL;
+
+ timelimit = CurrentTime - timelimit;
+
+ DLINK_FOREACH(ptr, WHOWASHASH[strhash(nick)].head)
+ {
+ struct Whowas *temp = ptr->data;
+
+ if (temp->logoff < timelimit)
+ continue;
+ if (irccmp(nick, temp->name))
+ continue;
+ return temp->online;
+ }
+
+ return NULL;
+}
+
+void
+count_whowas_memory(unsigned int *wwu, uint64_t *wwum)
+{
+ const struct Whowas *tmp;
+ int i;
+ unsigned int u = 0;
+ uint64_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;
+}
+
+void
+whowas_init(void)
+{
+ unsigned int idx;
+
+ for (idx = 0; idx < NICKNAMEHISTORYLENGTH; ++idx)
+ WHOWAS[idx].hashv = -1;
+}