summaryrefslogtreecommitdiff
path: root/modules/core
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 /modules/core
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 'modules/core')
-rw-r--r--modules/core/Makefile.am58
-rw-r--r--modules/core/Makefile.in766
-rw-r--r--modules/core/m_die.c97
-rw-r--r--modules/core/m_error.c116
-rw-r--r--modules/core/m_join.c680
-rw-r--r--modules/core/m_kick.c241
-rw-r--r--modules/core/m_kill.c331
-rw-r--r--modules/core/m_message.c935
-rw-r--r--modules/core/m_mode.c313
-rw-r--r--modules/core/m_nick.c1004
-rw-r--r--modules/core/m_part.c167
-rw-r--r--modules/core/m_quit.c98
-rw-r--r--modules/core/m_server.c624
-rw-r--r--modules/core/m_sjoin.c850
-rw-r--r--modules/core/m_squit.c184
15 files changed, 6464 insertions, 0 deletions
diff --git a/modules/core/Makefile.am b/modules/core/Makefile.am
new file mode 100644
index 0000000..6e4cbba
--- /dev/null
+++ b/modules/core/Makefile.am
@@ -0,0 +1,58 @@
+AUTOMAKE_OPTIONS = foreign
+MODULE_FLAGS = -module -avoid-version
+
+AM_CPPFLAGS = -I$(top_srcdir)/include
+modulesdir = $(pkglibdir)/modules
+
+
+m_die_la_LDFLAGS = $(MODULE_FLAGS)
+m_error_la_LDFLAGS = $(MODULE_FLAGS)
+m_join_la_LDFLAGS = $(MODULE_FLAGS)
+m_kick_la_LDFLAGS = $(MODULE_FLAGS)
+m_kill_la_LDFLAGS = $(MODULE_FLAGS)
+m_message_la_LDFLAGS = $(MODULE_FLAGS)
+m_mode_la_LDFLAGS = $(MODULE_FLAGS)
+m_nick_la_LDFLAGS = $(MODULE_FLAGS)
+m_part_la_LDFLAGS = $(MODULE_FLAGS)
+m_quit_la_LDFLAGS = $(MODULE_FLAGS)
+m_server_la_LDFLAGS = $(MODULE_FLAGS)
+m_sjoin_la_LDFLAGS = $(MODULE_FLAGS)
+m_squit_la_LDFLAGS = $(MODULE_FLAGS)
+
+m_die_la_SOURCES = m_die.c
+m_error_la_SOURCES = m_error.c
+m_join_la_SOURCES = m_join.c
+m_kick_la_SOURCES = m_kick.c
+m_kill_la_SOURCES = m_kill.c
+m_message_la_SOURCES = m_message.c
+m_mode_la_SOURCES = m_mode.c
+m_nick_la_SOURCES = m_nick.c
+m_part_la_SOURCES = m_part.c
+m_quit_la_SOURCES = m_quit.c
+m_server_la_SOURCES = m_server.c
+m_sjoin_la_SOURCES = m_sjoin.c
+m_squit_la_SOURCES = m_squit.c
+
+modules_LTLIBRARIES = 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
+
+modules: $(modules_LTLIBRARIES)
+
+install-exec-hook:
+ if test -d $(DESTDIR)$(pkglibdir)-old; then \
+ rm -rf $(DESTDIR)$(pkglibdir)-old; \
+ fi
+ if test -d $(DESTDIR)$(pkglibdir); then \
+ mv $(DESTDIR)$(pkglibdir) $(DESTDIR)$(pkglibdir)-old; \
+ fi
diff --git a/modules/core/Makefile.in b/modules/core/Makefile.in
new file mode 100644
index 0000000..9af88eb
--- /dev/null
+++ b/modules/core/Makefile.in
@@ -0,0 +1,766 @@
+# 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@
+subdir = modules/core
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(top_srcdir)/depcomp
+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__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(modulesdir)"
+LTLIBRARIES = $(modules_LTLIBRARIES)
+m_die_la_LIBADD =
+am_m_die_la_OBJECTS = m_die.lo
+m_die_la_OBJECTS = $(am_m_die_la_OBJECTS)
+m_die_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(m_die_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+m_error_la_LIBADD =
+am_m_error_la_OBJECTS = m_error.lo
+m_error_la_OBJECTS = $(am_m_error_la_OBJECTS)
+m_error_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_error_la_LDFLAGS) $(LDFLAGS) -o $@
+m_join_la_LIBADD =
+am_m_join_la_OBJECTS = m_join.lo
+m_join_la_OBJECTS = $(am_m_join_la_OBJECTS)
+m_join_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_join_la_LDFLAGS) $(LDFLAGS) -o $@
+m_kick_la_LIBADD =
+am_m_kick_la_OBJECTS = m_kick.lo
+m_kick_la_OBJECTS = $(am_m_kick_la_OBJECTS)
+m_kick_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_kick_la_LDFLAGS) $(LDFLAGS) -o $@
+m_kill_la_LIBADD =
+am_m_kill_la_OBJECTS = m_kill.lo
+m_kill_la_OBJECTS = $(am_m_kill_la_OBJECTS)
+m_kill_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_kill_la_LDFLAGS) $(LDFLAGS) -o $@
+m_message_la_LIBADD =
+am_m_message_la_OBJECTS = m_message.lo
+m_message_la_OBJECTS = $(am_m_message_la_OBJECTS)
+m_message_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_message_la_LDFLAGS) $(LDFLAGS) -o $@
+m_mode_la_LIBADD =
+am_m_mode_la_OBJECTS = m_mode.lo
+m_mode_la_OBJECTS = $(am_m_mode_la_OBJECTS)
+m_mode_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_mode_la_LDFLAGS) $(LDFLAGS) -o $@
+m_nick_la_LIBADD =
+am_m_nick_la_OBJECTS = m_nick.lo
+m_nick_la_OBJECTS = $(am_m_nick_la_OBJECTS)
+m_nick_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_nick_la_LDFLAGS) $(LDFLAGS) -o $@
+m_part_la_LIBADD =
+am_m_part_la_OBJECTS = m_part.lo
+m_part_la_OBJECTS = $(am_m_part_la_OBJECTS)
+m_part_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_part_la_LDFLAGS) $(LDFLAGS) -o $@
+m_quit_la_LIBADD =
+am_m_quit_la_OBJECTS = m_quit.lo
+m_quit_la_OBJECTS = $(am_m_quit_la_OBJECTS)
+m_quit_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_quit_la_LDFLAGS) $(LDFLAGS) -o $@
+m_server_la_LIBADD =
+am_m_server_la_OBJECTS = m_server.lo
+m_server_la_OBJECTS = $(am_m_server_la_OBJECTS)
+m_server_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_server_la_LDFLAGS) $(LDFLAGS) -o $@
+m_sjoin_la_LIBADD =
+am_m_sjoin_la_OBJECTS = m_sjoin.lo
+m_sjoin_la_OBJECTS = $(am_m_sjoin_la_OBJECTS)
+m_sjoin_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_sjoin_la_LDFLAGS) $(LDFLAGS) -o $@
+m_squit_la_LIBADD =
+am_m_squit_la_OBJECTS = m_squit.lo
+m_squit_la_OBJECTS = $(am_m_squit_la_OBJECTS)
+m_squit_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_squit_la_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 $@
+SOURCES = $(m_die_la_SOURCES) $(m_error_la_SOURCES) \
+ $(m_join_la_SOURCES) $(m_kick_la_SOURCES) $(m_kill_la_SOURCES) \
+ $(m_message_la_SOURCES) $(m_mode_la_SOURCES) \
+ $(m_nick_la_SOURCES) $(m_part_la_SOURCES) $(m_quit_la_SOURCES) \
+ $(m_server_la_SOURCES) $(m_sjoin_la_SOURCES) \
+ $(m_squit_la_SOURCES)
+DIST_SOURCES = $(m_die_la_SOURCES) $(m_error_la_SOURCES) \
+ $(m_join_la_SOURCES) $(m_kick_la_SOURCES) $(m_kill_la_SOURCES) \
+ $(m_message_la_SOURCES) $(m_mode_la_SOURCES) \
+ $(m_nick_la_SOURCES) $(m_part_la_SOURCES) $(m_quit_la_SOURCES) \
+ $(m_server_la_SOURCES) $(m_sjoin_la_SOURCES) \
+ $(m_squit_la_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
+MODULE_FLAGS = -module -avoid-version
+AM_CPPFLAGS = -I$(top_srcdir)/include
+modulesdir = $(pkglibdir)/modules
+m_die_la_LDFLAGS = $(MODULE_FLAGS)
+m_error_la_LDFLAGS = $(MODULE_FLAGS)
+m_join_la_LDFLAGS = $(MODULE_FLAGS)
+m_kick_la_LDFLAGS = $(MODULE_FLAGS)
+m_kill_la_LDFLAGS = $(MODULE_FLAGS)
+m_message_la_LDFLAGS = $(MODULE_FLAGS)
+m_mode_la_LDFLAGS = $(MODULE_FLAGS)
+m_nick_la_LDFLAGS = $(MODULE_FLAGS)
+m_part_la_LDFLAGS = $(MODULE_FLAGS)
+m_quit_la_LDFLAGS = $(MODULE_FLAGS)
+m_server_la_LDFLAGS = $(MODULE_FLAGS)
+m_sjoin_la_LDFLAGS = $(MODULE_FLAGS)
+m_squit_la_LDFLAGS = $(MODULE_FLAGS)
+m_die_la_SOURCES = m_die.c
+m_error_la_SOURCES = m_error.c
+m_join_la_SOURCES = m_join.c
+m_kick_la_SOURCES = m_kick.c
+m_kill_la_SOURCES = m_kill.c
+m_message_la_SOURCES = m_message.c
+m_mode_la_SOURCES = m_mode.c
+m_nick_la_SOURCES = m_nick.c
+m_part_la_SOURCES = m_part.c
+m_quit_la_SOURCES = m_quit.c
+m_server_la_SOURCES = m_server.c
+m_sjoin_la_SOURCES = m_sjoin.c
+m_squit_la_SOURCES = m_squit.c
+modules_LTLIBRARIES = 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
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(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 modules/core/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign modules/core/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-modulesLTLIBRARIES: $(modules_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(modules_LTLIBRARIES)'; test -n "$(modulesdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(modulesdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(modulesdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(modulesdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(modulesdir)"; \
+ }
+
+uninstall-modulesLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(modules_LTLIBRARIES)'; test -n "$(modulesdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(modulesdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(modulesdir)/$$f"; \
+ done
+
+clean-modulesLTLIBRARIES:
+ -test -z "$(modules_LTLIBRARIES)" || rm -f $(modules_LTLIBRARIES)
+ @list='$(modules_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+m_die.la: $(m_die_la_OBJECTS) $(m_die_la_DEPENDENCIES) $(EXTRA_m_die_la_DEPENDENCIES)
+ $(m_die_la_LINK) -rpath $(modulesdir) $(m_die_la_OBJECTS) $(m_die_la_LIBADD) $(LIBS)
+m_error.la: $(m_error_la_OBJECTS) $(m_error_la_DEPENDENCIES) $(EXTRA_m_error_la_DEPENDENCIES)
+ $(m_error_la_LINK) -rpath $(modulesdir) $(m_error_la_OBJECTS) $(m_error_la_LIBADD) $(LIBS)
+m_join.la: $(m_join_la_OBJECTS) $(m_join_la_DEPENDENCIES) $(EXTRA_m_join_la_DEPENDENCIES)
+ $(m_join_la_LINK) -rpath $(modulesdir) $(m_join_la_OBJECTS) $(m_join_la_LIBADD) $(LIBS)
+m_kick.la: $(m_kick_la_OBJECTS) $(m_kick_la_DEPENDENCIES) $(EXTRA_m_kick_la_DEPENDENCIES)
+ $(m_kick_la_LINK) -rpath $(modulesdir) $(m_kick_la_OBJECTS) $(m_kick_la_LIBADD) $(LIBS)
+m_kill.la: $(m_kill_la_OBJECTS) $(m_kill_la_DEPENDENCIES) $(EXTRA_m_kill_la_DEPENDENCIES)
+ $(m_kill_la_LINK) -rpath $(modulesdir) $(m_kill_la_OBJECTS) $(m_kill_la_LIBADD) $(LIBS)
+m_message.la: $(m_message_la_OBJECTS) $(m_message_la_DEPENDENCIES) $(EXTRA_m_message_la_DEPENDENCIES)
+ $(m_message_la_LINK) -rpath $(modulesdir) $(m_message_la_OBJECTS) $(m_message_la_LIBADD) $(LIBS)
+m_mode.la: $(m_mode_la_OBJECTS) $(m_mode_la_DEPENDENCIES) $(EXTRA_m_mode_la_DEPENDENCIES)
+ $(m_mode_la_LINK) -rpath $(modulesdir) $(m_mode_la_OBJECTS) $(m_mode_la_LIBADD) $(LIBS)
+m_nick.la: $(m_nick_la_OBJECTS) $(m_nick_la_DEPENDENCIES) $(EXTRA_m_nick_la_DEPENDENCIES)
+ $(m_nick_la_LINK) -rpath $(modulesdir) $(m_nick_la_OBJECTS) $(m_nick_la_LIBADD) $(LIBS)
+m_part.la: $(m_part_la_OBJECTS) $(m_part_la_DEPENDENCIES) $(EXTRA_m_part_la_DEPENDENCIES)
+ $(m_part_la_LINK) -rpath $(modulesdir) $(m_part_la_OBJECTS) $(m_part_la_LIBADD) $(LIBS)
+m_quit.la: $(m_quit_la_OBJECTS) $(m_quit_la_DEPENDENCIES) $(EXTRA_m_quit_la_DEPENDENCIES)
+ $(m_quit_la_LINK) -rpath $(modulesdir) $(m_quit_la_OBJECTS) $(m_quit_la_LIBADD) $(LIBS)
+m_server.la: $(m_server_la_OBJECTS) $(m_server_la_DEPENDENCIES) $(EXTRA_m_server_la_DEPENDENCIES)
+ $(m_server_la_LINK) -rpath $(modulesdir) $(m_server_la_OBJECTS) $(m_server_la_LIBADD) $(LIBS)
+m_sjoin.la: $(m_sjoin_la_OBJECTS) $(m_sjoin_la_DEPENDENCIES) $(EXTRA_m_sjoin_la_DEPENDENCIES)
+ $(m_sjoin_la_LINK) -rpath $(modulesdir) $(m_sjoin_la_OBJECTS) $(m_sjoin_la_LIBADD) $(LIBS)
+m_squit.la: $(m_squit_la_OBJECTS) $(m_squit_la_DEPENDENCIES) $(EXTRA_m_squit_la_DEPENDENCIES)
+ $(m_squit_la_LINK) -rpath $(modulesdir) $(m_squit_la_OBJECTS) $(m_squit_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_die.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_error.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_join.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_kick.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_kill.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_message.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_mode.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_nick.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_part.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_quit.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_server.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_sjoin.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_squit.Plo@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 $@ $<
+
+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 $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(modulesdir)"; 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."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-modulesLTLIBRARIES \
+ 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-modulesLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+ @$(NORMAL_INSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) install-exec-hook
+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-modulesLTLIBRARIES
+
+.MAKE: install-am install-exec-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-modulesLTLIBRARIES 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-exec-hook install-html install-html-am \
+ install-info install-info-am install-man \
+ install-modulesLTLIBRARIES install-pdf install-pdf-am \
+ install-ps install-ps-am 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-modulesLTLIBRARIES
+
+
+modules: $(modules_LTLIBRARIES)
+
+install-exec-hook:
+ if test -d $(DESTDIR)$(pkglibdir)-old; then \
+ rm -rf $(DESTDIR)$(pkglibdir)-old; \
+ fi
+ if test -d $(DESTDIR)$(pkglibdir); then \
+ mv $(DESTDIR)$(pkglibdir) $(DESTDIR)$(pkglibdir)-old; \
+ fi
+
+# 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/modules/core/m_die.c b/modules/core/m_die.c
new file mode 100644
index 0000000..b47c92c
--- /dev/null
+++ b/modules/core/m_die.c
@@ -0,0 +1,97 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_die.c: Kills off this server.
+ *
+ * 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 "ircd.h"
+#include "irc_string.h"
+#include "numeric.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+#include "restart.h"
+#include "conf.h"
+
+
+/*
+ * mo_die - DIE command handler
+ */
+static void
+mo_die(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ char buf[IRCD_BUFSIZE];
+
+ if (!HasOFlag(source_p, OPER_FLAG_DIE))
+ {
+ sendto_one(source_p, form_str(ERR_NOPRIVS),
+ me.name, source_p->name, "die");
+ return;
+ }
+
+ if (parc < 2 || EmptyString(parv[1]))
+ {
+ sendto_one(source_p, ":%s NOTICE %s :Need server name /die %s",
+ me.name, source_p->name, me.name);
+ return;
+ }
+
+ if (irccmp(parv[1], me.name))
+ {
+ sendto_one(source_p, ":%s NOTICE %s :Mismatch on /die %s",
+ me.name, source_p->name, me.name);
+ return;
+ }
+
+ snprintf(buf, sizeof(buf), "received DIE command from %s",
+ get_oper_name(source_p));
+ server_die(buf, 0);
+}
+
+static struct Message die_msgtab = {
+ "DIE", 0, 0, 1, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_not_oper, m_ignore, m_ignore, mo_die, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&die_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&die_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = MODULE_FLAG_CORE
+};
diff --git a/modules/core/m_error.c b/modules/core/m_error.c
new file mode 100644
index 0000000..9228628
--- /dev/null
+++ b/modules/core/m_error.c
@@ -0,0 +1,116 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_error.c: Handles error messages from the other end.
+ *
+ * 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 "ircd.h"
+#include "send.h"
+#include "modules.h"
+#include "log.h"
+#include "parse.h"
+
+
+/*
+ * Note: At least at protocol level ERROR has only one parameter.
+ * --msa
+ *
+ * parv[0] = sender prefix
+ * parv[*] = parameters
+ */
+static void
+m_error(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ const char *para;
+
+ para = (parc > 1 && *parv[1] != '\0') ? parv[1] : "<>";
+
+ ilog(LOG_TYPE_IRCD, "Received ERROR message from %s: %s",
+ source_p->name, para);
+
+ if (client_p == source_p)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ADMIN, "ERROR :from %s -- %s",
+ get_client_name(client_p, HIDE_IP), para);
+ sendto_realops_flags(UMODE_ALL, L_OPER, "ERROR :from %s -- %s",
+ get_client_name(client_p, MASK_IP), 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), para);
+ sendto_realops_flags(UMODE_ALL, L_ADMIN, "ERROR :from %s via %s -- %s",
+ source_p->name, get_client_name(client_p, HIDE_IP), para);
+ }
+
+ if (MyClient(source_p))
+ exit_client(source_p, source_p, "ERROR");
+}
+
+static void
+ms_error(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ const char *para;
+
+ para = (parc > 1 && *parv[1] != '\0') ? parv[1] : "<>";
+
+ ilog(LOG_TYPE_IRCD, "Received ERROR message from %s: %s",
+ source_p->name, para);
+
+ if (client_p == source_p)
+ sendto_realops_flags(UMODE_ALL, L_ALL, "ERROR :from %s -- %s",
+ get_client_name(client_p, MASK_IP), para);
+ else
+ sendto_realops_flags(UMODE_ALL, L_ALL, "ERROR :from %s via %s -- %s",
+ source_p->name,
+ get_client_name(client_p, MASK_IP), para);
+}
+
+static struct Message error_msgtab = {
+ "ERROR", 0, 0, 1, MAXPARA, MFLG_SLOW, 0,
+ { m_error, m_ignore, ms_error, m_ignore, m_ignore, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&error_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&error_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = MODULE_FLAG_CORE
+};
diff --git a/modules/core/m_join.c b/modules/core/m_join.c
new file mode 100644
index 0000000..35bbf3a
--- /dev/null
+++ b/modules/core/m_join.c
@@ -0,0 +1,680 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_join.c: Joins a channel.
+ *
+ * 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 "channel.h"
+#include "channel_mode.h"
+#include "client.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "s_serv.h"
+#include "conf.h"
+#include "parse.h"
+#include "modules.h"
+
+
+static void do_join_0(struct Client *, struct Client *);
+
+static void set_final_mode(struct Mode *, struct Mode *);
+static void remove_our_modes(struct Channel *, struct Client *);
+static void remove_a_mode(struct Channel *, struct Client *, int, char);
+
+static char modebuf[MODEBUFLEN];
+static char parabuf[MODEBUFLEN];
+static char sendbuf[MODEBUFLEN];
+static char *mbuf;
+
+/* last0() stolen from ircu */
+static char *
+last0(struct Client *client_p, struct Client *source_p, char *chanlist)
+{
+ char *p;
+ int join0 = 0;
+
+ for (p = chanlist; *p; ++p) /* find last "JOIN 0" */
+ {
+ if (*p == '0' && (*(p + 1) == ',' || *(p + 1) == '\0'))
+ {
+ if ((*p + 1) == ',')
+ ++p;
+
+ chanlist = p + 1;
+ join0 = 1;
+ }
+ else
+ {
+ while (*p != ',' && *p != '\0') /* skip past channel name */
+ ++p;
+
+ if (*p == '\0') /* hit the end */
+ break;
+ }
+ }
+
+ if (join0)
+ do_join_0(client_p, source_p);
+
+ return chanlist;
+}
+
+/* m_join()
+ * parv[0] = sender prefix
+ * parv[1] = channel
+ * parv[2] = channel password (key)
+ */
+static void
+m_join(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ char *p = NULL;
+ char *key_list = NULL;
+ char *chan_list = NULL;
+ char *chan = NULL;
+ struct Channel *chptr = NULL;
+ int i = 0;
+ unsigned int flags = 0;
+
+ if (EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, "JOIN");
+ return;
+ }
+
+ assert(client_p == source_p);
+
+ key_list = parv[2];
+ chan_list = last0(client_p, source_p, parv[1]);
+
+ for (chan = strtoken(&p, chan_list, ","); chan;
+ chan = strtoken(&p, NULL, ","))
+ {
+ char *key = NULL;
+
+ /* If we have any more keys, take the first for this channel. */
+ if (!EmptyString(key_list) && (key_list = strchr(key = key_list, ',')))
+ *key_list++ = '\0';
+
+ /* Empty keys are the same as no keys. */
+ if (key && *key == '\0')
+ key = NULL;
+
+ if (!check_channel_name(chan, 1))
+ {
+ sendto_one(source_p, form_str(ERR_BADCHANNAME),
+ me.name, source_p->name, chan);
+ continue;
+ }
+
+ if (!IsExemptResv(source_p) &&
+ !(HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.oper_pass_resv) &&
+ (!hash_find_resv(chan) == ConfigChannel.restrict_channels))
+ {
+ sendto_one(source_p, form_str(ERR_BADCHANNAME),
+ me.name, source_p->name, chan);
+ sendto_realops_flags(UMODE_SPY, L_ALL,
+ "Forbidding reserved channel [%s] from user %s",
+ chan, get_client_name(source_p, HIDE_IP));
+ continue;
+ }
+
+ if (dlink_list_length(&source_p->channel) >=
+ (HasUMode(source_p, UMODE_OPER) ?
+ ConfigChannel.max_chans_per_oper :
+ ConfigChannel.max_chans_per_user))
+ {
+ sendto_one(source_p, form_str(ERR_TOOMANYCHANNELS),
+ me.name, source_p->name, chan);
+ break;
+ }
+
+ if ((chptr = hash_find_channel(chan)) != NULL)
+ {
+ if (IsMember(source_p, chptr))
+ continue;
+
+ if (splitmode && !HasUMode(source_p, UMODE_OPER) &&
+ ConfigChannel.no_join_on_split)
+ {
+ sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
+ me.name, source_p->name, chan);
+ continue;
+ }
+
+ /*
+ * can_join checks for +i key, bans.
+ */
+ if ((i = can_join(source_p, chptr, key)))
+ {
+ sendto_one(source_p, form_str(i), me.name,
+ source_p->name, chptr->chname);
+ continue;
+ }
+
+ /*
+ * This should never be the case unless there is some sort of
+ * persistant channels.
+ */
+ if (dlink_list_length(&chptr->members) == 0)
+ flags = CHFL_CHANOP;
+ else
+ flags = 0;
+ }
+ else
+ {
+ if (splitmode && !HasUMode(source_p, UMODE_OPER) &&
+ (ConfigChannel.no_create_on_split || ConfigChannel.no_join_on_split))
+ {
+ sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
+ me.name, source_p->name, chan);
+ continue;
+ }
+
+ flags = CHFL_CHANOP;
+ chptr = make_channel(chan);
+ }
+
+ if (!HasUMode(source_p, UMODE_OPER))
+ check_spambot_warning(source_p, chptr->chname);
+
+ add_user_to_channel(chptr, source_p, flags, 1);
+
+ /*
+ * Set timestamp if appropriate, and propagate
+ */
+ if (flags & CHFL_CHANOP)
+ {
+ chptr->channelts = CurrentTime;
+ chptr->mode.mode |= MODE_TOPICLIMIT;
+ chptr->mode.mode |= MODE_NOPRIVMSGS;
+
+ sendto_server(client_p, CAP_TS6, NOCAPS,
+ ":%s SJOIN %lu %s +nt :@%s",
+ me.id, (unsigned long)chptr->channelts,
+ chptr->chname, source_p->id);
+ sendto_server(client_p, NOCAPS, CAP_TS6,
+ ":%s SJOIN %lu %s +nt :@%s",
+ me.name, (unsigned long)chptr->channelts,
+ chptr->chname, source_p->name);
+ /*
+ * notify all other users on the new channel
+ */
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s JOIN :%s",
+ source_p->name, source_p->username,
+ source_p->host, chptr->chname);
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s MODE %s +nt",
+ me.name, chptr->chname);
+ }
+ else
+ {
+ sendto_server(client_p, CAP_TS6, NOCAPS,
+ ":%s JOIN %lu %s +",
+ source_p->id, (unsigned long)chptr->channelts,
+ chptr->chname);
+ sendto_server(client_p, NOCAPS, CAP_TS6,
+ ":%s SJOIN %lu %s + :%s",
+ me.name, (unsigned long)chptr->channelts,
+ chptr->chname, source_p->name);
+
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s JOIN :%s",
+ source_p->name, source_p->username,
+ source_p->host, chptr->chname);
+ }
+
+ del_invite(chptr, source_p);
+
+ if (chptr->topic[0])
+ {
+ sendto_one(source_p, form_str(RPL_TOPIC), me.name,
+ source_p->name, chptr->chname, chptr->topic);
+
+ sendto_one(source_p, form_str(RPL_TOPICWHOTIME),
+ me.name, source_p->name, chptr->chname,
+ chptr->topic_info, chptr->topic_time);
+ }
+
+ channel_member_names(source_p, chptr, 1);
+
+ source_p->localClient->last_join_time = CurrentTime;
+ }
+}
+
+/* ms_join()
+ *
+ * inputs - parv[0] = uid
+ * parv[1] = ts
+ * parv[2] = channel name
+ * parv[3] = modes (Deprecated)
+ * output - none
+ * side effects - handles remote JOIN's sent by servers. In TSora
+ * remote clients are joined using SJOIN, hence a
+ * JOIN sent by a server on behalf of a client is an error.
+ * here, the initial code is in to take an extra parameter
+ * and use it for the TimeStamp on a new channel.
+ */
+static void
+ms_join(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ time_t newts = 0;
+ time_t oldts = 0;
+ int keep_our_modes = 1;
+ int keep_new_modes = 1;
+ int isnew = 0;
+ const char *servername = NULL;
+ struct Channel *chptr = NULL;
+ struct Mode mode, *oldmode;
+
+ if (parc == 2 && !irccmp(parv[1], "0"))
+ {
+ do_join_0(client_p, source_p);
+ return;
+ }
+
+ if (parc < 4)
+ return;
+
+ if (!check_channel_name(parv[2], 0))
+ {
+ sendto_realops_flags(UMODE_DEBUG, L_ALL,
+ "*** Too long or invalid channel name from %s: %s",
+ client_p->name, parv[2]);
+ return;
+ }
+
+ mbuf = modebuf;
+ mode.mode = mode.limit = 0;
+ mode.key[0] = '\0';
+
+ if ((chptr = hash_find_channel(parv[2])) == NULL)
+ {
+ isnew = 1;
+ chptr = make_channel(parv[2]);
+ }
+
+ newts = atol(parv[1]);
+ oldts = chptr->channelts;
+ oldmode = &chptr->mode;
+
+ if (ConfigFileEntry.ignore_bogus_ts)
+ {
+ if (newts < 800000000)
+ {
+ sendto_realops_flags(UMODE_DEBUG, L_ALL,
+ "*** Bogus TS %lu on %s ignored from %s",
+ (unsigned long)newts, chptr->chname,
+ client_p->name);
+
+ newts = (oldts == 0) ? 0 : 800000000;
+ }
+ }
+ else
+ {
+ if (!newts && !isnew && oldts)
+ {
+ sendto_channel_local(ALL_MEMBERS, 0, chptr,
+ ":%s NOTICE %s :*** Notice -- TS for %s changed from %lu to 0",
+ me.name, chptr->chname, chptr->chname, (unsigned long)oldts);
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Server %s changing TS on %s from %lu to 0",
+ source_p->name, chptr->chname, (unsigned long)oldts);
+ }
+ }
+
+ if (isnew)
+ chptr->channelts = newts;
+ else if (newts == 0 || oldts == 0)
+ chptr->channelts = 0;
+ else if (newts == oldts)
+ ;
+ else if (newts < oldts)
+ {
+ keep_our_modes = 0;
+ chptr->channelts = newts;
+ }
+ else
+ keep_new_modes = 0;
+
+ if (!keep_new_modes)
+ mode = *oldmode;
+ else if (keep_our_modes)
+ {
+ mode.mode |= oldmode->mode;
+ if (oldmode->limit > mode.limit)
+ mode.limit = oldmode->limit;
+ if (strcmp(mode.key, oldmode->key) < 0)
+ strcpy(mode.key, oldmode->key);
+ }
+
+ set_final_mode(&mode, oldmode);
+ chptr->mode = mode;
+
+ /* Lost the TS, other side wins, so remove modes on this side */
+ if (!keep_our_modes)
+ {
+ remove_our_modes(chptr, source_p);
+
+ if (chptr->topic[0])
+ {
+ set_channel_topic(chptr, "", "", 0);
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s TOPIC %s :",
+ (IsHidden(source_p) ||
+ ConfigServerHide.hide_servers) ?
+ me.name : source_p->name, chptr->chname);
+ }
+
+ sendto_channel_local(ALL_MEMBERS, 0, chptr,
+ ":%s NOTICE %s :*** Notice -- TS for %s changed from %lu to %lu",
+ me.name, chptr->chname, chptr->chname,
+ (unsigned long)oldts, (unsigned long)newts);
+ }
+
+ if (*modebuf != '\0')
+ {
+ servername = (ConfigServerHide.hide_servers || IsHidden(source_p)) ?
+ me.name : source_p->name;
+
+ /* This _SHOULD_ be to ALL_MEMBERS
+ * It contains only +imnpstlk, etc */
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s MODE %s %s %s",
+ servername, chptr->chname, modebuf, parabuf);
+ }
+
+ if (!IsMember(source_p, chptr))
+ {
+ add_user_to_channel(chptr, source_p, 0, 1);
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s JOIN :%s",
+ source_p->name, source_p->username,
+ source_p->host, chptr->chname);
+ }
+
+ sendto_server(client_p, CAP_TS6, NOCAPS,
+ ":%s JOIN %lu %s +",
+ ID(source_p), (unsigned long)chptr->channelts, chptr->chname);
+ sendto_server(client_p, NOCAPS, CAP_TS6,
+ ":%s SJOIN %lu %s + :%s",
+ source_p->servptr->name, (unsigned long)chptr->channelts,
+ chptr->chname, source_p->name);
+}
+
+/* do_join_0()
+ *
+ * inputs - pointer to client doing join 0
+ * output - NONE
+ * side effects - Use has decided to join 0. This is legacy
+ * from the days when channels were numbers not names. *sigh*
+ * There is a bunch of evilness necessary here due to
+ * anti spambot code.
+ */
+static void
+do_join_0(struct Client *client_p, struct Client *source_p)
+{
+ struct Channel *chptr = NULL;
+ dlink_node *ptr = NULL, *ptr_next = NULL;
+
+ if (source_p->channel.head)
+ if (MyConnect(source_p) && !HasUMode(source_p, UMODE_OPER))
+ check_spambot_warning(source_p, NULL);
+
+ DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->channel.head)
+ {
+ chptr = ((struct Membership *)ptr->data)->chptr;
+
+ sendto_server(client_p, CAP_TS6, NOCAPS,
+ ":%s PART %s", ID(source_p), chptr->chname);
+ sendto_server(client_p, NOCAPS, CAP_TS6,
+ ":%s PART %s", source_p->name, chptr->chname);
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s PART %s",
+ source_p->name, source_p->username,
+ source_p->host, chptr->chname);
+
+ remove_user_from_channel(ptr->data);
+ }
+}
+
+/* set_final_mode
+ *
+ * inputs - channel mode
+ * - old channel mode
+ * output - NONE
+ * side effects - walk through all the channel modes turning off modes
+ * that were on in oldmode but aren't on in mode.
+ * Then walk through turning on modes that are on in mode
+ * but were not set in oldmode.
+ */
+static void
+set_final_mode(struct Mode *mode, struct Mode *oldmode)
+{
+ const struct mode_letter *tab;
+ char *pbuf = parabuf;
+ int what = 0;
+ int len;
+
+ for (tab = chan_modes; tab->letter; ++tab)
+ {
+ if ((tab->mode & mode->mode) &&
+ !(tab->mode & oldmode->mode))
+ {
+ if (what != 1)
+ {
+ *mbuf++ = '+';
+ what = 1;
+ }
+ *mbuf++ = tab->letter;
+ }
+ }
+
+ for (tab = chan_modes; tab->letter; ++tab)
+ {
+ if ((tab->mode & oldmode->mode) &&
+ !(tab->mode & mode->mode))
+ {
+ if (what != -1)
+ {
+ *mbuf++ = '-';
+ what = -1;
+ }
+ *mbuf++ = tab->letter;
+ }
+ }
+
+ if (oldmode->limit != 0 && mode->limit == 0)
+ {
+ if (what != -1)
+ {
+ *mbuf++ = '-';
+ what = -1;
+ }
+ *mbuf++ = 'l';
+ }
+
+ if (oldmode->key[0] && !mode->key[0])
+ {
+ if (what != -1)
+ {
+ *mbuf++ = '-';
+ what = -1;
+ }
+ *mbuf++ = 'k';
+ len = ircsprintf(pbuf, "%s ", oldmode->key);
+ pbuf += len;
+ }
+
+ if (mode->limit != 0 && oldmode->limit != mode->limit)
+ {
+ if (what != 1)
+ {
+ *mbuf++ = '+';
+ what = 1;
+ }
+ *mbuf++ = 'l';
+ len = ircsprintf(pbuf, "%d ", mode->limit);
+ pbuf += len;
+ }
+
+ if (mode->key[0] && strcmp(oldmode->key, mode->key))
+ {
+ if (what != 1)
+ {
+ *mbuf++ = '+';
+ what = 1;
+ }
+ *mbuf++ = 'k';
+ len = ircsprintf(pbuf, "%s ", mode->key);
+ pbuf += len;
+ }
+ *mbuf = '\0';
+}
+
+/* remove_our_modes()
+ *
+ * inputs - pointer to channel to remove modes from
+ * - client pointer
+ * output - NONE
+ * side effects - Go through the local members, remove all their
+ * chanop modes etc., this side lost the TS.
+ */
+static void
+remove_our_modes(struct Channel *chptr, struct Client *source_p)
+{
+ remove_a_mode(chptr, source_p, CHFL_CHANOP, 'o');
+#ifdef HALFOPS
+ remove_a_mode(chptr, source_p, CHFL_HALFOP, 'h');
+#endif
+ remove_a_mode(chptr, source_p, CHFL_VOICE, 'v');
+}
+
+/* remove_a_mode()
+ *
+ * inputs -
+ * output - NONE
+ * side effects - remove ONE mode from a channel
+ */
+static void
+remove_a_mode(struct Channel *chptr, struct Client *source_p,
+ int mask, char flag)
+{
+ dlink_node *ptr;
+ struct Membership *ms;
+ char lmodebuf[MODEBUFLEN];
+ const char *lpara[MAXMODEPARAMS];
+ int count = 0;
+ int lcount;
+
+ mbuf = lmodebuf;
+ *mbuf++ = '-';
+
+ for (lcount = 0; lcount < MAXMODEPARAMS; lcount++)
+ lpara[lcount] = "";
+ sendbuf[0] = '\0';
+
+ DLINK_FOREACH(ptr, chptr->members.head)
+ {
+ ms = ptr->data;
+
+ if ((ms->flags & mask) == 0)
+ continue;
+
+ ms->flags &= ~mask;
+
+ lpara[count++] = ms->client_p->name;
+
+ *mbuf++ = flag;
+
+ if (count >= MAXMODEPARAMS)
+ {
+ for (lcount = 0; lcount < MAXMODEPARAMS; lcount++)
+ {
+ if (*lpara[lcount] == '\0')
+ break;
+
+ strlcat(sendbuf, " ", sizeof(sendbuf));
+ strlcat(sendbuf, lpara[lcount], sizeof(sendbuf));
+ lpara[lcount] = "";
+ }
+
+ *mbuf = '\0';
+ sendto_channel_local(ALL_MEMBERS, 0, chptr,
+ ":%s MODE %s %s%s",
+ (IsHidden(source_p) ||
+ ConfigServerHide.hide_servers) ?
+ me.name : source_p->name,
+ chptr->chname, lmodebuf, sendbuf);
+ mbuf = lmodebuf;
+ *mbuf++ = '-';
+ count = 0;
+ sendbuf[0] = '\0';
+ }
+ }
+
+ if (count != 0)
+ {
+ *mbuf = '\0';
+ for (lcount = 0; lcount < MAXMODEPARAMS; lcount++)
+ {
+ if (*lpara[lcount] == '\0')
+ break;
+
+ strlcat(sendbuf, " ", sizeof(sendbuf));
+ strlcat(sendbuf, lpara[lcount], sizeof(sendbuf));
+ }
+ sendto_channel_local(ALL_MEMBERS, 0, chptr,
+ ":%s MODE %s %s%s",
+ (IsHidden(source_p) || ConfigServerHide.hide_servers) ?
+ me.name : source_p->name,
+ chptr->chname, lmodebuf, sendbuf);
+ }
+}
+
+static struct Message join_msgtab = {
+ "JOIN", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_join, ms_join, m_ignore, m_join, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&join_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&join_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = MODULE_FLAG_CORE
+};
diff --git a/modules/core/m_kick.c b/modules/core/m_kick.c
new file mode 100644
index 0000000..f800136
--- /dev/null
+++ b/modules/core/m_kick.c
@@ -0,0 +1,241 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_kick.c: Kicks a user from a channel.
+ *
+ * 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 "channel.h"
+#include "channel_mode.h"
+#include "client.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "modules.h"
+#include "parse.h"
+#include "hash.h"
+#include "packet.h"
+#include "s_serv.h"
+
+
+/* m_kick()
+ * parv[0] = sender prefix
+ * parv[1] = channel
+ * parv[2] = client to kick
+ * parv[3] = kick comment
+ */
+static void
+m_kick(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *who;
+ struct Channel *chptr;
+ int chasing = 0;
+ char *comment;
+ char *name;
+ char *p = NULL;
+ char *user;
+ const char *from, *to;
+ struct Membership *ms = NULL;
+ struct Membership *ms_target;
+
+ 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 (EmptyString(parv[2]))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ from, to, "KICK");
+ return;
+ }
+
+ if (MyClient(source_p) && !IsFloodDone(source_p))
+ flood_endgrace(source_p);
+
+ comment = (EmptyString(parv[3])) ? parv[2] : parv[3];
+ if (strlen(comment) > (size_t)KICKLEN)
+ comment[KICKLEN] = '\0';
+
+ name = parv[1];
+ while (*name == ',')
+ name++;
+
+ if ((p = strchr(name,',')) != NULL)
+ *p = '\0';
+ if (*name == '\0')
+ return;
+
+ if ((chptr = hash_find_channel(name)) == NULL)
+ {
+ sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
+ from, to, name);
+ return;
+ }
+
+ if (!IsServer(source_p) && !HasFlag(source_p, FLAGS_SERVICE))
+ {
+ if ((ms = find_channel_link(source_p, chptr)) == NULL)
+ {
+ if (MyConnect(source_p))
+ {
+ sendto_one(source_p, form_str(ERR_NOTONCHANNEL),
+ me.name, source_p->name, name);
+ return;
+ }
+ }
+
+ if (!has_member_flags(ms, CHFL_CHANOP|CHFL_HALFOP))
+ {
+ /* was a user, not a server, and user isn't seen as a chanop here */
+ if (MyConnect(source_p))
+ {
+ /* user on _my_ server, with no chanops.. so go away */
+ sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
+ me.name, source_p->name, name);
+ return;
+ }
+
+ if (chptr->channelts == 0)
+ {
+ /* If its a TS 0 channel, do it the old way */
+ sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
+ from, to, name);
+ return;
+ }
+
+ /* Its a user doing a kick, but is not showing as chanop locally
+ * its also not a user ON -my- server, and the channel has a TS.
+ * There are two cases we can get to this point then...
+ *
+ * 1) connect burst is happening, and for some reason a legit
+ * op has sent a KICK, but the SJOIN hasn't happened yet or
+ * been seen. (who knows.. due to lag...)
+ *
+ * 2) The channel is desynced. That can STILL happen with TS
+ *
+ * Now, the old code roger wrote, would allow the KICK to
+ * go through. Thats quite legit, but lets weird things like
+ * KICKS by users who appear not to be chanopped happen,
+ * or even neater, they appear not to be on the channel.
+ * This fits every definition of a desync, doesn't it? ;-)
+ * So I will allow the KICK, otherwise, things are MUCH worse.
+ * But I will warn it as a possible desync.
+ *
+ * -Dianora
+ */
+ }
+ }
+
+ user = parv[2];
+
+ while (*user == ',')
+ user++;
+
+ if ((p = strchr(user, ',')) != NULL)
+ *p = '\0';
+
+ if (*user == '\0')
+ return;
+
+ if ((who = find_chasing(client_p, source_p, user, &chasing)) == NULL)
+ return;
+
+ if ((ms_target = find_channel_link(who, chptr)) != NULL)
+ {
+#ifdef HALFOPS
+ /* half ops cannot kick other halfops on private channels */
+ if (has_member_flags(ms, CHFL_HALFOP) && !has_member_flags(ms, CHFL_CHANOP))
+ {
+ if (((chptr->mode.mode & MODE_PRIVATE) && has_member_flags(ms_target,
+ CHFL_CHANOP|CHFL_HALFOP)) || has_member_flags(ms_target, CHFL_CHANOP))
+ {
+ sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
+ me.name, source_p->name, name);
+ return;
+ }
+ }
+#endif
+
+ /* jdc
+ * - In the case of a server kicking a user (i.e. CLEARCHAN),
+ * the kick should show up as coming from the server which did
+ * the kick.
+ * - Personally, flame and I believe that server kicks shouldn't
+ * be sent anyways. Just waiting for some oper to abuse it...
+ */
+ if (IsServer(source_p))
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s KICK %s %s :%s",
+ source_p->name, name, who->name, comment);
+ else
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s KICK %s %s :%s",
+ source_p->name, source_p->username,
+ source_p->host, name, who->name, comment);
+
+ sendto_server(client_p, CAP_TS6, NOCAPS,
+ ":%s KICK %s %s :%s",
+ ID(source_p), chptr->chname, ID(who), comment);
+ sendto_server(client_p, NOCAPS, CAP_TS6,
+ ":%s KICK %s %s :%s", source_p->name, chptr->chname,
+ who->name, comment);
+
+ remove_user_from_channel(ms_target);
+ }
+ else
+ sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
+ from, to, user, name);
+}
+
+static struct Message kick_msgtab = {
+ "KICK", 0, 0, 3, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_kick, m_kick, m_ignore, m_kick, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&kick_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&kick_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = MODULE_FLAG_CORE
+};
diff --git a/modules/core/m_kill.c b/modules/core/m_kill.c
new file mode 100644
index 0000000..a76e5a4
--- /dev/null
+++ b/modules/core/m_kill.c
@@ -0,0 +1,331 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_kill.c: Kills a user.
+ *
+ * Copyright (C) 2002 by the past and present ircd coders, and others.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * $Id$
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "client.h"
+#include "hash.h" /* for find_client() */
+#include "ircd.h"
+#include "numeric.h"
+#include "log.h"
+#include "s_serv.h"
+#include "conf.h"
+#include "send.h"
+#include "whowas.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "parse.h"
+#include "modules.h"
+
+
+static char buf[IRCD_BUFSIZE];
+
+static void
+relay_kill(struct Client *one, struct Client *source_p,
+ struct Client *target_p, const char *inpath,
+ const char *reason)
+{
+ dlink_node *ptr = NULL;
+
+ DLINK_FOREACH(ptr, serv_list.head)
+ {
+ struct Client *client_p = ptr->data;
+
+ if (client_p == one)
+ continue;
+
+ if (MyClient(source_p))
+ sendto_one(client_p, ":%s KILL %s :%s!%s!%s!%s (%s)",
+ ID_or_name(source_p, client_p),
+ ID_or_name(target_p, client_p),
+ me.name, source_p->host, source_p->username,
+ source_p->name, reason);
+ else
+ sendto_one(client_p, ":%s KILL %s :%s %s",
+ ID_or_name(source_p, client_p),
+ ID_or_name(target_p, client_p), inpath, reason);
+ }
+}
+
+/* mo_kill()
+ * parv[0] = sender prefix
+ * parv[1] = kill victim
+ * parv[2] = kill path
+ */
+static void
+mo_kill(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *target_p;
+ const char *inpath = client_p->name;
+ char *user;
+ char *reason;
+ char def_reason[] = "No reason";
+
+ user = parv[1];
+ reason = parv[2]; /* Either defined or NULL (parc >= 2!!) */
+
+ if (*user == '\0')
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, "KILL");
+ return;
+ }
+
+ if (!HasOFlag(source_p, OPER_FLAG_GLOBAL_KILL|OPER_FLAG_K))
+ {
+ sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
+ me.name, source_p->name);
+ return;
+ }
+
+ if (!EmptyString(reason))
+ {
+ if (strlen(reason) > (size_t)KILLLEN)
+ reason[KILLLEN] = '\0';
+ }
+ else
+ reason = def_reason;
+
+ if ((target_p = hash_find_client(user)) == NULL)
+ {
+ /*
+ * If the user has recently changed nick, automatically
+ * rewrite the KILL for this new nickname--this keeps
+ * servers in synch when nick change and kill collide
+ */
+ if ((target_p = get_history(user,
+ (time_t)ConfigFileEntry.kill_chase_time_limit))
+ == NULL)
+ {
+ sendto_one(source_p, form_str(ERR_NOSUCHNICK),
+ me.name, source_p->name, user);
+ return;
+ }
+
+ sendto_one(source_p, ":%s NOTICE %s :KILL changed from %s to %s",
+ me.name, source_p->name, user, target_p->name);
+ }
+
+ if (IsServer(target_p) || IsMe(target_p))
+ {
+ sendto_one(source_p, form_str(ERR_CANTKILLSERVER),
+ me.name, source_p->name);
+ return;
+ }
+
+ if (!MyConnect(target_p) && !HasOFlag(source_p, OPER_FLAG_GLOBAL_KILL))
+ {
+ sendto_one(source_p, ":%s NOTICE %s :Nick %s isnt on your server",
+ me.name, source_p->name, target_p->name);
+ return;
+ }
+
+ if (MyConnect(target_p))
+ sendto_one(target_p, ":%s!%s@%s KILL %s :%s",
+ source_p->name, source_p->username, source_p->host,
+ target_p->name, reason);
+
+ /*
+ * Do not change the format of this message. There's no point in changing messages
+ * that have been around for ever, for no reason..
+ */
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Received KILL message for %s. From %s Path: %s (%s)",
+ target_p->name, source_p->name, me.name, reason);
+
+ ilog(LOG_TYPE_KILL, "KILL From %s For %s Path %s (%s)",
+ source_p->name, target_p->name, me.name, reason);
+
+ /*
+ * And pass on the message to other servers. Note, that if KILL
+ * was changed, the message has to be sent to all links, also
+ * back.
+ * Suicide kills are NOT passed on --SRB
+ */
+ if (!MyConnect(target_p))
+ {
+ relay_kill(client_p, source_p, target_p, inpath, reason);
+ /*
+ * Set FLAGS_KILLED. This prevents exit_one_client from sending
+ * the unnecessary QUIT for this. (This flag should never be
+ * set in any other place)
+ */
+ AddFlag(target_p, FLAGS_KILLED);
+ }
+
+ snprintf(buf, sizeof(buf), "Killed (%s (%s))", source_p->name, reason);
+ exit_client(target_p, source_p, buf);
+}
+
+/* ms_kill()
+ * parv[0] = sender prefix
+ * parv[1] = kill victim
+ * parv[2] = kill path and reason
+ */
+static void
+ms_kill(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *target_p;
+ char *user;
+ char *reason;
+ const char *path;
+ char def_reason[] = "No reason";
+
+ if (EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, "KILL");
+ return;
+ }
+
+ user = parv[1];
+
+ if (EmptyString(parv[2]))
+ {
+ reason = def_reason;
+
+ /* hyb6 takes the nick of the killer from the path *sigh* --fl_ */
+ path = source_p->name;
+ }
+ else
+ {
+ reason = strchr(parv[2], ' ');
+
+ if (reason != NULL)
+ *reason++ = '\0';
+ else
+ reason = def_reason;
+
+ path = parv[2];
+ }
+
+ if ((target_p = find_person(client_p, user)) == NULL)
+ {
+ /*
+ * If the user has recently changed nick, but only if its
+ * not an uid, automatically rewrite the KILL for this new nickname.
+ * --this keeps servers in synch when nick change and kill collide
+ */
+ if (IsDigit(*user)) /* Somehow an uid was not found in the hash ! */
+ return;
+ if ((target_p = 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;
+ }
+
+ sendto_one(source_p,":%s NOTICE %s :KILL changed from %s to %s",
+ me.name, source_p->name, user, target_p->name);
+ }
+
+ if (IsServer(target_p) || IsMe(target_p))
+ {
+ sendto_one(source_p, form_str(ERR_CANTKILLSERVER),
+ me.name, source_p->name);
+ return;
+ }
+
+ if (MyConnect(target_p))
+ {
+ if (IsServer(source_p))
+ {
+ /* dont send clients kills from a hidden server */
+ if ((IsHidden(source_p) || ConfigServerHide.hide_servers) && !HasUMode(target_p, UMODE_OPER))
+ sendto_one(target_p, ":%s KILL %s :%s",
+ me.name, target_p->name, reason);
+ else
+ sendto_one(target_p, ":%s KILL %s :%s",
+ source_p->name, target_p->name, reason);
+ }
+ else
+ sendto_one(target_p, ":%s!%s@%s KILL %s :%s",
+ source_p->name, source_p->username, source_p->host,
+ target_p->name, reason);
+ }
+
+ /*
+ * Be warned, this message must be From %s, or it confuses clients
+ * so dont change it to From: or the case or anything! -- fl -- db
+ */
+ /*
+ * path must contain at least 2 !'s, or bitchx falsely declares it
+ * local --fl
+ */
+ if (HasUMode(source_p, UMODE_OPER)) /* send it normally */
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Received KILL message for %s. From %s Path: %s!%s!%s!%s %s",
+ target_p->name, source_p->name, source_p->servptr->name,
+ source_p->host, source_p->username, source_p->name, reason);
+ else
+ sendto_realops_flags(UMODE_SKILL, L_ALL,
+ "Received KILL message for %s. From %s %s",
+ target_p->name, source_p->name, reason);
+
+ ilog(LOG_TYPE_KILL, "KILL From %s For %s Path %s %s",
+ source_p->name, target_p->name, source_p->name, reason);
+
+ relay_kill(client_p, source_p, target_p, path, reason);
+ AddFlag(target_p, FLAGS_KILLED);
+
+ /* reason comes supplied with its own ()'s */
+ if (IsServer(source_p) && (IsHidden(source_p) || ConfigServerHide.hide_servers))
+ snprintf(buf, sizeof(buf), "Killed (%s %s)", me.name, reason);
+ else
+ snprintf(buf, sizeof(buf), "Killed (%s %s)", source_p->name, reason);
+
+ exit_client(target_p, source_p, buf);
+}
+
+
+static struct Message kill_msgtab = {
+ "KILL", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_not_oper, ms_kill, m_ignore, mo_kill, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&kill_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&kill_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = MODULE_FLAG_CORE
+};
diff --git a/modules/core/m_message.c b/modules/core/m_message.c
new file mode 100644
index 0000000..183154f
--- /dev/null
+++ b/modules/core/m_message.c
@@ -0,0 +1,935 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_message.c: Sends a (PRIVMSG|NOTICE) message to a user or channel.
+ *
+ * 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 "ircd.h"
+#include "numeric.h"
+#include "conf.h"
+#include "s_serv.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+#include "channel.h"
+#include "channel_mode.h"
+#include "irc_string.h"
+#include "hash.h"
+#include "packet.h"
+
+
+struct entity
+{
+ void *ptr;
+ int type;
+ int flags;
+};
+
+static int build_target_list(int p_or_n, const char *command,
+ struct Client *client_p,
+ struct Client *source_p,
+ char *nicks_channels, char *text);
+
+static int flood_attack_client(int p_or_n, struct Client *source_p,
+ struct Client *target_p);
+static int flood_attack_channel(int p_or_n, struct Client *source_p,
+ struct Channel *chptr);
+static struct Client* find_userhost (char *, char *, int *);
+
+#define ENTITY_NONE 0
+#define ENTITY_CHANNEL 1
+#define ENTITY_CHANOPS_ON_CHANNEL 2
+#define ENTITY_CLIENT 3
+
+static struct entity targets[512];
+static int ntargets = 0;
+
+static int duplicate_ptr(void *);
+
+static void m_message(int, const char *, struct Client *,
+ struct Client *, int, char **);
+
+static void msg_channel(int p_or_n, const char *command,
+ struct Client *client_p,
+ struct Client *source_p,
+ struct Channel *chptr, char *text);
+
+static void msg_channel_flags(int p_or_n, const char *command,
+ struct Client *client_p,
+ struct Client *source_p,
+ struct Channel *chptr, int flags, char *text);
+
+static void msg_client(int p_or_n, const char *command,
+ struct Client *source_p, struct Client *target_p,
+ char *text);
+
+static void handle_special(int p_or_n, const char *command,
+ struct Client *client_p,
+ struct Client *source_p, char *nick, char *text);
+
+/*
+** m_privmsg
+**
+** massive cleanup
+** rev argv 6/91
+**
+** Another massive cleanup Nov, 2000
+** (I don't think there is a single line left from 6/91. Maybe.)
+** m_privmsg and m_notice do basically the same thing.
+** in the original 2.8.2 code base, they were the same function
+** "m_message.c." When we did the great cleanup in conjuncton with bleep
+** of ircu fame, we split m_privmsg.c and m_notice.c.
+** I don't see the point of that now. Its harder to maintain, its
+** easier to introduce bugs into one version and not the other etc.
+** Really, the penalty of an extra function call isn't that big a deal folks.
+** -db Nov 13, 2000
+**
+*/
+
+#define PRIVMSG 0
+#define NOTICE 1
+
+static void
+m_privmsg(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ /* servers have no reason to send privmsgs, yet sometimes there is cause
+ * for a notice.. (for example remote kline replies) --fl_
+ */
+ if (!IsClient(source_p))
+ return;
+
+ m_message(PRIVMSG, "PRIVMSG", client_p, source_p, parc, parv);
+}
+
+static void
+m_notice(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ m_message(NOTICE, "NOTICE", client_p, source_p, parc, parv);
+}
+
+/*
+ * inputs - flag privmsg or notice
+ * - pointer to command "PRIVMSG" or "NOTICE"
+ * - pointer to client_p
+ * - pointer to source_p
+ * - pointer to channel
+ */
+static void
+m_message(int p_or_n, const char *command, struct Client *client_p,
+ struct Client *source_p, int parc, char *parv[])
+{
+ int i;
+
+ if (parc < 2 || EmptyString(parv[1]))
+ {
+ if (p_or_n != NOTICE)
+ sendto_one(source_p, form_str(ERR_NORECIPIENT),
+ ID_or_name(&me, client_p),
+ ID_or_name(source_p, client_p), command);
+ return;
+ }
+
+ if (parc < 3 || EmptyString(parv[2]))
+ {
+ if (p_or_n != NOTICE)
+ sendto_one(source_p, form_str(ERR_NOTEXTTOSEND),
+ ID_or_name(&me, client_p),
+ ID_or_name(source_p, client_p));
+ return;
+ }
+
+ /* Finish the flood grace period... */
+ if (MyClient(source_p) && !IsFloodDone(source_p))
+ flood_endgrace(source_p);
+
+ if (build_target_list(p_or_n, command, client_p, source_p, parv[1],
+ parv[2]) < 0)
+ return;
+
+ for (i = 0; i < ntargets; i++)
+ {
+ switch (targets[i].type)
+ {
+ case ENTITY_CHANNEL:
+ msg_channel(p_or_n, command, client_p, source_p,
+ (struct Channel *)targets[i].ptr, parv[2]);
+ break;
+
+ case ENTITY_CHANOPS_ON_CHANNEL:
+ msg_channel_flags(p_or_n, command, client_p, source_p,
+ (struct Channel *)targets[i].ptr,
+ targets[i].flags, parv[2]);
+ break;
+
+ case ENTITY_CLIENT:
+ msg_client(p_or_n, command, source_p,
+ (struct Client *)targets[i].ptr, parv[2]);
+ break;
+ }
+ }
+}
+
+/* build_target_list()
+ *
+ * inputs - pointer to given client_p (server)
+ * - pointer to given source (oper/client etc.)
+ * - pointer to list of nicks/channels
+ * - pointer to table to place results
+ * - pointer to text (only used if source_p is an oper)
+ * output - number of valid entities
+ * side effects - target_table is modified to contain a list of
+ * pointers to channels or clients
+ * if source client is an oper
+ * all the classic old bizzare oper privmsg tricks
+ * are parsed and sent as is, if prefixed with $
+ * to disambiguate.
+ *
+ */
+static int
+build_target_list(int p_or_n, const char *command, struct Client *client_p,
+ struct Client *source_p, char *nicks_channels, char *text)
+{
+ int type;
+ char *p = NULL, *nick, *target_list;
+ struct Channel *chptr = NULL;
+ struct Client *target_p = NULL;
+
+ target_list = nicks_channels;
+
+ ntargets = 0;
+
+ for (nick = strtoken(&p, target_list, ","); nick;
+ nick = strtoken(&p, NULL, ","))
+ {
+ char *with_prefix;
+ /*
+ * channels are privmsg'd a lot more than other clients, moved up
+ * here plain old channel msg?
+ */
+
+ if (IsChanPrefix(*nick))
+ {
+ if ((chptr = hash_find_channel(nick)) != NULL)
+ {
+ if (!duplicate_ptr(chptr))
+ {
+ if (ntargets >= ConfigFileEntry.max_targets)
+ {
+ sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
+ ID_or_name(&me, client_p),
+ ID_or_name(source_p, client_p), nick,
+ ConfigFileEntry.max_targets);
+ return (1);
+ }
+ targets[ntargets].ptr = (void *)chptr;
+ targets[ntargets++].type = ENTITY_CHANNEL;
+ }
+ }
+ else
+ {
+ if (p_or_n != NOTICE)
+ sendto_one(source_p, form_str(ERR_NOSUCHNICK),
+ ID_or_name(&me, client_p),
+ ID_or_name(source_p, client_p), nick);
+ }
+ continue;
+ }
+
+ /* look for a privmsg to another client */
+ if ((target_p = find_person(client_p, nick)) != NULL)
+ {
+ if (!duplicate_ptr(target_p))
+ {
+ if (ntargets >= ConfigFileEntry.max_targets)
+ {
+ sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
+ ID_or_name(&me, client_p),
+ ID_or_name(source_p, client_p), nick,
+ ConfigFileEntry.max_targets);
+ return (1);
+ }
+ targets[ntargets].ptr = (void *)target_p;
+ targets[ntargets].type = ENTITY_CLIENT;
+ targets[ntargets++].flags = 0;
+ }
+ continue;
+ }
+
+ /* @#channel or +#channel message ? */
+
+ type = 0;
+ with_prefix = nick;
+ /* allow %+@ if someone wants to do that */
+ for (; ;)
+ {
+ if (*nick == '@')
+ type |= CHFL_CHANOP;
+#ifdef HALFOPS
+ else if (*nick == '%')
+ type |= CHFL_CHANOP | CHFL_HALFOP;
+#endif
+ else if (*nick == '+')
+ type |= CHFL_CHANOP | CHFL_HALFOP | CHFL_VOICE;
+ else
+ break;
+ nick++;
+ }
+
+ if (type != 0)
+ {
+ /* suggested by Mortiis */
+ if (*nick == '\0') /* if its a '\0' dump it, there is no recipient */
+ {
+ sendto_one(source_p, form_str(ERR_NORECIPIENT),
+ ID_or_name(&me, client_p),
+ ID_or_name(source_p, client_p), command);
+ continue;
+ }
+
+ /* At this point, nick+1 should be a channel name i.e. #foo or &foo
+ * if the channel is found, fine, if not report an error
+ */
+
+ if ((chptr = hash_find_channel(nick)) != NULL)
+ {
+ if (IsClient(source_p) && !HasFlag(source_p, FLAGS_SERVICE))
+ {
+ if (!has_member_flags(find_channel_link(source_p, chptr),
+ CHFL_CHANOP|CHFL_HALFOP|CHFL_VOICE))
+ {
+ sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
+ ID_or_name(&me, client_p),
+ ID_or_name(source_p, client_p), with_prefix);
+ return(-1);
+ }
+ }
+
+ if (!duplicate_ptr(chptr))
+ {
+ if (ntargets >= ConfigFileEntry.max_targets)
+ {
+ sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
+ ID_or_name(&me, client_p),
+ ID_or_name(source_p, client_p), nick,
+ ConfigFileEntry.max_targets);
+ return(1);
+ }
+ targets[ntargets].ptr = (void *)chptr;
+ targets[ntargets].type = ENTITY_CHANOPS_ON_CHANNEL;
+ targets[ntargets++].flags = type;
+ }
+ }
+ else
+ {
+ if (p_or_n != NOTICE)
+ sendto_one(source_p, form_str(ERR_NOSUCHNICK),
+ ID_or_name(&me, client_p),
+ ID_or_name(source_p, client_p), nick);
+ }
+ continue;
+ }
+
+ if ((*nick == '$') || strchr(nick, '@') != NULL)
+ {
+ handle_special(p_or_n, command, client_p, source_p, nick, text);
+ }
+ else
+ {
+ if (p_or_n != NOTICE)
+ {
+ if (!IsDigit(*nick) || MyClient(source_p))
+ sendto_one(source_p, form_str(ERR_NOSUCHNICK),
+ ID_or_name(&me, client_p),
+ ID_or_name(source_p, client_p), nick);
+ }
+ }
+ /* continue; */
+ }
+
+ return(1);
+}
+
+/* duplicate_ptr()
+ *
+ * inputs - pointer to check
+ * - pointer to table of entities
+ * - number of valid entities so far
+ * output - YES if duplicate pointer in table, NO if not.
+ * note, this does the canonize using pointers
+ * side effects - NONE
+ */
+static int
+duplicate_ptr(void *ptr)
+{
+ int i;
+
+ for (i = 0; i < ntargets; i++)
+ {
+ if (targets[i].ptr == ptr)
+ return(1);
+ }
+
+ return(0);
+}
+
+/* msg_channel()
+ *
+ * inputs - flag privmsg or notice
+ * - pointer to command "PRIVMSG" or "NOTICE"
+ * - pointer to client_p
+ * - pointer to source_p
+ * - pointer to channel
+ * output - NONE
+ * side effects - message given channel
+ */
+static void
+msg_channel(int p_or_n, const char *command, struct Client *client_p,
+ struct Client *source_p, struct Channel *chptr, char *text)
+{
+ int result;
+
+ if (MyClient(source_p))
+ {
+ /* idle time shouldnt be reset by notices --fl */
+ if (p_or_n != NOTICE)
+ source_p->localClient->last_privmsg = CurrentTime;
+ }
+
+ /* chanops and voiced can flood their own channel with impunity */
+ if ((result = can_send(chptr, source_p, NULL)) < 0)
+ {
+ if (result == CAN_SEND_OPV ||
+ !flood_attack_channel(p_or_n, source_p, chptr))
+ sendto_channel_butone(client_p, source_p, chptr, 0, "%s %s :%s",
+ command, chptr->chname, text);
+ }
+ else
+ {
+ if (p_or_n != NOTICE)
+ sendto_one(source_p, form_str(ERR_CANNOTSENDTOCHAN),
+ ID_or_name(&me, client_p),
+ ID_or_name(source_p, client_p), chptr->chname);
+ }
+}
+
+/* msg_channel_flags()
+ *
+ * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
+ * say NOTICE must not auto reply
+ * - pointer to command, "PRIVMSG" or "NOTICE"
+ * - pointer to client_p
+ * - pointer to source_p
+ * - pointer to channel
+ * - flags
+ * - pointer to text to send
+ * output - NONE
+ * side effects - message given channel either chanop or voice
+ */
+static void
+msg_channel_flags(int p_or_n, const char *command, struct Client *client_p,
+ struct Client *source_p, struct Channel *chptr,
+ int flags, char *text)
+{
+ unsigned int type;
+ char c;
+
+ if (flags & CHFL_VOICE)
+ {
+ type = CHFL_VOICE|CHFL_HALFOP|CHFL_CHANOP;
+ c = '+';
+ }
+#ifdef HALFOPS
+ else if (flags & CHFL_HALFOP)
+ {
+ type = CHFL_HALFOP|CHFL_CHANOP;
+ c = '%';
+ }
+#endif
+ else
+ {
+ type = CHFL_CHANOP;
+ c = '@';
+ }
+
+ if (MyClient(source_p) && p_or_n != NOTICE)
+ source_p->localClient->last_privmsg = CurrentTime;
+
+ sendto_channel_butone(client_p, source_p, chptr, type, "%s %c%s :%s",
+ command, c, chptr->chname, text);
+}
+
+/* msg_client()
+ *
+ * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
+ * say NOTICE must not auto reply
+ * - pointer to command, "PRIVMSG" or "NOTICE"
+ * - pointer to source_p source (struct Client *)
+ * - pointer to target_p target (struct Client *)
+ * - pointer to text
+ * output - NONE
+ * side effects - message given channel either chanop or voice
+ */
+static void
+msg_client(int p_or_n, const char *command, struct Client *source_p,
+ struct Client *target_p, char *text)
+{
+ if (MyConnect(source_p))
+ {
+ /*
+ * reset idle time for message only if it's not a notice
+ */
+ if ((p_or_n != NOTICE))
+ source_p->localClient->last_privmsg = CurrentTime;
+
+ if ((p_or_n != NOTICE) && target_p->away[0])
+ sendto_one(source_p, form_str(RPL_AWAY), me.name,
+ source_p->name, target_p->name, target_p->away);
+
+ if (HasUMode(target_p, UMODE_REGONLY) && target_p != source_p)
+ {
+ if (!HasUMode(source_p, UMODE_REGISTERED|UMODE_OPER))
+ {
+ if (p_or_n != NOTICE)
+ sendto_one(source_p, form_str(ERR_NONONREG), me.name, source_p->name,
+ target_p->name);
+ return;
+ }
+ }
+ }
+
+ if (MyClient(target_p))
+ {
+ if (!IsServer(source_p) && HasUMode(target_p, UMODE_CALLERID|UMODE_SOFTCALLERID))
+ {
+ /* Here is the anti-flood bot/spambot code -db */
+ if (accept_message(source_p, target_p) || HasFlag(source_p, FLAGS_SERVICE) ||
+ (HasUMode(source_p, UMODE_OPER) && (ConfigFileEntry.opers_bypass_callerid == 1)))
+ {
+ sendto_one(target_p, ":%s!%s@%s %s %s :%s",
+ source_p->name, source_p->username,
+ source_p->host, command, target_p->name, text);
+ }
+ else
+ {
+ /* check for accept, flag recipient incoming message */
+ if (p_or_n != NOTICE)
+ sendto_one(source_p, form_str(RPL_TARGUMODEG),
+ ID_or_name(&me, source_p->from),
+ ID_or_name(source_p, source_p->from), target_p->name);
+
+ if ((target_p->localClient->last_caller_id_time +
+ ConfigFileEntry.caller_id_wait) < CurrentTime)
+ {
+ if (p_or_n != NOTICE)
+ sendto_one(source_p, form_str(RPL_TARGNOTIFY),
+ ID_or_name(&me, source_p->from),
+ ID_or_name(source_p, source_p->from), target_p->name);
+
+ sendto_one(target_p, form_str(RPL_UMODEGMSG),
+ me.name, target_p->name,
+ get_client_name(source_p, HIDE_IP));
+
+ target_p->localClient->last_caller_id_time = CurrentTime;
+
+ }
+ /* Only so opers can watch for floods */
+ flood_attack_client(p_or_n, source_p, target_p);
+ }
+ }
+ else
+ {
+ /* If the client is remote, we dont perform a special check for
+ * flooding.. as we wouldnt block their message anyway.. this means
+ * we dont give warnings.. we then check if theyre opered
+ * (to avoid flood warnings), lastly if theyre our client
+ * and flooding -- fl */
+ if (!MyClient(source_p) || HasUMode(source_p, UMODE_OPER) ||
+ (MyClient(source_p) &&
+ !flood_attack_client(p_or_n, source_p, target_p)))
+ sendto_anywhere(target_p, source_p, "%s %s :%s",
+ command, target_p->name, text);
+ }
+ }
+ else
+ /* The target is a remote user.. same things apply -- fl */
+ if (!MyClient(source_p) || HasUMode(source_p, UMODE_OPER) ||
+ (MyClient(source_p)
+ && !flood_attack_client(p_or_n, source_p, target_p)))
+ sendto_anywhere(target_p, source_p, "%s %s :%s", command, target_p->name,
+ text);
+}
+
+/* flood_attack_client()
+ *
+ * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
+ * say NOTICE must not auto reply
+ * - pointer to source Client
+ * - pointer to target Client
+ * output - 1 if target is under flood attack
+ * side effects - check for flood attack on target target_p
+ */
+static int
+flood_attack_client(int p_or_n, struct Client *source_p,
+ struct Client *target_p)
+{
+ int delta;
+
+ if (GlobalSetOptions.floodcount && MyConnect(target_p)
+ && IsClient(source_p) && !IsConfCanFlood(source_p))
+ {
+ if ((target_p->localClient->first_received_message_time + 1)
+ < CurrentTime)
+ {
+ delta =
+ CurrentTime - target_p->localClient->first_received_message_time;
+ target_p->localClient->received_number_of_privmsgs -= delta;
+ target_p->localClient->first_received_message_time = CurrentTime;
+
+ if (target_p->localClient->received_number_of_privmsgs <= 0)
+ {
+ target_p->localClient->received_number_of_privmsgs = 0;
+ DelFlag(target_p, FLAGS_FLOOD_NOTICED);
+ }
+ }
+
+ if ((target_p->localClient->received_number_of_privmsgs >=
+ GlobalSetOptions.floodcount) || HasFlag(target_p, FLAGS_FLOOD_NOTICED))
+ {
+ if (!HasFlag(target_p, FLAGS_FLOOD_NOTICED))
+ {
+ sendto_realops_flags(UMODE_BOTS, L_ALL,
+ "Possible Flooder %s on %s target: %s",
+ get_client_name(source_p, HIDE_IP),
+ source_p->servptr->name, target_p->name);
+ AddFlag(target_p, FLAGS_FLOOD_NOTICED);
+ /* add a bit of penalty */
+ target_p->localClient->received_number_of_privmsgs += 2;
+ }
+
+ if (MyClient(source_p) && (p_or_n != NOTICE))
+ sendto_one(source_p,
+ ":%s NOTICE %s :*** Message to %s throttled due to flooding",
+ me.name, source_p->name, target_p->name);
+ return(1);
+ }
+ else
+ target_p->localClient->received_number_of_privmsgs++;
+ }
+
+ return(0);
+}
+
+/* flood_attack_channel()
+ *
+ * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
+ * says NOTICE must not auto reply
+ * - pointer to source Client
+ * - pointer to target channel
+ * output - 1 if target is under flood attack
+ * side effects - check for flood attack on target chptr
+ */
+static int
+flood_attack_channel(int p_or_n, struct Client *source_p,
+ struct Channel *chptr)
+{
+ int delta;
+
+ if (GlobalSetOptions.floodcount && !IsConfCanFlood(source_p))
+ {
+ if ((chptr->first_received_message_time + 1) < CurrentTime)
+ {
+ delta = CurrentTime - chptr->first_received_message_time;
+ chptr->received_number_of_privmsgs -= delta;
+ chptr->first_received_message_time = CurrentTime;
+ if (chptr->received_number_of_privmsgs <= 0)
+ {
+ chptr->received_number_of_privmsgs = 0;
+ ClearFloodNoticed(chptr);
+ }
+ }
+
+ if ((chptr->received_number_of_privmsgs >= GlobalSetOptions.floodcount)
+ || IsSetFloodNoticed(chptr))
+ {
+ if (!IsSetFloodNoticed(chptr))
+ {
+ sendto_realops_flags(UMODE_BOTS, L_ALL,
+ "Possible Flooder %s on %s target: %s",
+ get_client_name(source_p, HIDE_IP),
+ source_p->servptr->name, chptr->chname);
+ SetFloodNoticed(chptr);
+
+ /* Add a bit of penalty */
+ chptr->received_number_of_privmsgs += 2;
+ }
+ if (MyClient(source_p) && (p_or_n != NOTICE))
+ sendto_one(source_p,
+ ":%s NOTICE %s :*** Message to %s throttled due to flooding",
+ me.name, source_p->name, chptr->chname);
+ return(1);
+ }
+ else
+ chptr->received_number_of_privmsgs++;
+ }
+
+ return(0);
+}
+
+/* handle_special()
+ *
+ * inputs - server pointer
+ * - client pointer
+ * - nick stuff to grok for opers
+ * - text to send if grok
+ * output - none
+ * side effects - old style username@server is handled here for non opers
+ * opers are allowed username%hostname@server
+ * all the traditional oper type messages are also parsed here.
+ * i.e. "/msg #some.host."
+ * However, syntax has been changed.
+ * previous syntax "/msg #some.host.mask"
+ * now becomes "/msg $#some.host.mask"
+ * previous syntax of: "/msg $some.server.mask" remains
+ * This disambiguates the syntax.
+ *
+ * XXX N.B. dalnet changed it to nick@server as have other servers.
+ * we will stick with tradition for now.
+ * - Dianora
+ */
+static void
+handle_special(int p_or_n, const char *command, struct Client *client_p,
+ struct Client *source_p, char *nick, char *text)
+{
+ struct Client *target_p;
+ char *host;
+ char *server;
+ char *s;
+ int count;
+
+ /*
+ * user[%host]@server addressed?
+ */
+ if ((server = strchr(nick, '@')) != NULL)
+ {
+ count = 0;
+
+ if ((host = strchr(nick, '%')) && !HasUMode(source_p, UMODE_OPER))
+ {
+ sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
+ ID_or_name(&me, client_p),
+ ID_or_name(source_p, client_p));
+ return;
+ }
+
+ if ((target_p = hash_find_server(server + 1)) != NULL)
+ {
+ if (!IsMe(target_p))
+ {
+ /*
+ * Not destined for a user on me :-(
+ */
+ sendto_one(target_p, ":%s %s %s :%s",
+ ID_or_name(source_p, target_p->from),
+ command, nick, text);
+ if ((p_or_n != NOTICE) && MyClient(source_p))
+ source_p->localClient->last_privmsg = CurrentTime;
+ return;
+ }
+
+ *server = '\0';
+
+ if (host != NULL)
+ *host++ = '\0';
+
+ /*
+ * Look for users which match the destination host
+ * (no host == wildcard) and if one and one only is
+ * found connected to me, deliver message!
+ */
+ target_p = find_userhost(nick, host, &count);
+
+ if (target_p != NULL)
+ {
+ if (server != NULL)
+ *server = '@';
+ if (host != NULL)
+ *--host = '%';
+
+ if (count == 1)
+ {
+ sendto_one(target_p, ":%s!%s@%s %s %s :%s",
+ source_p->name, source_p->username, source_p->host,
+ command, nick, text);
+ if ((p_or_n != NOTICE) && MyClient(source_p))
+ source_p->localClient->last_privmsg = CurrentTime;
+ }
+ else
+ sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
+ ID_or_name(&me, client_p),
+ ID_or_name(source_p, client_p), nick,
+ ConfigFileEntry.max_targets);
+ }
+ }
+ else if (server && *(server+1) && (target_p == NULL))
+ sendto_one(source_p, form_str(ERR_NOSUCHSERVER),
+ ID_or_name(&me, client_p),
+ ID_or_name(source_p, client_p), server+1);
+ else if (server && (target_p == NULL))
+ sendto_one(source_p, form_str(ERR_NOSUCHNICK),
+ ID_or_name(&me, client_p),
+ ID_or_name(source_p, client_p), nick);
+ return;
+ }
+
+ if (!HasUMode(source_p, UMODE_OPER))
+ {
+ sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
+ ID_or_name(&me, client_p),
+ ID_or_name(source_p, client_p));
+ return;
+ }
+
+ /*
+ * the following two cases allow masks in NOTICEs
+ * (for OPERs only)
+ *
+ * Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
+ */
+ if (*nick == '$')
+ {
+ if ((*(nick+1) == '$' || *(nick+1) == '#'))
+ nick++;
+ else if (MyClient(source_p) && HasUMode(source_p, UMODE_OPER))
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :The command %s %s is no longer supported, please use $%s",
+ me.name, source_p->name, command, nick, nick);
+ return;
+ }
+
+ if ((s = strrchr(nick, '.')) == NULL)
+ {
+ sendto_one(source_p, form_str(ERR_NOTOPLEVEL),
+ me.name, source_p->name, nick);
+ return;
+ }
+
+ while (*++s)
+ if (*s == '.' || *s == '*' || *s == '?')
+ break;
+
+ if (*s == '*' || *s == '?')
+ {
+ sendto_one(source_p, form_str(ERR_WILDTOPLEVEL),
+ ID_or_name(&me, client_p),
+ ID_or_name(source_p, client_p), nick);
+ return;
+ }
+
+ sendto_match_butone(IsServer(client_p) ? client_p : NULL, source_p,
+ nick + 1, (*nick == '#') ? MATCH_HOST : MATCH_SERVER,
+ "%s $%s :%s", command, nick, text);
+
+ if ((p_or_n != NOTICE) && MyClient(source_p))
+ source_p->localClient->last_privmsg = CurrentTime;
+
+ return;
+ }
+}
+
+/*
+ * find_userhost - find a user@host (server or user).
+ * inputs - user name to look for
+ * - host name to look for
+ * - pointer to count of number of matches found
+ * outputs - pointer to client if found
+ * - count is updated
+ * side effects - none
+ *
+ */
+static struct Client *
+find_userhost(char *user, char *host, int *count)
+{
+ struct Client *c2ptr;
+ struct Client *res = NULL;
+ dlink_node *lc2ptr;
+
+ *count = 0;
+
+ if (collapse(user) != NULL)
+ {
+ DLINK_FOREACH(lc2ptr, local_client_list.head)
+ {
+ c2ptr = lc2ptr->data;
+
+ if (!IsClient(c2ptr)) /* something other than a client */
+ continue;
+
+ if ((!host || match(host, c2ptr->host)) &&
+ irccmp(user, c2ptr->username) == 0)
+ {
+ (*count)++;
+ res = c2ptr;
+ }
+ }
+ }
+
+ return(res);
+}
+
+static struct Message privmsg_msgtab = {
+ "PRIVMSG", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_privmsg, m_privmsg, m_ignore, m_privmsg, m_ignore}
+};
+
+static struct Message notice_msgtab = {
+ "NOTICE", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_notice, m_notice, m_ignore, m_notice, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&privmsg_msgtab);
+ mod_add_cmd(&notice_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&privmsg_msgtab);
+ mod_del_cmd(&notice_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = MODULE_FLAG_CORE
+};
diff --git a/modules/core/m_mode.c b/modules/core/m_mode.c
new file mode 100644
index 0000000..fa68b22
--- /dev/null
+++ b/modules/core/m_mode.c
@@ -0,0 +1,313 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_mode.c: Sets a user or channel mode.
+ *
+ * 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 "channel.h"
+#include "channel_mode.h"
+#include "client.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_user.h"
+#include "conf.h"
+#include "s_serv.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+#include "packet.h"
+
+
+/*
+ * m_mode - MODE command handler
+ * parv[0] - sender
+ * parv[1] - channel
+ */
+static void
+m_mode(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Channel *chptr = NULL;
+ struct Membership *member;
+ static char modebuf[MODEBUFLEN];
+ static char parabuf[MODEBUFLEN];
+
+ if (EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, "MODE");
+ return;
+ }
+
+ /* Now, try to find the channel in question */
+ if (!IsChanPrefix(*parv[1]))
+ {
+ /* if here, it has to be a non-channel name */
+ set_user_mode(client_p, source_p, parc, parv);
+ return;
+ }
+
+ if ((chptr = hash_find_channel(parv[1])) == NULL)
+ {
+ sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
+ ID_or_name(&me, source_p->from),
+ ID_or_name(source_p, source_p->from),
+ parv[1]);
+ return;
+ }
+
+ /* Now known the channel exists */
+ if (parc < 3)
+ {
+ channel_modes(chptr, source_p, modebuf, parabuf);
+ sendto_one(source_p, form_str(RPL_CHANNELMODEIS),
+ me.name, source_p->name, chptr->chname, modebuf, parabuf);
+ sendto_one(source_p, form_str(RPL_CREATIONTIME),
+ me.name, source_p->name, chptr->chname, chptr->channelts);
+ }
+ /* bounce all modes from people we deop on sjoin
+ * servers have always gotten away with murder,
+ * including telnet servers *g* - Dianora
+ *
+ * XXX Is it worth the bother to make an ms_mode() ? - Dianora
+ */
+ else if (IsServer(source_p))
+ {
+ set_channel_mode(client_p, source_p, chptr, NULL, parc - 2, parv + 2,
+ chptr->chname);
+ }
+ else
+ {
+ member = find_channel_link(source_p, chptr);
+
+ if (!has_member_flags(member, CHFL_DEOPPED))
+ {
+ /* Finish the flood grace period... */
+ if (MyClient(source_p) && !IsFloodDone(source_p))
+ {
+ if (!((parc == 3) && (parv[2][0] == 'b') && (parv[2][1] == '\0')))
+ flood_endgrace(source_p);
+ }
+
+ set_channel_mode(client_p, source_p, chptr, member, parc - 2, parv + 2,
+ chptr->chname);
+ }
+ }
+}
+
+/*
+ * ms_tmode()
+ *
+ * inputs - parv[0] = UID
+ * parv[1] = TS
+ * parv[2] = channel name
+ * parv[3] = modestring
+ */
+static void
+ms_tmode(struct Client *client_p, struct Client *source_p, int parc, char *parv[])
+{
+ struct Channel *chptr = NULL;
+ struct Membership *member = NULL;
+
+ if ((chptr = hash_find_channel(parv[2])) == NULL)
+ {
+ sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
+ ID_or_name(&me, client_p), ID_or_name(source_p, client_p), parv[2]);
+ return;
+ }
+
+ if (atol(parv[1]) > chptr->channelts)
+ return;
+
+ if (IsServer(source_p))
+ set_channel_mode(client_p, source_p, chptr, NULL, parc - 3, parv + 3, chptr->chname);
+ else
+ {
+ member = find_channel_link(source_p, chptr);
+
+ /* XXX are we sure we just want to bail here? */
+ if (has_member_flags(member, CHFL_DEOPPED))
+ return;
+
+ set_channel_mode(client_p, source_p, chptr, member, parc - 3, parv + 3, chptr->chname);
+ }
+}
+
+/*
+ * ms_bmask()
+ *
+ * inputs - parv[0] = SID
+ * parv[1] = TS
+ * parv[2] = channel name
+ * parv[3] = type of ban to add ('b' 'I' or 'e')
+ * parv[4] = space delimited list of masks to add
+ * outputs - none
+ * side effects - propagates unchanged bmask line to CAP_TS6 servers,
+ * sends plain modes to the others. nothing is sent
+ * to the server the issuing server is connected through
+ */
+static void
+ms_bmask(struct Client *client_p, struct Client *source_p, int parc, char *parv[])
+{
+ static char modebuf[IRCD_BUFSIZE];
+ static char parabuf[IRCD_BUFSIZE];
+ static char banbuf[IRCD_BUFSIZE];
+ struct Channel *chptr;
+ char *s, *t, *mbuf, *pbuf;
+ long mode_type;
+ int mlen, tlen;
+ int modecount = 0;
+ int needcap = NOCAPS;
+
+ if ((chptr = hash_find_channel(parv[2])) == NULL)
+ return;
+
+ /* TS is higher, drop it. */
+ if (atol(parv[1]) > chptr->channelts)
+ return;
+
+ switch (*parv[3])
+ {
+ case 'b':
+ mode_type = CHFL_BAN;
+ break;
+
+ case 'e':
+ mode_type = CHFL_EXCEPTION;
+ needcap = CAP_EX;
+ break;
+
+ case 'I':
+ mode_type = CHFL_INVEX;
+ needcap = CAP_IE;
+ break;
+
+ /* maybe we should just blindly propagate this? */
+ default:
+ return;
+ }
+
+ parabuf[0] = '\0';
+ s = banbuf;
+ strlcpy(s, parv[4], sizeof(banbuf));
+
+ /* only need to construct one buffer, for non-ts6 servers */
+ mlen = ircsprintf(modebuf, ":%s MODE %s +",
+ source_p->name, chptr->chname);
+ mbuf = modebuf + mlen;
+ pbuf = parabuf;
+
+ do {
+ if ((t = strchr(s, ' ')) != NULL)
+ *t++ = '\0';
+ tlen = strlen(s);
+
+ /* I dont even want to begin parsing this.. */
+ if (tlen > MODEBUFLEN)
+ break;
+
+ if (tlen && *s != ':' && add_id(source_p, chptr, s, mode_type))
+ {
+ /* this new one wont fit.. */
+ if (mbuf - modebuf + 2 + pbuf - parabuf + tlen > IRCD_BUFSIZE - 2 ||
+ modecount >= MAXMODEPARAMS)
+ {
+ *mbuf = '\0';
+ *(pbuf - 1) = '\0';
+
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, "%s %s",
+ modebuf, parabuf);
+ sendto_server(client_p, needcap, CAP_TS6,
+ "%s %s", modebuf, parabuf);
+
+ mbuf = modebuf + mlen;
+ pbuf = parabuf;
+ modecount = 0;
+ }
+
+ *mbuf++ = parv[3][0];
+ pbuf += ircsprintf(pbuf, "%s ", s);
+ modecount++;
+ }
+
+ s = t;
+ } while (s != NULL);
+
+ if (modecount)
+ {
+ *mbuf = *(pbuf - 1) = '\0';
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, "%s %s", modebuf, parabuf);
+ sendto_server(client_p, needcap, CAP_TS6,
+ "%s %s", modebuf, parabuf);
+ }
+
+ /* assumption here is that since the server sent BMASK, they are TS6, so they have an ID */
+ sendto_server(client_p, CAP_TS6|needcap, NOCAPS,
+ ":%s BMASK %lu %s %s :%s",
+ source_p->id, (unsigned long)chptr->channelts, chptr->chname,
+ parv[3], parv[4]);
+}
+
+static struct Message mode_msgtab = {
+ "MODE", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_mode, m_mode, m_ignore, m_mode, m_ignore}
+};
+
+static struct Message tmode_msgtab = {
+ "TMODE", 0, 0, 4, MAXPARA, MFLG_SLOW, 0,
+ {m_ignore, m_ignore, ms_tmode, m_ignore, m_ignore, m_ignore}
+};
+
+static struct Message bmask_msgtab = {
+ "BMASK", 0, 0, 5, MAXPARA, MFLG_SLOW, 0,
+ {m_ignore, m_ignore, ms_bmask, m_ignore, m_ignore, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&mode_msgtab);
+ mod_add_cmd(&tmode_msgtab);
+ mod_add_cmd(&bmask_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&mode_msgtab);
+ mod_del_cmd(&tmode_msgtab);
+ mod_del_cmd(&bmask_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = MODULE_FLAG_CORE
+};
diff --git a/modules/core/m_nick.c b/modules/core/m_nick.c
new file mode 100644
index 0000000..68f4e57
--- /dev/null
+++ b/modules/core/m_nick.c
@@ -0,0 +1,1004 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_nick.c: Sets a users nick.
+ *
+ * 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 "hash.h"
+#include "fdlist.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "conf.h"
+#include "s_user.h"
+#include "whowas.h"
+#include "s_serv.h"
+#include "send.h"
+#include "channel.h"
+#include "channel_mode.h"
+#include "log.h"
+#include "resv.h"
+#include "parse.h"
+#include "modules.h"
+#include "packet.h"
+#include "watch.h"
+
+
+static void nick_from_server(struct Client *, struct Client *, int, char **,
+ time_t, const char *, char *, char *);
+static void uid_from_server(struct Client *, struct Client *, int, char **,
+ time_t, const char *, char *, char *);
+static int check_clean_nick(struct Client *client_p, struct Client *source_p,
+ char *nick, struct Client *server_p);
+static int check_clean_user(struct Client *client_p, char *nick, char *user,
+ struct Client *server_p);
+static int check_clean_host(struct Client *client_p, char *nick, char *host,
+ struct Client *server_p);
+
+static int clean_user_name(const char *);
+static int clean_host_name(const char *);
+static void perform_nick_collides(struct Client *, struct Client *, struct Client *,
+ int, char **, time_t, const char *, char *, char *, char *);
+
+
+/* set_initial_nick()
+ *
+ * inputs
+ * output
+ * side effects -
+ *
+ * This function is only called to set up an initially registering
+ * client.
+ */
+static void
+set_initial_nick(struct Client *source_p, const char *nick)
+{
+ /* Client setting NICK the first time */
+
+ /* This had to be copied here to avoid problems.. */
+ source_p->tsinfo = CurrentTime;
+ source_p->localClient->registration &= ~REG_NEED_NICK;
+
+ if (source_p->name[0])
+ hash_del_client(source_p);
+
+ strlcpy(source_p->name, nick, sizeof(source_p->name));
+ hash_add_client(source_p);
+
+ /* fd_desc is long enough */
+ fd_note(&source_p->localClient->fd, "Nick: %s", nick);
+
+ if (!source_p->localClient->registration)
+ register_local_user(source_p);
+}
+
+/* change_local_nick()
+ *
+ * inputs - pointer to server
+ * - pointer to client
+ * - nick
+ * output -
+ * side effects - changes nick of a LOCAL user
+ */
+static void
+change_local_nick(struct Client *source_p, const char *nick)
+{
+ assert(source_p->name[0] && !EmptyString(nick));
+ assert(MyConnect(source_p));
+
+ /*
+ * Client just changing his/her nick. If he/she is
+ * on a channel, send note of change to all clients
+ * on that channel. Propagate notice to other servers.
+ */
+ if ((source_p->localClient->last_nick_change +
+ ConfigFileEntry.max_nick_time) < CurrentTime)
+ source_p->localClient->number_of_nick_changes = 0;
+ source_p->localClient->last_nick_change = CurrentTime;
+ source_p->localClient->number_of_nick_changes++;
+
+ if ((ConfigFileEntry.anti_nick_flood &&
+ (source_p->localClient->number_of_nick_changes
+ <= ConfigFileEntry.max_nick_changes)) ||
+ !ConfigFileEntry.anti_nick_flood ||
+ (HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.no_oper_flood))
+ {
+ int samenick = !irccmp(source_p->name, nick);
+
+ if (!samenick)
+ {
+ source_p->tsinfo = CurrentTime;
+ clear_ban_cache_client(source_p);
+ watch_check_hash(source_p, RPL_LOGOFF);
+
+ if (HasUMode(source_p, UMODE_REGISTERED))
+ {
+ unsigned int oldmodes = source_p->umodes;
+ char modebuf[IRCD_BUFSIZE] = { '\0' };
+
+ DelUMode(source_p, UMODE_REGISTERED);
+ send_umode(source_p, source_p, oldmodes, 0xffffffff, modebuf);
+ }
+ }
+
+ /* XXX - the format of this notice should eventually be changed
+ * to either %s[%s@%s], or even better would be get_client_name() -bill
+ */
+ sendto_realops_flags(UMODE_NCHANGE, L_ALL, "Nick change: From %s to %s [%s@%s]",
+ source_p->name, nick, source_p->username, source_p->host);
+ sendto_common_channels_local(source_p, 1, ":%s!%s@%s NICK :%s",
+ source_p->name, source_p->username,
+ source_p->host, nick);
+ add_history(source_p, 1);
+
+ sendto_server(source_p, CAP_TS6, NOCAPS,
+ ":%s NICK %s :%lu",
+ ID(source_p), nick, (unsigned long)source_p->tsinfo);
+ sendto_server(source_p, NOCAPS, CAP_TS6,
+ ":%s NICK %s :%lu",
+ source_p->name, nick, (unsigned long)source_p->tsinfo);
+
+ hash_del_client(source_p);
+ strcpy(source_p->name, nick);
+ hash_add_client(source_p);
+
+ if (!samenick)
+ watch_check_hash(source_p, RPL_LOGON);
+
+ /* fd_desc is long enough */
+ fd_note(&source_p->localClient->fd, "Nick: %s", nick);
+ }
+ else
+ sendto_one(source_p, form_str(ERR_NICKTOOFAST),
+ me.name, source_p->name, source_p->name,
+ nick, ConfigFileEntry.max_nick_time);
+}
+
+/*! \brief NICK command handler (called by unregistered,
+ * locally connected clients)
+ *
+ * \param client_p Pointer to allocated Client struct with physical connection
+ * to this server, i.e. with an open socket connected.
+ * \param source_p Pointer to allocated Client struct from which the message
+ * originally comes from. This can be a local or remote client.
+ * \param parc Integer holding the number of supplied arguments.
+ * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
+ * pointers.
+ * \note Valid arguments for this command are:
+ * - parv[0] = sender prefix
+ * - parv[1] = nickname
+ */
+static void
+mr_nick(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *target_p = NULL;
+ char nick[NICKLEN + 1];
+ char *s = NULL;
+
+ if (parc < 2 || EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN), me.name,
+ source_p->name[0] ? source_p->name : "*");
+ return;
+ }
+
+ /* Terminate the nick at the first ~ */
+ if ((s = strchr(parv[1], '~')) != NULL)
+ *s = '\0';
+
+ /* copy the nick and terminate it */
+ strlcpy(nick, parv[1], sizeof(nick));
+
+ /* check the nickname is ok */
+ if (!valid_nickname(nick, 1))
+ {
+ sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME), me.name,
+ source_p->name[0] ? source_p->name : "*", parv[1]);
+ return;
+ }
+
+ /* check if the nick is resv'd */
+ if (find_matching_name_conf(NRESV_TYPE, nick, NULL, NULL, 0) &&
+ !IsExemptResv(source_p))
+ {
+ sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME), me.name,
+ source_p->name[0] ? source_p->name : "*", nick);
+ sendto_realops_flags(L_ALL, UMODE_REJ,
+ "Forbidding reserved nick [%s] from user %s",
+ nick, get_client_name(client_p, HIDE_IP));
+ return;
+ }
+
+ if ((target_p = hash_find_client(nick)) == NULL)
+ set_initial_nick(source_p, nick);
+ else if (source_p == target_p)
+ strlcpy(source_p->name, nick, sizeof(source_p->name));
+ else
+ sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name, "*", nick);
+}
+
+
+/*! \brief NICK command handler (called by already registered,
+ * locally connected clients)
+ *
+ * \param client_p Pointer to allocated Client struct with physical connection
+ * to this server, i.e. with an open socket connected.
+ * \param source_p Pointer to allocated Client struct from which the message
+ * originally comes from. This can be a local or remote client.
+ * \param parc Integer holding the number of supplied arguments.
+ * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
+ * pointers.
+ * \note Valid arguments for this command are:
+ * - parv[0] = sender prefix
+ * - parv[1] = nickname
+ */
+static void
+m_nick(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ char nick[NICKLEN + 1];
+ struct Client *target_p = NULL;
+
+ assert(source_p == client_p);
+
+ if (parc < 2 || EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN),
+ me.name, source_p->name);
+ return;
+ }
+
+ /* mark end of grace period, to prevent nickflooding */
+ if (!IsFloodDone(source_p))
+ flood_endgrace(source_p);
+
+ /* terminate nick to NICKLEN */
+ strlcpy(nick, parv[1], sizeof(nick));
+
+ /* check the nickname is ok */
+ if (!valid_nickname(nick, 1))
+ {
+ sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME),
+ me.name, source_p->name, nick);
+ return;
+ }
+
+ if (find_matching_name_conf(NRESV_TYPE, nick,
+ NULL, NULL, 0) && !IsExemptResv(source_p) &&
+ !(HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.oper_pass_resv))
+ {
+ sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME),
+ me.name, source_p->name, nick);
+ sendto_realops_flags(L_ALL, UMODE_REJ,
+ "Forbidding reserved nick [%s] from user %s",
+ nick, get_client_name(client_p, HIDE_IP));
+ return;
+ }
+
+ if ((target_p = hash_find_client(nick)) == NULL)
+ change_local_nick(source_p, nick);
+ else if (target_p == source_p)
+ {
+ /*
+ * If (target_p == source_p) the client is changing nicks between
+ * equivalent nicknames ie: [nick] -> {nick}
+ */
+
+ /* check the nick isnt exactly the same */
+ if (strcmp(target_p->name, nick))
+ change_local_nick(source_p, nick);
+ }
+ else if (IsUnknown(target_p))
+ {
+ /*
+ * if the client that has the nick isn't registered yet (nick but no
+ * user) then drop the unregged client
+ */
+ exit_client(target_p, &me, "Overridden");
+ change_local_nick(source_p, nick);
+ }
+ else
+ sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name,
+ source_p->name, nick);
+}
+
+
+/*! \brief NICK command handler (called by servers and remotely
+ * connected clients)
+ *
+ * \param client_p Pointer to allocated Client struct with physical connection
+ * to this server, i.e. with an open socket connected.
+ * \param source_p Pointer to allocated Client struct from which the message
+ * originally comes from. This can be a local or remote client.
+ * \param parc Integer holding the number of supplied arguments.
+ * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
+ * pointers.
+ * \note Valid arguments for this command are:
+ *
+ * server -> server nick change
+ * - parv[0] = sender prefix
+ * - parv[1] = nickname
+ * - parv[2] = TS when nick change
+ *
+ * server introducing new nick (without services support)
+ * - parv[0] = sender prefix
+ * - parv[1] = nickname
+ * - parv[2] = hop count
+ * - parv[3] = TS
+ * - parv[4] = umode
+ * - parv[5] = username
+ * - parv[6] = hostname
+ * - parv[7] = server
+ * - parv[8] = ircname
+ *
+ * server introducing new nick (with services support)
+ * - parv[0] = sender prefix
+ * - parv[1] = nickname
+ * - parv[2] = hop count
+ * - parv[3] = TS
+ * - parv[4] = umode
+ * - parv[5] = username
+ * - parv[6] = hostname
+ * - parv[7] = server
+ * - parv[8] = services id (timestamp)
+ * - parv[9] = ircname
+ */
+static void
+ms_nick(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *target_p = NULL;
+ time_t newts = 0;
+ const char *svsid = "0";
+
+ if (parc < 3 || EmptyString(parv[parc - 1]))
+ return;
+
+ if (parc >= 9)
+ {
+ struct Client *server_p = hash_find_server(parv[7]);
+
+ if (server_p == NULL)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Invalid server %s from %s for NICK %s",
+ parv[7], source_p->name, parv[1]);
+ sendto_one(client_p, ":%s KILL %s :%s (Server doesn't exist!)",
+ me.name, parv[1], me.name);
+ return;
+ }
+
+ if (check_clean_nick(client_p, source_p, parv[1], server_p) ||
+ check_clean_user(client_p, parv[1], parv[5], server_p) ||
+ check_clean_host(client_p, parv[1], parv[6], server_p))
+ return;
+
+ if (IsServer(source_p))
+ newts = atol(parv[3]);
+ if (IsServer(source_p) && parc == 10)
+ svsid = parv[8];
+ }
+ else if (parc == 3)
+ {
+ if (IsServer(source_p))
+ /* Servers can't change nicks.. */
+ return;
+
+ if (check_clean_nick(client_p, source_p, parv[1],
+ source_p->servptr))
+ return;
+
+ newts = atol(parv[2]);
+ }
+
+ /* if the nick doesnt exist, allow it and process like normal */
+ if ((target_p = hash_find_client(parv[1])) == NULL)
+ nick_from_server(client_p, source_p, parc, parv, newts, svsid, parv[1], parv[parc-1]);
+ else if (IsUnknown(target_p))
+ {
+ /* we're not living in the past anymore, an unknown client is local only. */
+ exit_client(target_p, &me, "Overridden");
+ nick_from_server(client_p, source_p, parc, parv, newts, svsid, parv[1], parv[parc-1]);
+ }
+ else if (target_p == source_p)
+ {
+ if (strcmp(target_p->name, parv[1]))
+ nick_from_server(client_p, source_p, parc, parv, newts, svsid, parv[1], parv[parc-1]);
+ }
+ else
+ perform_nick_collides(source_p, client_p, target_p, parc, parv,
+ newts, svsid, parv[1], parv[parc-1], NULL);
+}
+
+
+/*! \brief UID command handler (called by servers)
+ *
+ * \param client_p Pointer to allocated Client struct with physical connection
+ * to this server, i.e. with an open socket connected.
+ * \param source_p Pointer to allocated Client struct from which the message
+ * originally comes from. This can be a local or remote client.
+ * \param parc Integer holding the number of supplied arguments.
+ * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
+ * pointers.
+ * \note Valid arguments for this command are:
+ *
+ * server introducing new nick (without services support)
+ * - parv[0] = sender prefix
+ * - parv[1] = nickname
+ * - parv[2] = hop count
+ * - parv[3] = TS
+ * - parv[4] = umode
+ * - parv[5] = username
+ * - parv[6] = hostname
+ * - parv[7] = ip
+ * - parv[8] = uid
+ * - parv[9] = ircname (gecos)
+ *
+ * server introducing new nick (with services support)
+ * - parv[ 0] = sender prefix
+ * - parv[ 1] = nickname
+ * - parv[ 2] = hop count
+ * - parv[ 3] = TS
+ * - parv[ 4] = umode
+ * - parv[ 5] = username
+ * - parv[ 6] = hostname
+ * - parv[ 7] = ip
+ * - parv[ 8] = uid
+ * - parv[ 9] = services id (timestamp)
+ * - parv[10] = ircname (gecos)
+ */
+static void
+ms_uid(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *target_p = NULL;
+ time_t newts = 0;
+ const char *svsid = "0";
+
+ if (parc < 10 || EmptyString(parv[parc-1]))
+ return;
+
+ if (check_clean_nick(client_p, source_p, parv[1], source_p) ||
+ check_clean_user(client_p, parv[1], parv[5], source_p) ||
+ check_clean_host(client_p, parv[1], parv[6], source_p))
+ return;
+
+ newts = atol(parv[3]);
+ svsid = parc == 11 ? parv[9] : "0";
+
+ /*
+ * if there is an ID collision, kill our client, and kill theirs.
+ * this may generate 401's, but it ensures that both clients always
+ * go, even if the other server refuses to do the right thing.
+ */
+ if ((target_p = hash_find_id(parv[8])) != NULL)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "ID collision on %s(%s <- %s)(both killed)",
+ target_p->name, target_p->from->name,
+ client_p->name);
+ kill_client_ll_serv_butone(NULL, target_p, "%s (ID collision)",
+ me.name);
+
+ ++ServerStats.is_kill;
+ AddFlag(target_p, FLAGS_KILLED);
+ exit_client(target_p, &me, "ID Collision");
+ return;
+ }
+
+ if ((target_p = hash_find_client(parv[1])) == NULL)
+ uid_from_server(client_p, source_p, parc, parv, newts, svsid, parv[1], parv[parc-1]);
+ else if (IsUnknown(target_p))
+ {
+ exit_client(target_p, &me, "Overridden");
+ uid_from_server(client_p, source_p, parc, parv, newts, svsid, parv[1], parv[parc-1]);
+ }
+ else
+ perform_nick_collides(source_p, client_p, target_p, parc, parv, newts, svsid, parv[1],
+ parv[parc-1], parv[8]);
+}
+
+/* check_clean_nick()
+ *
+ * input - pointer to source
+ * -
+ * - nickname
+ * - truncated nickname
+ * - origin of client
+ * - pointer to server nick is coming from
+ * output - none
+ * side effects - if nickname is erroneous, or a different length to
+ * truncated nickname, return 1
+ */
+static int
+check_clean_nick(struct Client *client_p, struct Client *source_p,
+ char *nick, struct Client *server_p)
+{
+ /* the old code did some wacky stuff here, if the nick is invalid, kill it
+ * and dont bother messing at all
+ */
+ if (!valid_nickname(nick, 0))
+ {
+ ++ServerStats.is_kill;
+ sendto_realops_flags(UMODE_DEBUG, L_ALL,
+ "Bad/long Nick: %s From: %s(via %s)",
+ nick, server_p->name, client_p->name);
+
+ sendto_one(client_p, ":%s KILL %s :%s (Bad Nickname)",
+ me.name, nick, me.name);
+
+ /* bad nick change */
+ if (source_p != client_p)
+ {
+ kill_client_ll_serv_butone(client_p, source_p,
+ "%s (Bad Nickname)",
+ me.name);
+ AddFlag(source_p, FLAGS_KILLED);
+ exit_client(source_p, &me, "Bad Nickname");
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/* check_clean_user()
+ *
+ * input - pointer to client sending data
+ * - nickname
+ * - username to check
+ * - origin of NICK
+ * output - none
+ * side effects - if username is erroneous, return 1
+ */
+static int
+check_clean_user(struct Client *client_p, char *nick,
+ char *user, struct Client *server_p)
+{
+ if (!clean_user_name(user))
+ {
+ ++ServerStats.is_kill;
+ sendto_realops_flags(UMODE_DEBUG, L_ALL,
+ "Bad/Long Username: %s Nickname: %s From: %s(via %s)",
+ user, nick, server_p->name, client_p->name);
+ sendto_one(client_p, ":%s KILL %s :%s (Bad Username)",
+ me.name, nick, me.name);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* check_clean_host()
+ *
+ * input - pointer to client sending us data
+ * - nickname
+ * - hostname to check
+ * - source name
+ * output - none
+ * side effects - if hostname is erroneous, return 1
+ */
+static int
+check_clean_host(struct Client *client_p, char *nick,
+ char *host, struct Client *server_p)
+{
+ if (!clean_host_name(host))
+ {
+ ++ServerStats.is_kill;
+ sendto_realops_flags(UMODE_DEBUG, L_ALL,
+ "Bad/Long Hostname: %s Nickname: %s From: %s(via %s)",
+ host, nick, server_p->name, client_p->name);
+ sendto_one(client_p, ":%s KILL %s :%s (Bad Hostname)",
+ me.name, nick, me.name);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* clean_user_name()
+ *
+ * input - username
+ * output - none
+ * side effects - walks through the username, returning 0 if erroneous
+ */
+static int
+clean_user_name(const char *user)
+{
+ const char *p = user;
+
+ assert(user && *user);
+
+ for (; *p; ++p)
+ if (!IsUserChar(*p))
+ return 0;
+
+ return p - user <= USERLEN;
+}
+
+/* clean_host_name()
+ * input - hostname
+ * output - none
+ * side effects - walks through the hostname, returning 0 if erroneous
+ */
+static int
+clean_host_name(const char *host)
+{
+ const char *p = host;
+
+ assert(host && *host);
+
+ for (; *p; ++p)
+ if (!IsHostChar(*p))
+ return 0;
+
+ return p - host <= HOSTLEN;
+}
+
+/*
+ * nick_from_server()
+ */
+static void
+nick_from_server(struct Client *client_p, struct Client *source_p, int parc,
+ char *parv[], time_t newts, const char *svsid, char *nick, char *ngecos)
+{
+ int samenick = 0;
+
+ if (IsServer(source_p))
+ {
+ /* A server introducing a new client, change source */
+ source_p = make_client(client_p);
+ dlinkAdd(source_p, &source_p->node, &global_client_list);
+
+ if (parc > 2)
+ source_p->hopcount = atoi(parv[2]);
+ if (newts)
+ source_p->tsinfo = newts;
+ else
+ {
+ newts = source_p->tsinfo = CurrentTime;
+ ts_warn("Remote nick %s (%s) introduced without a TS", nick, parv[0]);
+ }
+
+ strlcpy(source_p->svid, svsid, sizeof(source_p->svid));
+ strlcpy(source_p->info, ngecos, sizeof(source_p->info));
+ /* copy the nick in place */
+ strlcpy(source_p->name, nick, sizeof(source_p->name));
+ hash_add_client(source_p);
+
+ if (parc > 8)
+ {
+ const char *m;
+
+ /* parse usermodes */
+ for (m = &parv[4][1]; *m; ++m)
+ {
+ unsigned int flag = user_modes[(unsigned char)*m];
+
+ if ((flag & UMODE_INVISIBLE) && !HasUMode(source_p, UMODE_INVISIBLE))
+ ++Count.invisi;
+ if ((flag & UMODE_OPER) && !HasUMode(source_p, UMODE_OPER))
+ ++Count.oper;
+
+ source_p->umodes |= flag & SEND_UMODES;
+ }
+
+ register_remote_user(source_p, parv[5], parv[6],
+ parv[7], ngecos);
+ return;
+ }
+ }
+ else if (source_p->name[0])
+ {
+ samenick = !irccmp(source_p->name, nick);
+
+ /* client changing their nick */
+ if (!samenick)
+ {
+ DelUMode(source_p, UMODE_REGISTERED);
+ watch_check_hash(source_p, RPL_LOGOFF);
+ source_p->tsinfo = newts ? newts : CurrentTime;
+ }
+
+ sendto_common_channels_local(source_p, 1, ":%s!%s@%s NICK :%s",
+ source_p->name,source_p->username,
+ source_p->host, nick);
+
+ add_history(source_p, 1);
+ sendto_server(client_p, CAP_TS6, NOCAPS,
+ ":%s NICK %s :%lu",
+ ID(source_p), nick, (unsigned long)source_p->tsinfo);
+ sendto_server(client_p, NOCAPS, CAP_TS6,
+ ":%s NICK %s :%lu",
+ source_p->name, nick, (unsigned long)source_p->tsinfo);
+ }
+
+ /* set the new nick name */
+ if (source_p->name[0])
+ hash_del_client(source_p);
+
+ strlcpy(source_p->name, nick, sizeof(source_p->name));
+ hash_add_client(source_p);
+
+ if (!samenick)
+ watch_check_hash(source_p, RPL_LOGON);
+}
+
+/*
+ * client_from_server()
+ */
+static void
+uid_from_server(struct Client *client_p, struct Client *source_p, int parc,
+ char *parv[], time_t newts, const char *svsid, char *nick, char *ugecos)
+{
+ const char *m = NULL;
+ const char *servername = source_p->name;
+
+ source_p = make_client(client_p);
+ dlinkAdd(source_p, &source_p->node, &global_client_list);
+
+ source_p->hopcount = atoi(parv[2]);
+ source_p->tsinfo = newts;
+ strlcpy(source_p->svid, svsid, sizeof(source_p->svid));
+
+ /* copy the nick in place */
+ strcpy(source_p->name, nick);
+ strlcpy(source_p->id, parv[8], sizeof(source_p->id));
+ strlcpy(source_p->sockhost, parv[7], sizeof(source_p->sockhost));
+ strlcpy(source_p->info, ugecos, sizeof(source_p->info));
+
+ hash_add_client(source_p);
+ hash_add_id(source_p);
+
+ /* parse usermodes */
+ for (m = &parv[4][1]; *m; ++m)
+ {
+ unsigned int flag = user_modes[(unsigned char)*m];
+
+ if ((flag & UMODE_INVISIBLE) && !HasUMode(source_p, UMODE_INVISIBLE))
+ ++Count.invisi;
+ if ((flag & UMODE_OPER) && !HasUMode(source_p, UMODE_OPER))
+ ++Count.oper;
+
+ source_p->umodes |= flag & SEND_UMODES;
+ }
+
+ register_remote_user(source_p, parv[5], parv[6],
+ servername, ugecos);
+}
+
+static void
+perform_nick_collides(struct Client *source_p, struct Client *client_p,
+ struct Client *target_p, int parc, char *parv[],
+ time_t newts, const char *svsid, char *nick, char *gecos, char *uid)
+{
+ int sameuser;
+
+ /* server introducing new nick */
+ if (IsServer(source_p))
+ {
+ /* if we dont have a ts, or their TS's are the same, kill both */
+ if (!newts || !target_p->tsinfo || (newts == target_p->tsinfo))
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Nick collision on %s(%s <- %s)(both killed)",
+ target_p->name, target_p->from->name,
+ client_p->name);
+
+ /* if we have a UID, issue a kill for it */
+ if (uid)
+ sendto_one(client_p, ":%s KILL %s :%s (Nick collision (new))",
+ me.id, uid, me.name);
+
+ kill_client_ll_serv_butone(NULL, target_p,
+ "%s (Nick collision (new))",
+ me.name);
+ ++ServerStats.is_kill;
+ sendto_one(target_p, form_str(ERR_NICKCOLLISION),
+ me.name, target_p->name, target_p->name);
+
+ AddFlag(target_p, FLAGS_KILLED);
+ exit_client(target_p, &me, "Nick collision (new)");
+ return;
+ }
+ /* the timestamps are different */
+ else
+ {
+ sameuser = !irccmp(target_p->username, parv[5]) &&
+ !irccmp(target_p->host, parv[6]);
+
+ /* if the users are the same (loaded a client on a different server)
+ * and the new users ts is older, or the users are different and the
+ * new users ts is newer, ignore the new client and let it do the kill
+ */
+ if ((sameuser && newts < target_p->tsinfo) ||
+ (!sameuser && newts > target_p->tsinfo))
+ {
+ if (uid)
+ sendto_one(client_p, ":%s KILL %s :%s (Nick collision (new))",
+ me.id, uid, me.name);
+ return;
+ }
+ else
+ {
+ if (sameuser)
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Nick collision on %s(%s <- %s)(older killed)",
+ target_p->name, target_p->from->name,
+ client_p->name);
+ else
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Nick collision on %s(%s <- %s)(newer killed)",
+ target_p->name, target_p->from->name,
+ client_p->name);
+
+ ++ServerStats.is_kill;
+ sendto_one(target_p, form_str(ERR_NICKCOLLISION),
+ me.name, target_p->name, target_p->name);
+
+ /* if it came from a LL server, itd have been source_p,
+ * so we dont need to mark target_p as known
+ */
+ kill_client_ll_serv_butone(source_p, target_p,
+ "%s (Nick collision (new))",
+ me.name);
+
+ AddFlag(target_p, FLAGS_KILLED);
+ exit_client(target_p, &me, "Nick collision");
+
+ if (!uid && (parc == 9 || parc == 10))
+ nick_from_server(client_p, source_p, parc, parv, newts, svsid, nick, gecos);
+ else if (uid && (parc == 10 || parc == 11))
+ uid_from_server(client_p, source_p, parc, parv, newts, svsid, nick, gecos);
+
+ return;
+ }
+ }
+ }
+
+ /* its a client changing nick and causing a collide */
+ if (!newts || !target_p->tsinfo || (newts == target_p->tsinfo))
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Nick change collision from %s to %s(%s <- %s)(both killed)",
+ source_p->name, target_p->name, target_p->from->name,
+ client_p->name);
+
+ sendto_one(target_p, form_str(ERR_NICKCOLLISION), me.name,
+ target_p->name, target_p->name);
+
+ ++ServerStats.is_kill;
+ kill_client_ll_serv_butone(NULL, source_p, "%s (Nick change collision)",
+ me.name);
+
+ ++ServerStats.is_kill;
+ kill_client_ll_serv_butone(NULL, target_p, "%s (Nick change collision)",
+ me.name);
+
+ AddFlag(target_p, FLAGS_KILLED);
+ exit_client(target_p, &me, "Nick collision (new)");
+
+ AddFlag(source_p, FLAGS_KILLED);
+ exit_client(source_p, &me, "Nick collision (old)");
+ return;
+ }
+ else
+ {
+ sameuser = !irccmp(target_p->username, source_p->username) &&
+ !irccmp(target_p->host, source_p->host);
+
+ if ((sameuser && newts < target_p->tsinfo) ||
+ (!sameuser && newts > target_p->tsinfo))
+ {
+ if (sameuser)
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Nick change collision from %s to %s(%s <- %s)(older killed)",
+ source_p->name, target_p->name, target_p->from->name,
+ client_p->name);
+ else
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Nick change collision from %s to %s(%s <- %s)(newer killed)",
+ source_p->name, target_p->name, target_p->from->name,
+ client_p->name);
+
+ ++ServerStats.is_kill;
+ kill_client_ll_serv_butone(client_p, source_p,
+ "%s (Nick change collision)",
+ me.name);
+
+ AddFlag(source_p, FLAGS_KILLED);
+
+ if (sameuser)
+ exit_client(source_p, &me, "Nick collision (old)");
+ else
+ exit_client(source_p, &me, "Nick collision (new)");
+ return;
+ }
+ else
+ {
+ if (sameuser)
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Nick collision on %s(%s <- %s)(older killed)",
+ target_p->name, target_p->from->name,
+ client_p->name);
+ else
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Nick collision on %s(%s <- %s)(newer killed)",
+ target_p->name, target_p->from->name,
+ client_p->name);
+
+ kill_client_ll_serv_butone(source_p, target_p,
+ "%s (Nick collision)",
+ me.name);
+
+ ++ServerStats.is_kill;
+ sendto_one(target_p, form_str(ERR_NICKCOLLISION),
+ me.name, target_p->name, target_p->name);
+
+ AddFlag(target_p, FLAGS_KILLED);
+ exit_client(target_p, &me, "Nick collision");
+ }
+ }
+
+ /* we should only ever call nick_from_server() here, as
+ * this is a client changing nick, not a new client
+ */
+ nick_from_server(client_p, source_p, parc, parv, newts, svsid, nick, gecos);
+}
+
+static struct Message nick_msgtab = {
+ "NICK", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ {mr_nick, m_nick, ms_nick, m_ignore, m_nick, m_ignore}
+};
+
+static struct Message uid_msgtab = {
+ "UID", 0, 0, 10, MAXPARA, MFLG_SLOW, 0,
+ {m_ignore, m_ignore, ms_uid, m_ignore, m_ignore, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&uid_msgtab);
+ mod_add_cmd(&nick_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&uid_msgtab);
+ mod_del_cmd(&nick_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = MODULE_FLAG_CORE
+};
diff --git a/modules/core/m_part.c b/modules/core/m_part.c
new file mode 100644
index 0000000..3d1e83a
--- /dev/null
+++ b/modules/core/m_part.c
@@ -0,0 +1,167 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_part.c: Parts a user from a channel.
+ *
+ * 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 "channel.h"
+#include "channel_mode.h"
+#include "client.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "s_serv.h"
+#include "parse.h"
+#include "modules.h"
+#include "conf.h"
+#include "packet.h"
+
+
+/* part_one_client()
+ *
+ * inputs - pointer to server
+ * - pointer to source client to remove
+ * - char pointer of name of channel to remove from
+ * output - none
+ * side effects - remove ONE client given the channel name
+ */
+static void
+part_one_client(struct Client *client_p, struct Client *source_p,
+ const char *name, const char *reason)
+{
+ struct Channel *chptr = NULL;
+ struct Membership *ms = NULL;
+
+ if ((chptr = hash_find_channel(name)) == NULL)
+ {
+ sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
+ me.name, source_p->name, name);
+ return;
+ }
+
+ if ((ms = find_channel_link(source_p, chptr)) == NULL)
+ {
+ sendto_one(source_p, form_str(ERR_NOTONCHANNEL),
+ me.name, source_p->name, name);
+ return;
+ }
+
+ if (MyConnect(source_p) && !HasUMode(source_p, UMODE_OPER))
+ check_spambot_warning(source_p, NULL);
+
+ /*
+ * Remove user from the old channel (if any)
+ * only allow /part reasons in -m chans
+ */
+ if (reason[0] && (!MyConnect(source_p) ||
+ ((can_send(chptr, source_p, ms) &&
+ (source_p->localClient->firsttime + ConfigFileEntry.anti_spam_exit_message_time)
+ < CurrentTime))))
+ {
+ sendto_server(client_p, CAP_TS6, NOCAPS,
+ ":%s PART %s :%s", ID(source_p), chptr->chname,
+ reason);
+ sendto_server(client_p, NOCAPS, CAP_TS6,
+ ":%s PART %s :%s", source_p->name, chptr->chname,
+ reason);
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s PART %s :%s",
+ source_p->name, source_p->username,
+ source_p->host, chptr->chname, reason);
+ }
+ else
+ {
+ sendto_server(client_p, CAP_TS6, NOCAPS,
+ ":%s PART %s", ID(source_p), chptr->chname);
+ sendto_server(client_p, NOCAPS, CAP_TS6,
+ ":%s PART %s", source_p->name, chptr->chname);
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s PART %s",
+ source_p->name, source_p->username,
+ source_p->host, chptr->chname);
+ }
+
+ remove_user_from_channel(ms);
+}
+
+/*
+** m_part
+** parv[0] = sender prefix
+** parv[1] = channel
+** parv[2] = reason
+*/
+static void
+m_part(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ char *p = NULL, *name = NULL;
+ char reason[KICKLEN + 1] = { '\0' };
+
+ if (IsServer(source_p))
+ return;
+
+ if (EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, "PART");
+ return;
+ }
+
+ if (parc > 2)
+ strlcpy(reason, parv[2], sizeof(reason));
+
+ /* Finish the flood grace period... */
+ if (MyClient(source_p) && !IsFloodDone(source_p))
+ flood_endgrace(source_p);
+
+ for (name = strtoken(&p, parv[1], ","); name;
+ name = strtoken(&p, NULL, ","))
+ part_one_client(client_p, source_p, name, reason);
+}
+
+static struct Message part_msgtab = {
+ "PART", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_part, m_part, m_ignore, m_part, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&part_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&part_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = MODULE_FLAG_CORE
+};
diff --git a/modules/core/m_quit.c b/modules/core/m_quit.c
new file mode 100644
index 0000000..ca73e2e
--- /dev/null
+++ b/modules/core/m_quit.c
@@ -0,0 +1,98 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_quit.c: Makes a user quit from IRC.
+ *
+ * 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 "ircd.h"
+#include "irc_string.h"
+#include "s_serv.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+#include "conf.h"
+
+
+/*
+** m_quit
+** parv[0] = sender prefix
+** parv[1] = comment
+*/
+static void
+m_quit(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ char *comment = (parc > 1 && parv[1]) ? parv[1] : client_p->name;
+ char reason[KICKLEN + 1] = "Quit: ";
+
+ if (*comment && (HasUMode(source_p, UMODE_OPER) ||
+ (source_p->localClient->firsttime + ConfigFileEntry.anti_spam_exit_message_time)
+ < CurrentTime))
+ strlcpy(reason+6, comment, sizeof(reason)-6);
+
+ exit_client(source_p, source_p, reason);
+}
+
+/*
+** ms_quit
+** parv[0] = sender prefix
+** parv[1] = comment
+*/
+static void
+ms_quit(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ char *comment = (parc > 1 && parv[1]) ? parv[1] : client_p->name;
+
+ if (strlen(comment) > (size_t)KICKLEN)
+ comment[KICKLEN] = '\0';
+
+ exit_client(source_p, source_p, comment);
+}
+
+static struct Message quit_msgtab = {
+ "QUIT", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ {m_quit, m_quit, ms_quit, m_ignore, m_quit, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&quit_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&quit_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = MODULE_FLAG_CORE
+};
diff --git a/modules/core/m_server.c b/modules/core/m_server.c
new file mode 100644
index 0000000..6054a34
--- /dev/null
+++ b/modules/core/m_server.c
@@ -0,0 +1,624 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_server.c: Introduces a server.
+ *
+ * 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" /* client struct */
+#include "event.h"
+#include "hash.h" /* add_to_client_hash_table */
+#include "irc_string.h"
+#include "ircd.h" /* me */
+#include "numeric.h" /* ERR_xxx */
+#include "conf.h" /* struct AccessItem */
+#include "log.h" /* log level defines */
+#include "s_serv.h" /* server_estab, check_server */
+#include "s_user.h"
+#include "send.h" /* sendto_one */
+#include "parse.h"
+#include "modules.h"
+
+
+static void set_server_gecos(struct Client *, const char *);
+
+/* mr_server()
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ * parv[2] = serverinfo/hopcount
+ * parv[3] = serverinfo
+ */
+static void
+mr_server(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ char *name;
+ struct Client *target_p;
+ int hop;
+
+ if (EmptyString(parv[3]))
+ {
+ sendto_one(client_p, "ERROR :No servername");
+ exit_client(client_p, client_p, "Wrong number of args");
+ return;
+ }
+
+ name = parv[1];
+ hop = atoi(parv[2]);
+
+ /*
+ * Reject a direct nonTS server connection if we're TS_ONLY -orabidoo
+ */
+ if (!DoesTS(client_p))
+ {
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "Unauthorized server connection attempt from %s: Non-TS server "
+ "for server %s", get_client_name(client_p, HIDE_IP), name);
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "Unauthorized server connection attempt from %s: Non-TS server "
+ "for server %s", get_client_name(client_p, MASK_IP), name);
+ exit_client(client_p, client_p, "Non-TS server");
+ return;
+ }
+
+ if (!valid_servname(name))
+ {
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "Unauthorized server connection attempt from %s: Bogus server name "
+ "for server %s", get_client_name(client_p, HIDE_IP), name);
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "Unauthorized server connection attempt from %s: Bogus server name "
+ "for server %s", get_client_name(client_p, MASK_IP), name);
+ exit_client(client_p, client_p, "Bogus server name");
+ return;
+ }
+
+ /* Now we just have to call check_server and everything should
+ * be check for us... -A1kmm.
+ */
+ switch (check_server(name, client_p))
+ {
+ case -1:
+ if (ConfigFileEntry.warn_no_nline)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "Unauthorized server connection attempt from %s: No entry for "
+ "servername %s", get_client_name(client_p, HIDE_IP), name);
+
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "Unauthorized server connection attempt from %s: No entry for "
+ "servername %s", get_client_name(client_p, MASK_IP), name);
+ }
+
+ exit_client(client_p, client_p, "Invalid servername.");
+ return;
+ /* NOT REACHED */
+ break;
+
+ case -2:
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "Unauthorized server connection attempt from %s: Bad password "
+ "for server %s", get_client_name(client_p, HIDE_IP), name);
+
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "Unauthorized server connection attempt from %s: Bad password "
+ "for server %s", get_client_name(client_p, MASK_IP), name);
+
+ exit_client(client_p, client_p, "Invalid password.");
+ return;
+ /* NOT REACHED */
+ break;
+
+ case -3:
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "Unauthorized server connection attempt from %s: Invalid host "
+ "for server %s", get_client_name(client_p, HIDE_IP), name);
+
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "Unauthorized server connection attempt from %s: Invalid host "
+ "for server %s", get_client_name(client_p, MASK_IP), name);
+
+ exit_client(client_p, client_p, "Invalid host.");
+ return;
+ /* NOT REACHED */
+ break;
+ }
+
+ if ((client_p->id[0] && (target_p = hash_find_id(client_p->id)))
+ || (target_p = hash_find_server(name)))
+ {
+ /* This link is trying feed me a server that I already have
+ * access through another path -- multiple paths not accepted
+ * currently, kill this link immediately!!
+ *
+ * Rather than KILL the link which introduced it, KILL the
+ * youngest of the two links. -avalon
+ *
+ * Definitely don't do that here. This is from an unregistered
+ * connect - A1kmm.
+ */
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "Attempt to re-introduce server %s SID %s from %s",
+ name, client_p->id,
+ get_client_name(client_p, HIDE_IP));
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "Attempt to re-introduce server %s SID %s from %s",
+ name, client_p->id,
+ get_client_name(client_p, MASK_IP));
+ sendto_one(client_p, "ERROR :Server ID already exists.");
+ exit_client(client_p, client_p, "Server ID Exists");
+ return;
+ }
+
+ /* XXX If somehow there is a connect in progress and
+ * a connect comes in with same name toss the pending one,
+ * but only if it's not the same client! - Dianora
+ */
+ if ((target_p = find_servconn_in_progress(name)))
+ if (target_p != client_p)
+ exit_client(target_p, &me, "Overridden");
+
+ /* if we are connecting (Handshake), we already have the name from the
+ * connect{} block in client_p->name
+ */
+ strlcpy(client_p->name, name, sizeof(client_p->name));
+ set_server_gecos(client_p, parv[3]);
+ client_p->hopcount = hop;
+ server_estab(client_p);
+}
+
+/* ms_server()
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ * parv[2] = serverinfo/hopcount
+ * parv[3] = serverinfo
+ */
+static void
+ms_server(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ char *name;
+ struct Client *target_p;
+ struct AccessItem *aconf;
+ int hop;
+ int hlined = 0;
+ int llined = 0;
+ dlink_node *ptr = NULL;
+
+ /* Just to be sure -A1kmm. */
+ if (!IsServer(source_p))
+ return;
+
+ if (EmptyString(parv[3]))
+ {
+ sendto_one(client_p, "ERROR :No servername");
+ return;
+ }
+
+ name = parv[1];
+ hop = atoi(parv[2]);
+
+ if (!valid_servname(name))
+ {
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "Link %s introduced server with bogus server name %s",
+ get_client_name(client_p, SHOW_IP), name);
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "Link %s introduced server with bogus server name %s",
+ get_client_name(client_p, MASK_IP), name);
+ sendto_one(client_p, "ERROR :Bogus server name introduced");
+ exit_client(client_p, &me, "Bogus server name intoduced");
+ return;
+ }
+
+ if ((target_p = hash_find_server(name)))
+ {
+ /* This link is trying feed me a server that I already have
+ * access through another path -- multiple paths not accepted
+ * currently, kill this link immediately!!
+ *
+ * Rather than KILL the link which introduced it, KILL the
+ * youngest of the two links. -avalon
+ *
+ * I think that we should exit the link itself, not the introducer,
+ * and we should always exit the most recently received(i.e. the
+ * one we are receiving this SERVER for. -A1kmm
+ *
+ * You *cant* do this, if you link somewhere, it bursts you a server
+ * that already exists, then sends you a client burst, you squit the
+ * server, but you keep getting the burst of clients on a server that
+ * doesnt exist, although ircd can handle it, its not a realistic
+ * solution.. --fl_
+ */
+ sendto_one(client_p, "ERROR :Server %s already exists", name);
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "Link %s cancelled, server %s already exists",
+ get_client_name(client_p, SHOW_IP), name);
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "Link %s cancelled, server %s already exists",
+ client_p->name, name);
+ exit_client(client_p, &me, "Server Exists");
+ return;
+ }
+
+ /* XXX If somehow there is a connect in progress and
+ * a connect comes in with same name toss the pending one,
+ * but only if it's not the same client! - Dianora
+ */
+ if ((target_p = find_servconn_in_progress(name)))
+ if (target_p != client_p)
+ exit_client(target_p, &me, "Overridden");
+
+ aconf = map_to_conf(client_p->localClient->confs.head->data);
+
+ /* See if the newly found server is behind a guaranteed
+ * leaf. If so, close the link.
+ */
+ DLINK_FOREACH(ptr, aconf->leaf_list.head)
+ if (match(ptr->data, name))
+ {
+ llined = 1;
+ break;
+ }
+
+ DLINK_FOREACH(ptr, aconf->hub_list.head)
+ if (match(ptr->data, name))
+ {
+ hlined = 1;
+ break;
+ }
+
+ /* Ok, this way this works is
+ *
+ * A server can have a CONF_HUB allowing it to introduce servers
+ * behind it.
+ *
+ * connect {
+ * name = "irc.bighub.net";
+ * hub_mask="*";
+ * ...
+ *
+ * That would allow "irc.bighub.net" to introduce anything it wanted..
+ *
+ * However
+ *
+ * connect {
+ * name = "irc.somehub.fi";
+ * hub_mask="*";
+ * leaf_mask="*.edu";
+ *...
+ * Would allow this server in finland to hub anything but
+ * .edu's
+ */
+
+ /* Ok, check client_p can hub the new server */
+ if (!hlined)
+ {
+ /* OOOPs nope can't HUB */
+ sendto_realops_flags(UMODE_ALL, L_ADMIN, "Non-Hub link %s introduced %s.",
+ get_client_name(client_p, HIDE_IP), name);
+ sendto_realops_flags(UMODE_ALL, L_OPER, "Non-Hub link %s introduced %s.",
+ get_client_name(client_p, MASK_IP), name);
+ exit_client(source_p, &me, "No matching hub_mask.");
+ return;
+ }
+
+ /* Check for the new server being leafed behind this HUB */
+ if (llined)
+ {
+ /* OOOPs nope can't HUB this leaf */
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "Link %s introduced leafed server %s.",
+ get_client_name(client_p, HIDE_IP), name);
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "Link %s introduced leafed server %s.",
+ get_client_name(client_p, MASK_IP), name);
+ /* If it is new, we are probably misconfigured, so split the
+ * non-hub server introducing this. Otherwise, split the new
+ * server. -A1kmm.
+ */
+ /* wastes too much bandwidth, generates too many errors on
+ * larger networks, dont bother. --fl_
+ */
+ exit_client(client_p, &me, "Leafed Server.");
+ return;
+ }
+
+ target_p = make_client(client_p);
+ make_server(target_p);
+ target_p->hopcount = hop;
+ target_p->servptr = source_p;
+
+ strlcpy(target_p->name, name, sizeof(target_p->name));
+
+ set_server_gecos(target_p, parv[3]);
+ SetServer(target_p);
+
+ if (HasFlag(source_p, FLAGS_SERVICE) || find_matching_name_conf(SERVICE_TYPE, target_p->name, NULL, NULL, 0))
+ AddFlag(target_p, FLAGS_SERVICE);
+
+ dlinkAdd(target_p, &target_p->node, &global_client_list);
+ dlinkAdd(target_p, make_dlink_node(), &global_serv_list);
+ dlinkAdd(target_p, &target_p->lnode, &target_p->servptr->serv->server_list);
+
+ hash_add_client(target_p);
+
+ sendto_server(client_p, NOCAPS, NOCAPS, ":%s SERVER %s %d :%s%s",
+ source_p->name, target_p->name, hop + 1,
+ IsHidden(target_p) ? "(H) " : "", target_p->info);
+
+ sendto_realops_flags(UMODE_EXTERNAL, L_ALL,
+ "Server %s being introduced by %s",
+ target_p->name, source_p->name);
+}
+
+/* ms_sid()
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ * parv[2] = serverinfo/hopcount
+ * parv[3] = sid of new server
+ * parv[4] = serverinfo
+ */
+static void
+ms_sid(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *target_p;
+ struct AccessItem *aconf = NULL;
+ int hlined = 0;
+ int llined = 0;
+ dlink_node *ptr = NULL;
+ int hop;
+
+ /* Just to be sure -A1kmm. */
+ if (!IsServer(source_p))
+ return;
+
+ if (EmptyString(parv[4]))
+ {
+ sendto_one(client_p, "ERROR :No servername");
+ return;
+ }
+
+ hop = atoi(parv[2]);
+
+ if (!valid_servname(parv[1]))
+ {
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "Link %s introduced server with bogus server name %s",
+ get_client_name(client_p, SHOW_IP), parv[1]);
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "Link %s introduced server with bogus server name %s",
+ get_client_name(client_p, MASK_IP), parv[1]);
+ sendto_one(client_p, "ERROR :Bogus server name introduced");
+ exit_client(client_p, &me, "Bogus server name intoduced");
+ return;
+ }
+
+ if (!valid_sid(parv[3]))
+ {
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "Link %s introduced server with bogus server ID %s",
+ get_client_name(client_p, SHOW_IP), parv[3]);
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "Link %s introduced server with bogus server ID %s",
+ get_client_name(client_p, MASK_IP), parv[3]);
+ sendto_one(client_p, "ERROR :Bogus server ID introduced");
+ exit_client(client_p, &me, "Bogus server ID intoduced");
+ return;
+ }
+
+ /* collision on SID? */
+ if ((target_p = hash_find_id(parv[3])))
+ {
+ sendto_one(client_p, "ERROR :SID %s already exists", parv[3]);
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "Link %s cancelled, SID %s already exists",
+ get_client_name(client_p, SHOW_IP), parv[3]);
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "Link %s cancelled, SID %s already exists",
+ client_p->name, parv[3]);
+ exit_client(client_p, &me, "SID Exists");
+ return;
+ }
+
+ /* collision on name? */
+ if ((target_p = hash_find_server(parv[1])))
+ {
+ sendto_one(client_p, "ERROR :Server %s already exists", parv[1]);
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "Link %s cancelled, server %s already exists",
+ get_client_name(client_p, SHOW_IP), parv[1]);
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "Link %s cancelled, server %s already exists",
+ client_p->name, parv[1]);
+ exit_client(client_p, &me, "Server Exists");
+ return;
+ }
+
+ /* XXX If somehow there is a connect in progress and
+ * a connect comes in with same name toss the pending one,
+ * but only if it's not the same client! - Dianora
+ */
+ if ((target_p = find_servconn_in_progress(parv[1])))
+ if (target_p != client_p)
+ exit_client(target_p, &me, "Overridden");
+
+ aconf = map_to_conf(client_p->localClient->confs.head->data);
+
+ /* See if the newly found server is behind a guaranteed
+ * leaf. If so, close the link.
+ */
+ DLINK_FOREACH(ptr, aconf->leaf_list.head)
+ if (match(ptr->data, parv[1]))
+ {
+ llined = 1;
+ break;
+ }
+
+ DLINK_FOREACH(ptr, aconf->hub_list.head)
+ if (match(ptr->data, parv[1]))
+ {
+ hlined = 1;
+ break;
+ }
+
+
+ /* Ok, this way this works is
+ *
+ * A server can have a CONF_HUB allowing it to introduce servers
+ * behind it.
+ *
+ * connect {
+ * name = "irc.bighub.net";
+ * hub_mask="*";
+ * ...
+ *
+ * That would allow "irc.bighub.net" to introduce anything it wanted..
+ *
+ * However
+ *
+ * connect {
+ * name = "irc.somehub.fi";
+ * hub_mask="*";
+ * leaf_mask="*.edu";
+ *...
+ * Would allow this server in finland to hub anything but
+ * .edu's
+ */
+
+ /* Ok, check client_p can hub the new server, and make sure it's not a LL */
+ if (!hlined)
+ {
+ /* OOOPs nope can't HUB */
+ sendto_realops_flags(UMODE_ALL, L_ADMIN, "Non-Hub link %s introduced %s.",
+ get_client_name(client_p, SHOW_IP), parv[1]);
+ sendto_realops_flags(UMODE_ALL, L_OPER, "Non-Hub link %s introduced %s.",
+ get_client_name(client_p, MASK_IP), parv[1]);
+ exit_client(source_p, &me, "No matching hub_mask.");
+ return;
+ }
+
+ /* Check for the new server being leafed behind this HUB */
+ if (llined)
+ {
+ /* OOOPs nope can't HUB this leaf */
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "Link %s introduced leafed server %s.",
+ get_client_name(client_p, SHOW_IP), parv[1]);
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "Link %s introduced leafed server %s.",
+ get_client_name(client_p, MASK_IP), parv[1]);
+ exit_client(client_p, &me, "Leafed Server.");
+ return;
+ }
+
+ target_p = make_client(client_p);
+ make_server(target_p);
+ target_p->hopcount = hop;
+ target_p->servptr = source_p;
+
+ strlcpy(target_p->name, parv[1], sizeof(target_p->name));
+ strlcpy(target_p->id, parv[3], sizeof(target_p->id));
+
+ set_server_gecos(target_p, parv[4]);
+ SetServer(target_p);
+
+ if (HasFlag(source_p, FLAGS_SERVICE) || find_matching_name_conf(SERVICE_TYPE, target_p->name, NULL, NULL, 0))
+ AddFlag(target_p, FLAGS_SERVICE);
+
+ dlinkAdd(target_p, &target_p->node, &global_client_list);
+ dlinkAdd(target_p, make_dlink_node(), &global_serv_list);
+ dlinkAdd(target_p, &target_p->lnode, &target_p->servptr->serv->server_list);
+
+ hash_add_client(target_p);
+ hash_add_id(target_p);
+
+ sendto_server(client_p, CAP_TS6, NOCAPS, ":%s SID %s %d %s :%s%s",
+ ID_or_name(source_p, client_p), target_p->name, hop + 1,
+ target_p->id, IsHidden(target_p) ? "(H) " : "", target_p->info);
+ sendto_server(client_p, NOCAPS, CAP_TS6, ":%s SERVER %s %d :%s%s",
+ source_p->name, target_p->name, hop + 1,
+ IsHidden(target_p) ? "(H) " : "", target_p->info);
+
+ sendto_realops_flags(UMODE_EXTERNAL, L_ALL,
+ "Server %s being introduced by %s",
+ target_p->name, source_p->name);
+}
+
+/* set_server_gecos()
+ *
+ * input - pointer to client
+ * output - NONE
+ * side effects - servers gecos field is set
+ */
+static void
+set_server_gecos(struct Client *client_p, const char *info)
+{
+ const char *s = info;
+
+ /* check for (H) which is a hidden server */
+ if (!strncmp(s, "(H) ", 4))
+ {
+ SetHidden(client_p);
+ s = s + 4;
+ }
+
+ if (!EmptyString(s))
+ strlcpy(client_p->info, s, sizeof(client_p->info));
+ else
+ strlcpy(client_p->info, "(Unknown Location)", sizeof(client_p->info));
+}
+
+static struct Message server_msgtab = {
+ "SERVER", 0, 0, 4, MAXPARA, MFLG_SLOW, 0,
+ {mr_server, m_registered, ms_server, m_ignore, m_registered, m_ignore}
+};
+
+static struct Message sid_msgtab = {
+ "SID", 0, 0, 5, MAXPARA, MFLG_SLOW, 0,
+ {rfc1459_command_send_error, m_ignore, ms_sid, m_ignore, m_ignore, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&sid_msgtab);
+ mod_add_cmd(&server_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&sid_msgtab);
+ mod_del_cmd(&server_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = MODULE_FLAG_CORE
+};
diff --git a/modules/core/m_sjoin.c b/modules/core/m_sjoin.c
new file mode 100644
index 0000000..72f1bda
--- /dev/null
+++ b/modules/core/m_sjoin.c
@@ -0,0 +1,850 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_sjoin.c: Joins a user to a channel.
+ *
+ * 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 "channel.h"
+#include "channel_mode.h"
+#include "client.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_serv.h"
+#include "conf.h"
+#include "s_misc.h"
+
+
+static char modebuf[MODEBUFLEN];
+static char parabuf[MODEBUFLEN];
+static char sendbuf[MODEBUFLEN];
+static const char *para[MAXMODEPARAMS];
+static char *mbuf;
+static int pargs;
+
+static void set_final_mode(struct Mode *, struct Mode *);
+static void remove_our_modes(struct Channel *, struct Client *);
+static void remove_a_mode(struct Channel *, struct Client *, int, char);
+static void remove_ban_list(struct Channel *, struct Client *, dlink_list *, char, int);
+
+
+/* ms_sjoin()
+ *
+ * parv[0] - sender
+ * parv[1] - TS
+ * parv[2] - channel
+ * parv[3] - modes + n arguments (key and/or limit)
+ * parv[4+n] - flags+nick list (all in one parameter)
+ *
+ * process a SJOIN, taking the TS's into account to either ignore the
+ * incoming modes or undo the existing ones or merge them, and JOIN
+ * all the specified users while sending JOIN/MODEs to local clients
+ */
+static void
+ms_sjoin(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Channel *chptr = NULL;
+ struct Client *target_p = NULL;
+ time_t newts;
+ time_t oldts;
+ time_t tstosend;
+ struct Mode mode, *oldmode;
+ int args = 0;
+ char keep_our_modes = 1;
+ char keep_new_modes = 1;
+ char have_many_nicks = 0;
+ int lcount;
+ char nick_prefix[4];
+ char uid_prefix[4];
+ char *np, *up;
+ int len_nick = 0;
+ int len_uid = 0;
+ int isnew = 0;
+ int buflen = 0;
+ int slen;
+ unsigned int fl;
+ char *s;
+ char *sptr;
+ char nick_buf[IRCD_BUFSIZE]; /* buffer for modes and prefix */
+ char uid_buf[IRCD_BUFSIZE]; /* buffer for modes/prefixes for CAP_TS6 servers */
+ char *nick_ptr, *uid_ptr; /* pointers used for making the two mode/prefix buffers */
+ char *p; /* pointer used making sjbuf */
+ dlink_node *m;
+ const char *servername = (ConfigServerHide.hide_servers || IsHidden(source_p)) ?
+ me.name : source_p->name;
+
+ if (IsClient(source_p) || parc < 5)
+ return;
+
+ if (!check_channel_name(parv[2], 0))
+ {
+ sendto_realops_flags(UMODE_DEBUG, L_ALL,
+ "*** Too long or invalid channel name from %s: %s",
+ client_p->name, parv[2]);
+ return;
+ }
+
+ modebuf[0] = '\0';
+ mbuf = modebuf;
+ pargs = 0;
+ newts = atol(parv[1]);
+
+ mode.mode = 0;
+ mode.limit = 0;
+ mode.key[0] = '\0';
+
+ for (s = parv[3]; *s; ++s)
+ {
+ switch (*s)
+ {
+ case 't':
+ mode.mode |= MODE_TOPICLIMIT;
+ break;
+ case 'n':
+ mode.mode |= MODE_NOPRIVMSGS;
+ break;
+ case 's':
+ mode.mode |= MODE_SECRET;
+ break;
+ case 'm':
+ mode.mode |= MODE_MODERATED;
+ break;
+ case 'i':
+ mode.mode |= MODE_INVITEONLY;
+ break;
+ case 'p':
+ mode.mode |= MODE_PRIVATE;
+ break;
+ case 'r':
+ mode.mode |= MODE_REGISTERED;
+ break;
+ case 'O':
+ mode.mode |= MODE_OPERONLY;
+ break;
+ case 'S':
+ mode.mode |= MODE_SSLONLY;
+ break;
+ case 'k':
+ strlcpy(mode.key, parv[4 + args], sizeof(mode.key));
+ args++;
+
+ if (parc < 5 + args)
+ return;
+ break;
+ case 'l':
+ mode.limit = atoi(parv[4 + args]);
+ args++;
+
+ if (parc < 5 + args)
+ return;
+ break;
+ }
+ }
+
+ if ((chptr = hash_find_channel(parv[2])) == NULL)
+ {
+ isnew = 1;
+ chptr = make_channel(parv[2]);
+ }
+
+ parabuf[0] = '\0';
+ oldts = chptr->channelts;
+ oldmode = &chptr->mode;
+
+ if (ConfigFileEntry.ignore_bogus_ts)
+ {
+ if (newts < 800000000)
+ {
+ sendto_realops_flags(UMODE_DEBUG, L_ALL,
+ "*** Bogus TS %lu on %s ignored from %s",
+ (unsigned long)newts, chptr->chname,
+ client_p->name);
+
+ newts = (oldts == 0) ? 0 : 800000000;
+ }
+ }
+ else
+ {
+ if (!newts && !isnew && oldts)
+ {
+ sendto_channel_local(ALL_MEMBERS, 0, chptr,
+ ":%s NOTICE %s :*** Notice -- TS for %s changed from %lu to 0",
+ me.name, chptr->chname, chptr->chname, (unsigned long)oldts);
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Server %s changing TS on %s from %lu to 0",
+ source_p->name, chptr->chname, (unsigned long)oldts);
+ }
+ }
+
+ if (isnew)
+ chptr->channelts = tstosend = newts;
+ else if (newts == 0 || oldts == 0)
+ chptr->channelts = tstosend = 0;
+ else if (newts == oldts)
+ tstosend = oldts;
+ else if (newts < oldts)
+ {
+ keep_our_modes = 0;
+ chptr->channelts = tstosend = newts;
+ }
+ else
+ {
+ keep_new_modes = 0;
+ tstosend = oldts;
+ }
+
+ if (!keep_new_modes)
+ mode = *oldmode;
+ else if (keep_our_modes)
+ {
+ mode.mode |= oldmode->mode;
+ if (oldmode->limit > mode.limit)
+ mode.limit = oldmode->limit;
+ if (strcmp(mode.key, oldmode->key) < 0)
+ strcpy(mode.key, oldmode->key);
+ }
+ set_final_mode(&mode, oldmode);
+ chptr->mode = mode;
+
+ /* Lost the TS, other side wins, so remove modes on this side */
+ if (!keep_our_modes)
+ {
+ remove_our_modes(chptr, source_p);
+
+ if (chptr->topic[0])
+ {
+ set_channel_topic(chptr, "", "", 0);
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s TOPIC %s :",
+ (IsHidden(source_p) ||
+ ConfigServerHide.hide_servers) ?
+ me.name : source_p->name, chptr->chname);
+ }
+
+ sendto_channel_local(ALL_MEMBERS, 0, chptr,
+ ":%s NOTICE %s :*** Notice -- TS for %s changed from %lu to %lu",
+ me.name, chptr->chname, chptr->chname,
+ (unsigned long)oldts, (unsigned long)newts);
+ }
+
+ if (*modebuf != '\0')
+ {
+ /* This _SHOULD_ be to ALL_MEMBERS
+ * It contains only +imnpstlk, etc */
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s MODE %s %s %s",
+ servername, chptr->chname, modebuf, parabuf);
+ }
+
+ if (parv[3][0] != '0' && keep_new_modes)
+ {
+ channel_modes(chptr, source_p, modebuf, parabuf);
+ }
+ else
+ {
+ modebuf[0] = '0';
+ modebuf[1] = '\0';
+ }
+
+ buflen = ircsprintf(nick_buf, ":%s SJOIN %lu %s %s %s:",
+ source_p->name, (unsigned long)tstosend,
+ chptr->chname, modebuf, parabuf);
+ nick_ptr = nick_buf + buflen;
+
+ buflen = ircsprintf(uid_buf, ":%s SJOIN %lu %s %s %s:",
+ ID(source_p), (unsigned long)tstosend,
+ chptr->chname, modebuf, parabuf);
+ uid_ptr = uid_buf + buflen;
+
+ /* check we can fit a nick on the end, as well as \r\n and a prefix "
+ * @%+", and a space.
+ */
+ if (buflen >= (IRCD_BUFSIZE - IRCD_MAX(NICKLEN, IDLEN) - 2 - 3 - 1))
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Long SJOIN from server: %s(via %s) (ignored)",
+ source_p->name, client_p->name);
+ return;
+ }
+
+ mbuf = modebuf;
+ sendbuf[0] = '\0';
+ pargs = 0;
+
+ *mbuf++ = '+';
+
+ s = parv[args + 4];
+ while (*s == ' ')
+ s++;
+ if ((p = strchr(s, ' ')) != NULL)
+ {
+ *p++ = '\0';
+ while (*p == ' ')
+ p++;
+ have_many_nicks = *p;
+ }
+
+ while (*s)
+ {
+ int valid_mode = 1;
+ fl = 0;
+
+ do
+ {
+ switch (*s)
+ {
+ case '@':
+ fl |= CHFL_CHANOP;
+ s++;
+ break;
+#ifdef HALFOPS
+ case '%':
+ fl |= CHFL_HALFOP;
+ s++;
+ break;
+#endif
+ case '+':
+ fl |= CHFL_VOICE;
+ s++;
+ break;
+ default:
+ valid_mode = 0;
+ break;
+ }
+ } while (valid_mode);
+
+ target_p = find_chasing(client_p, source_p, s, NULL);
+
+ /*
+ * if the client doesnt exist, or if its fake direction/server, skip.
+ * we cannot send ERR_NOSUCHNICK here because if its a UID, we cannot
+ * lookup the nick, and its better to never send the numeric than only
+ * sometimes.
+ */
+ if (target_p == NULL ||
+ target_p->from != client_p ||
+ !IsClient(target_p))
+ {
+ goto nextnick;
+ }
+
+ len_nick = strlen(target_p->name);
+ len_uid = strlen(ID(target_p));
+
+ np = nick_prefix;
+ up = uid_prefix;
+
+ if (keep_new_modes)
+ {
+ if (fl & CHFL_CHANOP)
+ {
+ *np++ = '@';
+ *up++ = '@';
+ len_nick++;
+ len_uid++;
+ }
+#ifdef HALFOPS
+ if (fl & CHFL_HALFOP)
+ {
+ *np++ = '%';
+ *up++ = '%';
+ len_nick++;
+ len_uid++;
+ }
+#endif
+ if (fl & CHFL_VOICE)
+ {
+ *np++ = '+';
+ *up++ = '+';
+ len_nick++;
+ len_uid++;
+ }
+ }
+ else
+ {
+ if (fl & (CHFL_CHANOP|CHFL_HALFOP))
+ fl = CHFL_DEOPPED;
+ else
+ fl = 0;
+ }
+ *np = *up = '\0';
+
+ if ((nick_ptr - nick_buf + len_nick) > (IRCD_BUFSIZE - 2))
+ {
+ sendto_server(client_p, 0, CAP_TS6, "%s", nick_buf);
+
+ buflen = ircsprintf(nick_buf, ":%s SJOIN %lu %s %s %s:",
+ source_p->name, (unsigned long)tstosend,
+ chptr->chname, modebuf, parabuf);
+ nick_ptr = nick_buf + buflen;
+ }
+
+ nick_ptr += ircsprintf(nick_ptr, "%s%s ", nick_prefix, target_p->name);
+
+ if ((uid_ptr - uid_buf + len_uid) > (IRCD_BUFSIZE - 2))
+ {
+ sendto_server(client_p, CAP_TS6, 0, "%s", uid_buf);
+
+ buflen = ircsprintf(uid_buf, ":%s SJOIN %lu %s %s %s:",
+ ID(source_p), (unsigned long)tstosend,
+ chptr->chname, modebuf, parabuf);
+ uid_ptr = uid_buf + buflen;
+ }
+
+ uid_ptr += ircsprintf(uid_ptr, "%s%s ", uid_prefix, ID(target_p));
+
+ if (!IsMember(target_p, chptr))
+ {
+ add_user_to_channel(chptr, target_p, fl, !have_many_nicks);
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s JOIN :%s",
+ target_p->name, target_p->username,
+ target_p->host, chptr->chname);
+ }
+
+ if (fl & CHFL_CHANOP)
+ {
+ *mbuf++ = 'o';
+ para[pargs++] = target_p->name;
+
+ if (pargs >= MAXMODEPARAMS)
+ {
+ /*
+ * Ok, the code is now going to "walk" through
+ * sendbuf, filling in para strings. So, I will use sptr
+ * to point into the sendbuf.
+ * Notice, that ircsprintf() returns the number of chars
+ * successfully inserted into string.
+ * - Dianora
+ */
+
+ sptr = sendbuf;
+ *mbuf = '\0';
+ for(lcount = 0; lcount < MAXMODEPARAMS; lcount++)
+ {
+ slen = ircsprintf(sptr, " %s", para[lcount]); /* see? */
+ sptr += slen; /* ready for next */
+ }
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s MODE %s %s%s",
+ servername, chptr->chname, modebuf, sendbuf);
+ mbuf = modebuf;
+ *mbuf++ = '+';
+
+ sendbuf[0] = '\0';
+ pargs = 0;
+ }
+ }
+#ifdef HALFOPS
+ if (fl & CHFL_HALFOP)
+ {
+ *mbuf++ = 'h';
+ para[pargs++] = target_p->name;
+
+ if (pargs >= MAXMODEPARAMS)
+ {
+ sptr = sendbuf;
+ *mbuf = '\0';
+ for(lcount = 0; lcount < MAXMODEPARAMS; lcount++)
+ {
+ slen = ircsprintf(sptr, " %s", para[lcount]);
+ sptr += slen;
+ }
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s MODE %s %s%s",
+ servername, chptr->chname, modebuf, sendbuf);
+
+ mbuf = modebuf;
+ *mbuf++ = '+';
+
+ sendbuf[0] = '\0';
+ pargs = 0;
+ }
+ }
+#endif
+ if (fl & CHFL_VOICE)
+ {
+ *mbuf++ = 'v';
+ para[pargs++] = target_p->name;
+
+ if (pargs >= MAXMODEPARAMS)
+ {
+ sptr = sendbuf;
+ *mbuf = '\0';
+ for (lcount = 0; lcount < MAXMODEPARAMS; lcount++)
+ {
+ slen = ircsprintf(sptr, " %s", para[lcount]);
+ sptr += slen;
+ }
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s MODE %s %s%s",
+ servername, chptr->chname, modebuf, sendbuf);
+
+ mbuf = modebuf;
+ *mbuf++ = '+';
+
+ sendbuf[0] = '\0';
+ pargs = 0;
+ }
+ }
+
+ nextnick:
+ if ((s = p) == NULL)
+ break;
+ while (*s == ' ')
+ s++;
+ if ((p = strchr(s, ' ')) != NULL)
+ {
+ *p++ = 0;
+ while (*p == ' ')
+ p++;
+ }
+ }
+
+ *mbuf = '\0';
+ *(nick_ptr - 1) = '\0';
+ *(uid_ptr - 1) = '\0';
+
+ /*
+ * checking for lcount < MAXMODEPARAMS at this time is wrong
+ * since the code has already verified above that pargs < MAXMODEPARAMS
+ * checking for para[lcount] != '\0' is also wrong, since
+ * there is no place where para[lcount] is set!
+ * - Dianora
+ */
+
+ if (pargs != 0)
+ {
+ sptr = sendbuf;
+
+ for (lcount = 0; lcount < pargs; lcount++)
+ {
+ slen = ircsprintf(sptr, " %s", para[lcount]);
+ sptr += slen;
+ }
+
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s MODE %s %s%s",
+ servername, chptr->chname, modebuf, sendbuf);
+ }
+
+ /* If this happens, its the result of a malformed SJOIN
+ * a remnant from the old persistent channel code. *sigh*
+ * Or it could be the result of a client just leaving
+ * and leaving us with a channel formed just as the client parts.
+ * - Dianora
+ */
+
+ if ((dlink_list_length(&chptr->members) == 0) && isnew)
+ {
+ destroy_channel(chptr);
+ return;
+ }
+
+ if (parv[4 + args][0] == '\0')
+ return;
+
+ /* relay the SJOIN to other servers */
+ DLINK_FOREACH(m, serv_list.head)
+ {
+ target_p = m->data;
+
+ if (target_p == client_p)
+ continue;
+
+ if (IsCapable(target_p, CAP_TS6))
+ sendto_one(target_p, "%s", uid_buf);
+ else
+ sendto_one(target_p, "%s", nick_buf);
+ }
+
+ if (HasID(source_p) && !keep_our_modes)
+ {
+ if (dlink_list_length(&chptr->banlist) > 0)
+ remove_ban_list(chptr, client_p, &chptr->banlist,
+ 'b', NOCAPS);
+
+ if (dlink_list_length(&chptr->exceptlist) > 0)
+ remove_ban_list(chptr, client_p, &chptr->exceptlist,
+ 'e', CAP_EX);
+
+ if (dlink_list_length(&chptr->invexlist) > 0)
+ remove_ban_list(chptr, client_p, &chptr->invexlist,
+ 'I', CAP_IE);
+ clear_ban_cache(chptr);
+ }
+}
+
+/* set_final_mode
+ *
+ * inputs - channel mode
+ * - old channel mode
+ * output - NONE
+ * side effects - walk through all the channel modes turning off modes
+ * that were on in oldmode but aren't on in mode.
+ * Then walk through turning on modes that are on in mode
+ * but were not set in oldmode.
+ */
+static void
+set_final_mode(struct Mode *mode, struct Mode *oldmode)
+{
+ const struct mode_letter *tab;
+ char *pbuf = parabuf;
+ int len;
+
+ *mbuf++ = '-';
+
+ for (tab = chan_modes; tab->letter; ++tab)
+ {
+ if ((tab->mode & oldmode->mode) &&
+ !(tab->mode & mode->mode))
+ *mbuf++ = tab->letter;
+ }
+
+ if (oldmode->limit != 0 && mode->limit == 0)
+ *mbuf++ = 'l';
+
+ if (oldmode->key[0] && !mode->key[0])
+ {
+ *mbuf++ = 'k';
+ len = ircsprintf(pbuf, "%s ", oldmode->key);
+ pbuf += len;
+ pargs++;
+ }
+
+ if (*(mbuf-1) == '-')
+ *(mbuf-1) = '+';
+ else
+ *mbuf++ = '+';
+
+ for (tab = chan_modes; tab->letter; ++tab)
+ {
+ if ((tab->mode & mode->mode) &&
+ !(tab->mode & oldmode->mode))
+ *mbuf++ = tab->letter;
+ }
+
+ if (mode->limit != 0 && oldmode->limit != mode->limit)
+ {
+ *mbuf++ = 'l';
+ len = ircsprintf(pbuf, "%d ", mode->limit);
+ pbuf += len;
+ pargs++;
+ }
+
+ if (mode->key[0] && strcmp(oldmode->key, mode->key))
+ {
+ *mbuf++ = 'k';
+ len = ircsprintf(pbuf, "%s ", mode->key);
+ pbuf += len;
+ pargs++;
+ }
+ if (*(mbuf-1) == '+')
+ *(mbuf-1) = '\0';
+ else
+ *mbuf = '\0';
+}
+
+/* remove_our_modes()
+ *
+ * inputs - pointer to channel to remove modes from
+ * - client pointer
+ * output - NONE
+ * side effects - Go through the local members, remove all their
+ * chanop modes etc., this side lost the TS.
+ */
+static void
+remove_our_modes(struct Channel *chptr, struct Client *source_p)
+{
+ remove_a_mode(chptr, source_p, CHFL_CHANOP, 'o');
+#ifdef HALFOPS
+ remove_a_mode(chptr, source_p, CHFL_HALFOP, 'h');
+#endif
+ remove_a_mode(chptr, source_p, CHFL_VOICE, 'v');
+}
+
+/* remove_a_mode()
+ *
+ * inputs - pointer to channel
+ * - server or client removing the mode
+ * - mask o/h/v mask to be removed
+ * - flag o/h/v to be removed
+ * output - NONE
+ * side effects - remove ONE mode from all members of a channel
+ */
+static void
+remove_a_mode(struct Channel *chptr, struct Client *source_p,
+ int mask, char flag)
+{
+ dlink_node *ptr;
+ struct Membership *ms;
+ char lmodebuf[MODEBUFLEN];
+ char *sp=sendbuf;
+ const char *lpara[MAXMODEPARAMS];
+ int count = 0;
+ int i;
+ int l;
+
+ mbuf = lmodebuf;
+ *mbuf++ = '-';
+ *sp = '\0';
+
+ DLINK_FOREACH(ptr, chptr->members.head)
+ {
+ ms = ptr->data;
+
+ if ((ms->flags & mask) == 0)
+ continue;
+
+ ms->flags &= ~mask;
+
+ lpara[count++] = ms->client_p->name;
+
+ *mbuf++ = flag;
+
+ if (count >= MAXMODEPARAMS)
+ {
+ for(i = 0; i < MAXMODEPARAMS; i++)
+ {
+ l = ircsprintf(sp, " %s", lpara[i]);
+ sp += l;
+ }
+
+ *mbuf = '\0';
+ sendto_channel_local(ALL_MEMBERS, 0, chptr,
+ ":%s MODE %s %s%s",
+ (IsHidden(source_p) ||
+ ConfigServerHide.hide_servers) ?
+ me.name : source_p->name,
+ chptr->chname, lmodebuf, sendbuf);
+ mbuf = lmodebuf;
+ *mbuf++ = '-';
+ count = 0;
+ sp = sendbuf;
+ *sp = '\0';
+ }
+ }
+
+ if (count != 0)
+ {
+ *mbuf = '\0';
+ for(i = 0; i < count; i++)
+ {
+ l = ircsprintf(sp, " %s", lpara[i]);
+ sp += l;
+ }
+ sendto_channel_local(ALL_MEMBERS, 0, chptr,
+ ":%s MODE %s %s%s",
+ (IsHidden(source_p) || ConfigServerHide.hide_servers) ?
+ me.name : source_p->name,
+ chptr->chname, lmodebuf, sendbuf);
+ }
+}
+
+/* remove_ban_list()
+ *
+ * inputs - channel, source, list to remove, char of mode, caps required
+ * outputs - none
+ * side effects - given ban list is removed, modes are sent to local clients and
+ * non-ts6 servers linked through another uplink other than source_p
+ */
+static void
+remove_ban_list(struct Channel *chptr, struct Client *source_p,
+ dlink_list *list, char c, int cap)
+{
+ char lmodebuf[MODEBUFLEN];
+ char lparabuf[IRCD_BUFSIZE];
+ struct Ban *banptr = NULL;
+ dlink_node *ptr = NULL;
+ dlink_node *next_ptr = NULL;
+ char *pbuf = NULL;
+ int count = 0;
+ int cur_len, mlen, plen;
+
+ pbuf = lparabuf;
+
+ cur_len = mlen = ircsprintf(lmodebuf, ":%s MODE %s -",
+ source_p->name, chptr->chname);
+ mbuf = lmodebuf + mlen;
+
+ DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
+ {
+ banptr = ptr->data;
+
+ plen = banptr->len + 4; /* another +b and "!@ " */
+ if (count >= MAXMODEPARAMS ||
+ (cur_len + 1 /* space between */ + (plen - 1)) > IRCD_BUFSIZE - 2)
+ {
+ /* NUL-terminate and remove trailing space */
+ *mbuf = *(pbuf - 1) = '\0';
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, "%s %s",
+ lmodebuf, lparabuf);
+ sendto_server(source_p, cap, CAP_TS6,
+ "%s %s", lmodebuf, lparabuf);
+
+ cur_len = mlen;
+ mbuf = lmodebuf + mlen;
+ pbuf = lparabuf;
+ count = 0;
+ }
+
+ *mbuf++ = c;
+ cur_len += plen;
+ pbuf += ircsprintf(pbuf, "%s!%s@%s ", banptr->name, banptr->username,
+ banptr->host);
+ ++count;
+
+ remove_ban(banptr, list);
+ }
+
+ *mbuf = *(pbuf - 1) = '\0';
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, "%s %s", lmodebuf, lparabuf);
+ sendto_server(source_p, cap, CAP_TS6,
+ "%s %s", lmodebuf, lparabuf);
+}
+
+static struct Message sjoin_msgtab = {
+ "SJOIN", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_ignore, ms_sjoin, m_ignore, m_ignore, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&sjoin_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&sjoin_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = MODULE_FLAG_CORE
+};
diff --git a/modules/core/m_squit.c b/modules/core/m_squit.c
new file mode 100644
index 0000000..0995c47
--- /dev/null
+++ b/modules/core/m_squit.c
@@ -0,0 +1,184 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_squit.c: Makes a server quit.
+ *
+ * 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 "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "conf.h"
+#include "log.h"
+#include "s_serv.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+
+
+/* mo_squit - SQUIT message handler
+ * parv[0] = sender prefix
+ * parv[1] = server name
+ * parv[2] = comment
+ */
+static void
+mo_squit(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *target_p = NULL;
+ struct Client *p;
+ dlink_node *ptr;
+ char *comment;
+ const char *server;
+ char def_reason[] = "No reason";
+
+ if (parc < 2 || EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, "SQUIT");
+ return;
+ }
+
+ server = parv[1];
+
+ /* The following allows wild cards in SQUIT. Only
+ * useful when the command is issued by an oper.
+ */
+ DLINK_FOREACH(ptr, global_serv_list.head)
+ {
+ p = ptr->data;
+
+ if (IsServer(p) || IsMe(p))
+ {
+ if (match(server, p->name))
+ {
+ target_p = p;
+ break;
+ }
+ }
+ }
+
+ if ((target_p == NULL) || IsMe(target_p))
+ {
+ sendto_one(source_p, form_str(ERR_NOSUCHSERVER),
+ me.name, source_p->name, server);
+ return;
+ }
+
+ if (!MyConnect(target_p) && !HasOFlag(source_p, OPER_FLAG_REMOTE))
+ {
+ sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
+ me.name, source_p->name);
+ return;
+ }
+
+ comment = (parc > 2 && parv[2]) ? parv[2] : def_reason;
+
+ if (strlen(comment) > (size_t)REASONLEN)
+ comment[REASONLEN] = '\0';
+
+ if (MyConnect(target_p))
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL, "Received SQUIT %s from %s (%s)",
+ target_p->name, get_client_name(source_p, HIDE_IP), comment);
+ ilog(LOG_TYPE_IRCD, "Received SQUIT %s from %s (%s)",
+ target_p->name, get_client_name(source_p, HIDE_IP), comment);
+ }
+
+ exit_client(target_p, source_p, comment);
+}
+
+/** NOTE: I removed wildcard lookups here, because a wildcarded
+ ** SQUIT should/can never happen in ms_squit. -Michael
+ **/
+
+/* ms_squit - SQUIT message handler
+ * parv[0] = sender prefix
+ * parv[1] = server name
+ * parv[2] = comment
+ */
+static void
+ms_squit(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *target_p = NULL;
+ const char *comment = NULL;
+
+ if (parc < 2 || EmptyString(parv[parc - 1]))
+ return;
+
+ if ((target_p = hash_find_server(parv[1])) == NULL)
+ return;
+
+ if (!IsServer(target_p) && !IsMe(target_p))
+ return;
+
+ if (IsMe(target_p))
+ target_p = client_p;
+
+ comment = (parc > 2 && parv[parc - 1]) ? parv[parc - 1] : client_p->name;
+
+ if (MyConnect(target_p))
+ {
+ sendto_wallops_flags(UMODE_WALLOP, &me, "Remote SQUIT %s from %s (%s)",
+ target_p->name, source_p->name, comment);
+ sendto_server(NULL, CAP_TS6, NOCAPS,
+ ":%s WALLOPS :Remote SQUIT %s from %s (%s)",
+ me.id, target_p->name, source_p->name, comment);
+ sendto_server(NULL, NOCAPS, CAP_TS6,
+ ":%s WALLOPS :Remote SQUIT %s from %s (%s)",
+ me.name, target_p->name, source_p->name, comment);
+ ilog(LOG_TYPE_IRCD, "SQUIT From %s : %s (%s)", source_p->name,
+ target_p->name, comment);
+ }
+
+ exit_client(target_p, source_p, comment);
+}
+
+static struct Message squit_msgtab = {
+ "SQUIT", 0, 0, 1, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_not_oper, ms_squit, m_ignore, mo_squit, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&squit_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&squit_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = MODULE_FLAG_CORE
+};