summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/Makefile.am192
-rw-r--r--modules/Makefile.in1495
-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
-rw-r--r--modules/m_accept.c221
-rw-r--r--modules/m_admin.c157
-rw-r--r--modules/m_away.c144
-rw-r--r--modules/m_cap.c433
-rw-r--r--modules/m_capab.c89
-rw-r--r--modules/m_challenge.c207
-rw-r--r--modules/m_close.c90
-rw-r--r--modules/m_connect.c322
-rw-r--r--modules/m_dline.c592
-rw-r--r--modules/m_encap.c138
-rw-r--r--modules/m_eob.c76
-rw-r--r--modules/m_etrace.c233
-rw-r--r--modules/m_gline.c575
-rw-r--r--modules/m_globops.c112
-rw-r--r--modules/m_hash.c190
-rw-r--r--modules/m_help.c230
-rw-r--r--modules/m_info.c733
-rw-r--r--modules/m_invite.c179
-rw-r--r--modules/m_ison.c134
-rw-r--r--modules/m_kline.c563
-rw-r--r--modules/m_knock.c178
-rw-r--r--modules/m_links.c191
-rw-r--r--modules/m_list.c200
-rw-r--r--modules/m_locops.c107
-rw-r--r--modules/m_lusers.c113
-rw-r--r--modules/m_map.c184
-rw-r--r--modules/m_module.c263
-rw-r--r--modules/m_motd.c130
-rw-r--r--modules/m_names.c196
-rw-r--r--modules/m_oper.c161
-rw-r--r--modules/m_operwall.c137
-rw-r--r--modules/m_pass.c115
-rw-r--r--modules/m_ping.c149
-rw-r--r--modules/m_pong.c135
-rw-r--r--modules/m_post.c87
-rw-r--r--modules/m_rehash.c136
-rw-r--r--modules/m_restart.c98
-rw-r--r--modules/m_resv.c434
-rw-r--r--modules/m_services.c355
-rw-r--r--modules/m_set.c616
-rw-r--r--modules/m_stats.c1533
-rw-r--r--modules/m_svinfo.c143
-rw-r--r--modules/m_svsmode.c208
-rw-r--r--modules/m_svsnick.c148
-rw-r--r--modules/m_tburst.c143
-rw-r--r--modules/m_testline.c258
-rw-r--r--modules/m_testmask.c131
-rw-r--r--modules/m_time.c99
-rw-r--r--modules/m_topic.c171
-rw-r--r--modules/m_trace.c448
-rw-r--r--modules/m_user.c134
-rw-r--r--modules/m_userhost.c127
-rw-r--r--modules/m_users.c120
-rw-r--r--modules/m_version.c189
-rw-r--r--modules/m_wallops.c112
-rw-r--r--modules/m_watch.c269
-rw-r--r--modules/m_who.c368
-rw-r--r--modules/m_whois.c421
-rw-r--r--modules/m_whowas.c175
-rw-r--r--modules/m_xline.c467
77 files changed, 23218 insertions, 0 deletions
diff --git a/modules/Makefile.am b/modules/Makefile.am
new file mode 100644
index 0000000..e25e3a8
--- /dev/null
+++ b/modules/Makefile.am
@@ -0,0 +1,192 @@
+AUTOMAKE_OPTIONS = foreign
+MODULE_FLAGS = -module -avoid-version
+SUBDIRS = core
+
+AM_CPPFLAGS = -I$(top_srcdir)/include
+modulesdir = $(pkglibdir)/modules/autoload
+
+modules_LTLIBRARIES = m_accept.la \
+ m_admin.la \
+ m_away.la \
+ m_capab.la \
+ m_cap.la \
+ m_challenge.la \
+ m_close.la \
+ m_connect.la \
+ m_dline.la \
+ m_encap.la \
+ m_eob.la \
+ m_etrace.la \
+ m_gline.la \
+ m_globops.la \
+ m_hash.la \
+ m_help.la \
+ m_info.la \
+ m_invite.la \
+ m_ison.la \
+ m_kline.la \
+ m_knock.la \
+ m_links.la \
+ m_list.la \
+ m_locops.la \
+ m_lusers.la \
+ m_map.la \
+ m_module.la \
+ m_motd.la \
+ m_names.la \
+ m_oper.la \
+ m_operwall.la \
+ m_pass.la \
+ m_ping.la \
+ m_pong.la \
+ m_post.la \
+ m_rehash.la \
+ m_restart.la \
+ m_resv.la \
+ m_set.la \
+ m_services.la \
+ m_stats.la \
+ m_svinfo.la \
+ m_svsmode.la \
+ m_svsnick.la \
+ m_tburst.la \
+ m_testline.la \
+ m_testmask.la \
+ m_time.la \
+ m_topic.la \
+ m_trace.la \
+ m_user.la \
+ m_userhost.la \
+ m_users.la \
+ m_version.la \
+ m_wallops.la \
+ m_watch.la \
+ m_who.la \
+ m_whois.la \
+ m_whowas.la \
+ m_xline.la
+
+
+m_challenge_la_LDFLAGS = $(MODULE_FLAGS)
+m_accept_la_LDFLAGS = $(MODULE_FLAGS)
+m_admin_la_LDFLAGS = $(MODULE_FLAGS)
+m_away_la_LDFLAGS = $(MODULE_FLAGS)
+m_capab_la_LDFLAGS = $(MODULE_FLAGS)
+m_cap_la_LDFLAGS = $(MODULE_FLAGS)
+m_close_la_LDFLAGS = $(MODULE_FLAGS)
+m_connect_la_LDFLAGS = $(MODULE_FLAGS)
+m_dline_la_LDFLAGS = $(MODULE_FLAGS)
+m_encap_la_LDFLAGS = $(MODULE_FLAGS)
+m_eob_la_LDFLAGS = $(MODULE_FLAGS)
+m_etrace_la_LDFLAGS = $(MODULE_FLAGS)
+m_gline_la_LDFLAGS = $(MODULE_FLAGS)
+m_globops_la_LDFLAGS = $(MODULE_FLAGS)
+m_hash_la_LDFLAGS = $(MODULE_FLAGS)
+m_help_la_LDFLAGS = $(MODULE_FLAGS)
+m_info_la_LDFLAGS = $(MODULE_FLAGS)
+m_invite_la_LDFLAGS = $(MODULE_FLAGS)
+m_ison_la_LDFLAGS = $(MODULE_FLAGS)
+m_kline_la_LDFLAGS = $(MODULE_FLAGS)
+m_knock_la_LDFLAGS = $(MODULE_FLAGS)
+m_links_la_LDFLAGS = $(MODULE_FLAGS)
+m_list_la_LDFLAGS = $(MODULE_FLAGS)
+m_locops_la_LDFLAGS = $(MODULE_FLAGS)
+m_lusers_la_LDFLAGS = $(MODULE_FLAGS)
+m_map_la_LDFLAGS = $(MODULE_FLAGS)
+m_module_la_LDFLAGS = $(MODULE_FLAGS)
+m_motd_la_LDFLAGS = $(MODULE_FLAGS)
+m_names_la_LDFLAGS = $(MODULE_FLAGS)
+m_oper_la_LDFLAGS = $(MODULE_FLAGS)
+m_operwall_la_LDFLAGS = $(MODULE_FLAGS)
+m_pass_la_LDFLAGS = $(MODULE_FLAGS)
+m_ping_la_LDFLAGS = $(MODULE_FLAGS)
+m_pong_la_LDFLAGS = $(MODULE_FLAGS)
+m_post_la_LDFLAGS = $(MODULE_FLAGS)
+m_rehash_la_LDFLAGS = $(MODULE_FLAGS)
+m_restart_la_LDFLAGS = $(MODULE_FLAGS)
+m_resv_la_LDFLAGS = $(MODULE_FLAGS)
+m_set_la_LDFLAGS = $(MODULE_FLAGS)
+m_services_la_LDFLAGS = $(MODULE_FLAGS)
+m_stats_la_LDFLAGS = $(MODULE_FLAGS)
+m_svinfo_la_LDFLAGS = $(MODULE_FLAGS)
+m_svsmode_la_LDFLAGS = $(MODULE_FLAGS)
+m_svsnick_la_LDFLAGS = $(MODULE_FLAGS)
+m_tburst_la_LDFLAGS = $(MODULE_FLAGS)
+m_testline_la_LDFLAGS = $(MODULE_FLAGS)
+m_testmask_la_LDFLAGS = $(MODULE_FLAGS)
+m_time_la_LDFLAGS = $(MODULE_FLAGS)
+m_topic_la_LDFLAGS = $(MODULE_FLAGS)
+m_trace_la_LDFLAGS = $(MODULE_FLAGS)
+m_user_la_LDFLAGS = $(MODULE_FLAGS)
+m_userhost_la_LDFLAGS = $(MODULE_FLAGS)
+m_users_la_LDFLAGS = $(MODULE_FLAGS)
+m_version_la_LDFLAGS = $(MODULE_FLAGS)
+m_wallops_la_LDFLAGS = $(MODULE_FLAGS)
+m_watch_la_LDFLAGS = $(MODULE_FLAGS)
+m_who_la_LDFLAGS = $(MODULE_FLAGS)
+m_whois_la_LDFLAGS = $(MODULE_FLAGS)
+m_whowas_la_LDFLAGS = $(MODULE_FLAGS)
+m_xline_la_LDFLAGS = $(MODULE_FLAGS)
+
+m_accept_la_SOURCES = m_accept.c
+m_admin_la_SOURCES = m_admin.c
+m_away_la_SOURCES = m_away.c
+m_capab_la_SOURCES = m_capab.c
+m_cap_la_SOURCES = m_cap.c
+m_challenge_la_SOURCES = m_challenge.c
+m_close_la_SOURCES = m_close.c
+m_connect_la_SOURCES = m_connect.c
+m_dline_la_SOURCES = m_dline.c
+m_encap_la_SOURCES = m_encap.c
+m_eob_la_SOURCES = m_eob.c
+m_etrace_la_SOURCES = m_etrace.c
+m_gline_la_SOURCES = m_gline.c
+m_globops_la_SOURCES = m_globops.c
+m_hash_la_SOURCES = m_hash.c
+m_help_la_SOURCES = m_help.c
+m_info_la_SOURCES = m_info.c
+m_invite_la_SOURCES = m_invite.c
+m_ison_la_SOURCES = m_ison.c
+m_kline_la_SOURCES = m_kline.c
+m_knock_la_SOURCES = m_knock.c
+m_links_la_SOURCES = m_links.c
+m_list_la_SOURCES = m_list.c
+m_locops_la_SOURCES = m_locops.c
+m_lusers_la_SOURCES = m_lusers.c
+m_map_la_SOURCES = m_map.c
+m_module_la_SOURCES = m_module.c
+m_motd_la_SOURCES = m_motd.c
+m_names_la_SOURCES = m_names.c
+m_oper_la_SOURCES = m_oper.c
+m_operwall_la_SOURCES = m_operwall.c
+m_pass_la_SOURCES = m_pass.c
+m_ping_la_SOURCES = m_ping.c
+m_pong_la_SOURCES = m_pong.c
+m_post_la_SOURCES = m_post.c
+m_rehash_la_SOURCES = m_rehash.c
+m_restart_la_SOURCES = m_restart.c
+m_resv_la_SOURCES = m_resv.c
+m_set_la_SOURCES = m_set.c
+m_services_la_SOURCES = m_services.c
+m_stats_la_SOURCES = m_stats.c
+m_svinfo_la_SOURCES = m_svinfo.c
+m_svsmode_la_SOURCES = m_svsmode.c
+m_svsnick_la_SOURCES = m_svsnick.c
+m_tburst_la_SOURCES = m_tburst.c
+m_testline_la_SOURCES = m_testline.c
+m_testmask_la_SOURCES = m_testmask.c
+m_time_la_SOURCES = m_time.c
+m_topic_la_SOURCES = m_topic.c
+m_trace_la_SOURCES = m_trace.c
+m_user_la_SOURCES = m_user.c
+m_userhost_la_SOURCES = m_userhost.c
+m_users_la_SOURCES = m_users.c
+m_version_la_SOURCES = m_version.c
+m_wallops_la_SOURCES = m_wallops.c
+m_watch_la_SOURCES = m_watch.c
+m_who_la_SOURCES = m_who.c
+m_whois_la_SOURCES = m_whois.c
+m_whowas_la_SOURCES = m_whowas.c
+m_xline_la_SOURCES = m_xline.c
+
+modules: $(modules_LTLIBRARIES)
diff --git a/modules/Makefile.in b/modules/Makefile.in
new file mode 100644
index 0000000..1f6cb89
--- /dev/null
+++ b/modules/Makefile.in
@@ -0,0 +1,1495 @@
+# 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
+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_accept_la_LIBADD =
+am_m_accept_la_OBJECTS = m_accept.lo
+m_accept_la_OBJECTS = $(am_m_accept_la_OBJECTS)
+m_accept_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_accept_la_LDFLAGS) $(LDFLAGS) -o $@
+m_admin_la_LIBADD =
+am_m_admin_la_OBJECTS = m_admin.lo
+m_admin_la_OBJECTS = $(am_m_admin_la_OBJECTS)
+m_admin_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_admin_la_LDFLAGS) $(LDFLAGS) -o $@
+m_away_la_LIBADD =
+am_m_away_la_OBJECTS = m_away.lo
+m_away_la_OBJECTS = $(am_m_away_la_OBJECTS)
+m_away_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_away_la_LDFLAGS) $(LDFLAGS) -o $@
+m_cap_la_LIBADD =
+am_m_cap_la_OBJECTS = m_cap.lo
+m_cap_la_OBJECTS = $(am_m_cap_la_OBJECTS)
+m_cap_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(m_cap_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+m_capab_la_LIBADD =
+am_m_capab_la_OBJECTS = m_capab.lo
+m_capab_la_OBJECTS = $(am_m_capab_la_OBJECTS)
+m_capab_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_capab_la_LDFLAGS) $(LDFLAGS) -o $@
+m_challenge_la_LIBADD =
+am_m_challenge_la_OBJECTS = m_challenge.lo
+m_challenge_la_OBJECTS = $(am_m_challenge_la_OBJECTS)
+m_challenge_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_challenge_la_LDFLAGS) $(LDFLAGS) -o $@
+m_close_la_LIBADD =
+am_m_close_la_OBJECTS = m_close.lo
+m_close_la_OBJECTS = $(am_m_close_la_OBJECTS)
+m_close_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_close_la_LDFLAGS) $(LDFLAGS) -o $@
+m_connect_la_LIBADD =
+am_m_connect_la_OBJECTS = m_connect.lo
+m_connect_la_OBJECTS = $(am_m_connect_la_OBJECTS)
+m_connect_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_connect_la_LDFLAGS) $(LDFLAGS) -o $@
+m_dline_la_LIBADD =
+am_m_dline_la_OBJECTS = m_dline.lo
+m_dline_la_OBJECTS = $(am_m_dline_la_OBJECTS)
+m_dline_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_dline_la_LDFLAGS) $(LDFLAGS) -o $@
+m_encap_la_LIBADD =
+am_m_encap_la_OBJECTS = m_encap.lo
+m_encap_la_OBJECTS = $(am_m_encap_la_OBJECTS)
+m_encap_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_encap_la_LDFLAGS) $(LDFLAGS) -o $@
+m_eob_la_LIBADD =
+am_m_eob_la_OBJECTS = m_eob.lo
+m_eob_la_OBJECTS = $(am_m_eob_la_OBJECTS)
+m_eob_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(m_eob_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+m_etrace_la_LIBADD =
+am_m_etrace_la_OBJECTS = m_etrace.lo
+m_etrace_la_OBJECTS = $(am_m_etrace_la_OBJECTS)
+m_etrace_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_etrace_la_LDFLAGS) $(LDFLAGS) -o $@
+m_gline_la_LIBADD =
+am_m_gline_la_OBJECTS = m_gline.lo
+m_gline_la_OBJECTS = $(am_m_gline_la_OBJECTS)
+m_gline_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_gline_la_LDFLAGS) $(LDFLAGS) -o $@
+m_globops_la_LIBADD =
+am_m_globops_la_OBJECTS = m_globops.lo
+m_globops_la_OBJECTS = $(am_m_globops_la_OBJECTS)
+m_globops_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_globops_la_LDFLAGS) $(LDFLAGS) -o $@
+m_hash_la_LIBADD =
+am_m_hash_la_OBJECTS = m_hash.lo
+m_hash_la_OBJECTS = $(am_m_hash_la_OBJECTS)
+m_hash_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_hash_la_LDFLAGS) $(LDFLAGS) -o $@
+m_help_la_LIBADD =
+am_m_help_la_OBJECTS = m_help.lo
+m_help_la_OBJECTS = $(am_m_help_la_OBJECTS)
+m_help_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_help_la_LDFLAGS) $(LDFLAGS) -o $@
+m_info_la_LIBADD =
+am_m_info_la_OBJECTS = m_info.lo
+m_info_la_OBJECTS = $(am_m_info_la_OBJECTS)
+m_info_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_info_la_LDFLAGS) $(LDFLAGS) -o $@
+m_invite_la_LIBADD =
+am_m_invite_la_OBJECTS = m_invite.lo
+m_invite_la_OBJECTS = $(am_m_invite_la_OBJECTS)
+m_invite_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_invite_la_LDFLAGS) $(LDFLAGS) -o $@
+m_ison_la_LIBADD =
+am_m_ison_la_OBJECTS = m_ison.lo
+m_ison_la_OBJECTS = $(am_m_ison_la_OBJECTS)
+m_ison_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_ison_la_LDFLAGS) $(LDFLAGS) -o $@
+m_kline_la_LIBADD =
+am_m_kline_la_OBJECTS = m_kline.lo
+m_kline_la_OBJECTS = $(am_m_kline_la_OBJECTS)
+m_kline_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_kline_la_LDFLAGS) $(LDFLAGS) -o $@
+m_knock_la_LIBADD =
+am_m_knock_la_OBJECTS = m_knock.lo
+m_knock_la_OBJECTS = $(am_m_knock_la_OBJECTS)
+m_knock_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_knock_la_LDFLAGS) $(LDFLAGS) -o $@
+m_links_la_LIBADD =
+am_m_links_la_OBJECTS = m_links.lo
+m_links_la_OBJECTS = $(am_m_links_la_OBJECTS)
+m_links_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_links_la_LDFLAGS) $(LDFLAGS) -o $@
+m_list_la_LIBADD =
+am_m_list_la_OBJECTS = m_list.lo
+m_list_la_OBJECTS = $(am_m_list_la_OBJECTS)
+m_list_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_list_la_LDFLAGS) $(LDFLAGS) -o $@
+m_locops_la_LIBADD =
+am_m_locops_la_OBJECTS = m_locops.lo
+m_locops_la_OBJECTS = $(am_m_locops_la_OBJECTS)
+m_locops_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_locops_la_LDFLAGS) $(LDFLAGS) -o $@
+m_lusers_la_LIBADD =
+am_m_lusers_la_OBJECTS = m_lusers.lo
+m_lusers_la_OBJECTS = $(am_m_lusers_la_OBJECTS)
+m_lusers_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_lusers_la_LDFLAGS) $(LDFLAGS) -o $@
+m_map_la_LIBADD =
+am_m_map_la_OBJECTS = m_map.lo
+m_map_la_OBJECTS = $(am_m_map_la_OBJECTS)
+m_map_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(m_map_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+m_module_la_LIBADD =
+am_m_module_la_OBJECTS = m_module.lo
+m_module_la_OBJECTS = $(am_m_module_la_OBJECTS)
+m_module_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_module_la_LDFLAGS) $(LDFLAGS) -o $@
+m_motd_la_LIBADD =
+am_m_motd_la_OBJECTS = m_motd.lo
+m_motd_la_OBJECTS = $(am_m_motd_la_OBJECTS)
+m_motd_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_motd_la_LDFLAGS) $(LDFLAGS) -o $@
+m_names_la_LIBADD =
+am_m_names_la_OBJECTS = m_names.lo
+m_names_la_OBJECTS = $(am_m_names_la_OBJECTS)
+m_names_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_names_la_LDFLAGS) $(LDFLAGS) -o $@
+m_oper_la_LIBADD =
+am_m_oper_la_OBJECTS = m_oper.lo
+m_oper_la_OBJECTS = $(am_m_oper_la_OBJECTS)
+m_oper_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_oper_la_LDFLAGS) $(LDFLAGS) -o $@
+m_operwall_la_LIBADD =
+am_m_operwall_la_OBJECTS = m_operwall.lo
+m_operwall_la_OBJECTS = $(am_m_operwall_la_OBJECTS)
+m_operwall_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_operwall_la_LDFLAGS) $(LDFLAGS) -o $@
+m_pass_la_LIBADD =
+am_m_pass_la_OBJECTS = m_pass.lo
+m_pass_la_OBJECTS = $(am_m_pass_la_OBJECTS)
+m_pass_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_pass_la_LDFLAGS) $(LDFLAGS) -o $@
+m_ping_la_LIBADD =
+am_m_ping_la_OBJECTS = m_ping.lo
+m_ping_la_OBJECTS = $(am_m_ping_la_OBJECTS)
+m_ping_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_ping_la_LDFLAGS) $(LDFLAGS) -o $@
+m_pong_la_LIBADD =
+am_m_pong_la_OBJECTS = m_pong.lo
+m_pong_la_OBJECTS = $(am_m_pong_la_OBJECTS)
+m_pong_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_pong_la_LDFLAGS) $(LDFLAGS) -o $@
+m_post_la_LIBADD =
+am_m_post_la_OBJECTS = m_post.lo
+m_post_la_OBJECTS = $(am_m_post_la_OBJECTS)
+m_post_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_post_la_LDFLAGS) $(LDFLAGS) -o $@
+m_rehash_la_LIBADD =
+am_m_rehash_la_OBJECTS = m_rehash.lo
+m_rehash_la_OBJECTS = $(am_m_rehash_la_OBJECTS)
+m_rehash_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_rehash_la_LDFLAGS) $(LDFLAGS) -o $@
+m_restart_la_LIBADD =
+am_m_restart_la_OBJECTS = m_restart.lo
+m_restart_la_OBJECTS = $(am_m_restart_la_OBJECTS)
+m_restart_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_restart_la_LDFLAGS) $(LDFLAGS) -o $@
+m_resv_la_LIBADD =
+am_m_resv_la_OBJECTS = m_resv.lo
+m_resv_la_OBJECTS = $(am_m_resv_la_OBJECTS)
+m_resv_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_resv_la_LDFLAGS) $(LDFLAGS) -o $@
+m_services_la_LIBADD =
+am_m_services_la_OBJECTS = m_services.lo
+m_services_la_OBJECTS = $(am_m_services_la_OBJECTS)
+m_services_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_services_la_LDFLAGS) $(LDFLAGS) -o $@
+m_set_la_LIBADD =
+am_m_set_la_OBJECTS = m_set.lo
+m_set_la_OBJECTS = $(am_m_set_la_OBJECTS)
+m_set_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(m_set_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+m_stats_la_LIBADD =
+am_m_stats_la_OBJECTS = m_stats.lo
+m_stats_la_OBJECTS = $(am_m_stats_la_OBJECTS)
+m_stats_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_stats_la_LDFLAGS) $(LDFLAGS) -o $@
+m_svinfo_la_LIBADD =
+am_m_svinfo_la_OBJECTS = m_svinfo.lo
+m_svinfo_la_OBJECTS = $(am_m_svinfo_la_OBJECTS)
+m_svinfo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_svinfo_la_LDFLAGS) $(LDFLAGS) -o $@
+m_svsmode_la_LIBADD =
+am_m_svsmode_la_OBJECTS = m_svsmode.lo
+m_svsmode_la_OBJECTS = $(am_m_svsmode_la_OBJECTS)
+m_svsmode_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_svsmode_la_LDFLAGS) $(LDFLAGS) -o $@
+m_svsnick_la_LIBADD =
+am_m_svsnick_la_OBJECTS = m_svsnick.lo
+m_svsnick_la_OBJECTS = $(am_m_svsnick_la_OBJECTS)
+m_svsnick_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_svsnick_la_LDFLAGS) $(LDFLAGS) -o $@
+m_tburst_la_LIBADD =
+am_m_tburst_la_OBJECTS = m_tburst.lo
+m_tburst_la_OBJECTS = $(am_m_tburst_la_OBJECTS)
+m_tburst_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_tburst_la_LDFLAGS) $(LDFLAGS) -o $@
+m_testline_la_LIBADD =
+am_m_testline_la_OBJECTS = m_testline.lo
+m_testline_la_OBJECTS = $(am_m_testline_la_OBJECTS)
+m_testline_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_testline_la_LDFLAGS) $(LDFLAGS) -o $@
+m_testmask_la_LIBADD =
+am_m_testmask_la_OBJECTS = m_testmask.lo
+m_testmask_la_OBJECTS = $(am_m_testmask_la_OBJECTS)
+m_testmask_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_testmask_la_LDFLAGS) $(LDFLAGS) -o $@
+m_time_la_LIBADD =
+am_m_time_la_OBJECTS = m_time.lo
+m_time_la_OBJECTS = $(am_m_time_la_OBJECTS)
+m_time_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_time_la_LDFLAGS) $(LDFLAGS) -o $@
+m_topic_la_LIBADD =
+am_m_topic_la_OBJECTS = m_topic.lo
+m_topic_la_OBJECTS = $(am_m_topic_la_OBJECTS)
+m_topic_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_topic_la_LDFLAGS) $(LDFLAGS) -o $@
+m_trace_la_LIBADD =
+am_m_trace_la_OBJECTS = m_trace.lo
+m_trace_la_OBJECTS = $(am_m_trace_la_OBJECTS)
+m_trace_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_trace_la_LDFLAGS) $(LDFLAGS) -o $@
+m_user_la_LIBADD =
+am_m_user_la_OBJECTS = m_user.lo
+m_user_la_OBJECTS = $(am_m_user_la_OBJECTS)
+m_user_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_user_la_LDFLAGS) $(LDFLAGS) -o $@
+m_userhost_la_LIBADD =
+am_m_userhost_la_OBJECTS = m_userhost.lo
+m_userhost_la_OBJECTS = $(am_m_userhost_la_OBJECTS)
+m_userhost_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_userhost_la_LDFLAGS) $(LDFLAGS) -o $@
+m_users_la_LIBADD =
+am_m_users_la_OBJECTS = m_users.lo
+m_users_la_OBJECTS = $(am_m_users_la_OBJECTS)
+m_users_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_users_la_LDFLAGS) $(LDFLAGS) -o $@
+m_version_la_LIBADD =
+am_m_version_la_OBJECTS = m_version.lo
+m_version_la_OBJECTS = $(am_m_version_la_OBJECTS)
+m_version_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_version_la_LDFLAGS) $(LDFLAGS) -o $@
+m_wallops_la_LIBADD =
+am_m_wallops_la_OBJECTS = m_wallops.lo
+m_wallops_la_OBJECTS = $(am_m_wallops_la_OBJECTS)
+m_wallops_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_wallops_la_LDFLAGS) $(LDFLAGS) -o $@
+m_watch_la_LIBADD =
+am_m_watch_la_OBJECTS = m_watch.lo
+m_watch_la_OBJECTS = $(am_m_watch_la_OBJECTS)
+m_watch_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_watch_la_LDFLAGS) $(LDFLAGS) -o $@
+m_who_la_LIBADD =
+am_m_who_la_OBJECTS = m_who.lo
+m_who_la_OBJECTS = $(am_m_who_la_OBJECTS)
+m_who_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(m_who_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+m_whois_la_LIBADD =
+am_m_whois_la_OBJECTS = m_whois.lo
+m_whois_la_OBJECTS = $(am_m_whois_la_OBJECTS)
+m_whois_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_whois_la_LDFLAGS) $(LDFLAGS) -o $@
+m_whowas_la_LIBADD =
+am_m_whowas_la_OBJECTS = m_whowas.lo
+m_whowas_la_OBJECTS = $(am_m_whowas_la_OBJECTS)
+m_whowas_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_whowas_la_LDFLAGS) $(LDFLAGS) -o $@
+m_xline_la_LIBADD =
+am_m_xline_la_OBJECTS = m_xline.lo
+m_xline_la_OBJECTS = $(am_m_xline_la_OBJECTS)
+m_xline_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(m_xline_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_accept_la_SOURCES) $(m_admin_la_SOURCES) \
+ $(m_away_la_SOURCES) $(m_cap_la_SOURCES) $(m_capab_la_SOURCES) \
+ $(m_challenge_la_SOURCES) $(m_close_la_SOURCES) \
+ $(m_connect_la_SOURCES) $(m_dline_la_SOURCES) \
+ $(m_encap_la_SOURCES) $(m_eob_la_SOURCES) \
+ $(m_etrace_la_SOURCES) $(m_gline_la_SOURCES) \
+ $(m_globops_la_SOURCES) $(m_hash_la_SOURCES) \
+ $(m_help_la_SOURCES) $(m_info_la_SOURCES) \
+ $(m_invite_la_SOURCES) $(m_ison_la_SOURCES) \
+ $(m_kline_la_SOURCES) $(m_knock_la_SOURCES) \
+ $(m_links_la_SOURCES) $(m_list_la_SOURCES) \
+ $(m_locops_la_SOURCES) $(m_lusers_la_SOURCES) \
+ $(m_map_la_SOURCES) $(m_module_la_SOURCES) \
+ $(m_motd_la_SOURCES) $(m_names_la_SOURCES) \
+ $(m_oper_la_SOURCES) $(m_operwall_la_SOURCES) \
+ $(m_pass_la_SOURCES) $(m_ping_la_SOURCES) $(m_pong_la_SOURCES) \
+ $(m_post_la_SOURCES) $(m_rehash_la_SOURCES) \
+ $(m_restart_la_SOURCES) $(m_resv_la_SOURCES) \
+ $(m_services_la_SOURCES) $(m_set_la_SOURCES) \
+ $(m_stats_la_SOURCES) $(m_svinfo_la_SOURCES) \
+ $(m_svsmode_la_SOURCES) $(m_svsnick_la_SOURCES) \
+ $(m_tburst_la_SOURCES) $(m_testline_la_SOURCES) \
+ $(m_testmask_la_SOURCES) $(m_time_la_SOURCES) \
+ $(m_topic_la_SOURCES) $(m_trace_la_SOURCES) \
+ $(m_user_la_SOURCES) $(m_userhost_la_SOURCES) \
+ $(m_users_la_SOURCES) $(m_version_la_SOURCES) \
+ $(m_wallops_la_SOURCES) $(m_watch_la_SOURCES) \
+ $(m_who_la_SOURCES) $(m_whois_la_SOURCES) \
+ $(m_whowas_la_SOURCES) $(m_xline_la_SOURCES)
+DIST_SOURCES = $(m_accept_la_SOURCES) $(m_admin_la_SOURCES) \
+ $(m_away_la_SOURCES) $(m_cap_la_SOURCES) $(m_capab_la_SOURCES) \
+ $(m_challenge_la_SOURCES) $(m_close_la_SOURCES) \
+ $(m_connect_la_SOURCES) $(m_dline_la_SOURCES) \
+ $(m_encap_la_SOURCES) $(m_eob_la_SOURCES) \
+ $(m_etrace_la_SOURCES) $(m_gline_la_SOURCES) \
+ $(m_globops_la_SOURCES) $(m_hash_la_SOURCES) \
+ $(m_help_la_SOURCES) $(m_info_la_SOURCES) \
+ $(m_invite_la_SOURCES) $(m_ison_la_SOURCES) \
+ $(m_kline_la_SOURCES) $(m_knock_la_SOURCES) \
+ $(m_links_la_SOURCES) $(m_list_la_SOURCES) \
+ $(m_locops_la_SOURCES) $(m_lusers_la_SOURCES) \
+ $(m_map_la_SOURCES) $(m_module_la_SOURCES) \
+ $(m_motd_la_SOURCES) $(m_names_la_SOURCES) \
+ $(m_oper_la_SOURCES) $(m_operwall_la_SOURCES) \
+ $(m_pass_la_SOURCES) $(m_ping_la_SOURCES) $(m_pong_la_SOURCES) \
+ $(m_post_la_SOURCES) $(m_rehash_la_SOURCES) \
+ $(m_restart_la_SOURCES) $(m_resv_la_SOURCES) \
+ $(m_services_la_SOURCES) $(m_set_la_SOURCES) \
+ $(m_stats_la_SOURCES) $(m_svinfo_la_SOURCES) \
+ $(m_svsmode_la_SOURCES) $(m_svsnick_la_SOURCES) \
+ $(m_tburst_la_SOURCES) $(m_testline_la_SOURCES) \
+ $(m_testmask_la_SOURCES) $(m_time_la_SOURCES) \
+ $(m_topic_la_SOURCES) $(m_trace_la_SOURCES) \
+ $(m_user_la_SOURCES) $(m_userhost_la_SOURCES) \
+ $(m_users_la_SOURCES) $(m_version_la_SOURCES) \
+ $(m_wallops_la_SOURCES) $(m_watch_la_SOURCES) \
+ $(m_who_la_SOURCES) $(m_whois_la_SOURCES) \
+ $(m_whowas_la_SOURCES) $(m_xline_la_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-dvi-recursive install-exec-recursive \
+ install-html-recursive install-info-recursive \
+ install-pdf-recursive install-ps-recursive install-recursive \
+ installcheck-recursive installdirs-recursive pdf-recursive \
+ ps-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
+ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
+ distdir
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+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
+SUBDIRS = core
+AM_CPPFLAGS = -I$(top_srcdir)/include
+modulesdir = $(pkglibdir)/modules/autoload
+modules_LTLIBRARIES = m_accept.la \
+ m_admin.la \
+ m_away.la \
+ m_capab.la \
+ m_cap.la \
+ m_challenge.la \
+ m_close.la \
+ m_connect.la \
+ m_dline.la \
+ m_encap.la \
+ m_eob.la \
+ m_etrace.la \
+ m_gline.la \
+ m_globops.la \
+ m_hash.la \
+ m_help.la \
+ m_info.la \
+ m_invite.la \
+ m_ison.la \
+ m_kline.la \
+ m_knock.la \
+ m_links.la \
+ m_list.la \
+ m_locops.la \
+ m_lusers.la \
+ m_map.la \
+ m_module.la \
+ m_motd.la \
+ m_names.la \
+ m_oper.la \
+ m_operwall.la \
+ m_pass.la \
+ m_ping.la \
+ m_pong.la \
+ m_post.la \
+ m_rehash.la \
+ m_restart.la \
+ m_resv.la \
+ m_set.la \
+ m_services.la \
+ m_stats.la \
+ m_svinfo.la \
+ m_svsmode.la \
+ m_svsnick.la \
+ m_tburst.la \
+ m_testline.la \
+ m_testmask.la \
+ m_time.la \
+ m_topic.la \
+ m_trace.la \
+ m_user.la \
+ m_userhost.la \
+ m_users.la \
+ m_version.la \
+ m_wallops.la \
+ m_watch.la \
+ m_who.la \
+ m_whois.la \
+ m_whowas.la \
+ m_xline.la
+
+m_challenge_la_LDFLAGS = $(MODULE_FLAGS)
+m_accept_la_LDFLAGS = $(MODULE_FLAGS)
+m_admin_la_LDFLAGS = $(MODULE_FLAGS)
+m_away_la_LDFLAGS = $(MODULE_FLAGS)
+m_capab_la_LDFLAGS = $(MODULE_FLAGS)
+m_cap_la_LDFLAGS = $(MODULE_FLAGS)
+m_close_la_LDFLAGS = $(MODULE_FLAGS)
+m_connect_la_LDFLAGS = $(MODULE_FLAGS)
+m_dline_la_LDFLAGS = $(MODULE_FLAGS)
+m_encap_la_LDFLAGS = $(MODULE_FLAGS)
+m_eob_la_LDFLAGS = $(MODULE_FLAGS)
+m_etrace_la_LDFLAGS = $(MODULE_FLAGS)
+m_gline_la_LDFLAGS = $(MODULE_FLAGS)
+m_globops_la_LDFLAGS = $(MODULE_FLAGS)
+m_hash_la_LDFLAGS = $(MODULE_FLAGS)
+m_help_la_LDFLAGS = $(MODULE_FLAGS)
+m_info_la_LDFLAGS = $(MODULE_FLAGS)
+m_invite_la_LDFLAGS = $(MODULE_FLAGS)
+m_ison_la_LDFLAGS = $(MODULE_FLAGS)
+m_kline_la_LDFLAGS = $(MODULE_FLAGS)
+m_knock_la_LDFLAGS = $(MODULE_FLAGS)
+m_links_la_LDFLAGS = $(MODULE_FLAGS)
+m_list_la_LDFLAGS = $(MODULE_FLAGS)
+m_locops_la_LDFLAGS = $(MODULE_FLAGS)
+m_lusers_la_LDFLAGS = $(MODULE_FLAGS)
+m_map_la_LDFLAGS = $(MODULE_FLAGS)
+m_module_la_LDFLAGS = $(MODULE_FLAGS)
+m_motd_la_LDFLAGS = $(MODULE_FLAGS)
+m_names_la_LDFLAGS = $(MODULE_FLAGS)
+m_oper_la_LDFLAGS = $(MODULE_FLAGS)
+m_operwall_la_LDFLAGS = $(MODULE_FLAGS)
+m_pass_la_LDFLAGS = $(MODULE_FLAGS)
+m_ping_la_LDFLAGS = $(MODULE_FLAGS)
+m_pong_la_LDFLAGS = $(MODULE_FLAGS)
+m_post_la_LDFLAGS = $(MODULE_FLAGS)
+m_rehash_la_LDFLAGS = $(MODULE_FLAGS)
+m_restart_la_LDFLAGS = $(MODULE_FLAGS)
+m_resv_la_LDFLAGS = $(MODULE_FLAGS)
+m_set_la_LDFLAGS = $(MODULE_FLAGS)
+m_services_la_LDFLAGS = $(MODULE_FLAGS)
+m_stats_la_LDFLAGS = $(MODULE_FLAGS)
+m_svinfo_la_LDFLAGS = $(MODULE_FLAGS)
+m_svsmode_la_LDFLAGS = $(MODULE_FLAGS)
+m_svsnick_la_LDFLAGS = $(MODULE_FLAGS)
+m_tburst_la_LDFLAGS = $(MODULE_FLAGS)
+m_testline_la_LDFLAGS = $(MODULE_FLAGS)
+m_testmask_la_LDFLAGS = $(MODULE_FLAGS)
+m_time_la_LDFLAGS = $(MODULE_FLAGS)
+m_topic_la_LDFLAGS = $(MODULE_FLAGS)
+m_trace_la_LDFLAGS = $(MODULE_FLAGS)
+m_user_la_LDFLAGS = $(MODULE_FLAGS)
+m_userhost_la_LDFLAGS = $(MODULE_FLAGS)
+m_users_la_LDFLAGS = $(MODULE_FLAGS)
+m_version_la_LDFLAGS = $(MODULE_FLAGS)
+m_wallops_la_LDFLAGS = $(MODULE_FLAGS)
+m_watch_la_LDFLAGS = $(MODULE_FLAGS)
+m_who_la_LDFLAGS = $(MODULE_FLAGS)
+m_whois_la_LDFLAGS = $(MODULE_FLAGS)
+m_whowas_la_LDFLAGS = $(MODULE_FLAGS)
+m_xline_la_LDFLAGS = $(MODULE_FLAGS)
+m_accept_la_SOURCES = m_accept.c
+m_admin_la_SOURCES = m_admin.c
+m_away_la_SOURCES = m_away.c
+m_capab_la_SOURCES = m_capab.c
+m_cap_la_SOURCES = m_cap.c
+m_challenge_la_SOURCES = m_challenge.c
+m_close_la_SOURCES = m_close.c
+m_connect_la_SOURCES = m_connect.c
+m_dline_la_SOURCES = m_dline.c
+m_encap_la_SOURCES = m_encap.c
+m_eob_la_SOURCES = m_eob.c
+m_etrace_la_SOURCES = m_etrace.c
+m_gline_la_SOURCES = m_gline.c
+m_globops_la_SOURCES = m_globops.c
+m_hash_la_SOURCES = m_hash.c
+m_help_la_SOURCES = m_help.c
+m_info_la_SOURCES = m_info.c
+m_invite_la_SOURCES = m_invite.c
+m_ison_la_SOURCES = m_ison.c
+m_kline_la_SOURCES = m_kline.c
+m_knock_la_SOURCES = m_knock.c
+m_links_la_SOURCES = m_links.c
+m_list_la_SOURCES = m_list.c
+m_locops_la_SOURCES = m_locops.c
+m_lusers_la_SOURCES = m_lusers.c
+m_map_la_SOURCES = m_map.c
+m_module_la_SOURCES = m_module.c
+m_motd_la_SOURCES = m_motd.c
+m_names_la_SOURCES = m_names.c
+m_oper_la_SOURCES = m_oper.c
+m_operwall_la_SOURCES = m_operwall.c
+m_pass_la_SOURCES = m_pass.c
+m_ping_la_SOURCES = m_ping.c
+m_pong_la_SOURCES = m_pong.c
+m_post_la_SOURCES = m_post.c
+m_rehash_la_SOURCES = m_rehash.c
+m_restart_la_SOURCES = m_restart.c
+m_resv_la_SOURCES = m_resv.c
+m_set_la_SOURCES = m_set.c
+m_services_la_SOURCES = m_services.c
+m_stats_la_SOURCES = m_stats.c
+m_svinfo_la_SOURCES = m_svinfo.c
+m_svsmode_la_SOURCES = m_svsmode.c
+m_svsnick_la_SOURCES = m_svsnick.c
+m_tburst_la_SOURCES = m_tburst.c
+m_testline_la_SOURCES = m_testline.c
+m_testmask_la_SOURCES = m_testmask.c
+m_time_la_SOURCES = m_time.c
+m_topic_la_SOURCES = m_topic.c
+m_trace_la_SOURCES = m_trace.c
+m_user_la_SOURCES = m_user.c
+m_userhost_la_SOURCES = m_userhost.c
+m_users_la_SOURCES = m_users.c
+m_version_la_SOURCES = m_version.c
+m_wallops_la_SOURCES = m_wallops.c
+m_watch_la_SOURCES = m_watch.c
+m_who_la_SOURCES = m_who.c
+m_whois_la_SOURCES = m_whois.c
+m_whowas_la_SOURCES = m_whowas.c
+m_xline_la_SOURCES = m_xline.c
+all: all-recursive
+
+.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/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign modules/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_accept.la: $(m_accept_la_OBJECTS) $(m_accept_la_DEPENDENCIES) $(EXTRA_m_accept_la_DEPENDENCIES)
+ $(m_accept_la_LINK) -rpath $(modulesdir) $(m_accept_la_OBJECTS) $(m_accept_la_LIBADD) $(LIBS)
+m_admin.la: $(m_admin_la_OBJECTS) $(m_admin_la_DEPENDENCIES) $(EXTRA_m_admin_la_DEPENDENCIES)
+ $(m_admin_la_LINK) -rpath $(modulesdir) $(m_admin_la_OBJECTS) $(m_admin_la_LIBADD) $(LIBS)
+m_away.la: $(m_away_la_OBJECTS) $(m_away_la_DEPENDENCIES) $(EXTRA_m_away_la_DEPENDENCIES)
+ $(m_away_la_LINK) -rpath $(modulesdir) $(m_away_la_OBJECTS) $(m_away_la_LIBADD) $(LIBS)
+m_cap.la: $(m_cap_la_OBJECTS) $(m_cap_la_DEPENDENCIES) $(EXTRA_m_cap_la_DEPENDENCIES)
+ $(m_cap_la_LINK) -rpath $(modulesdir) $(m_cap_la_OBJECTS) $(m_cap_la_LIBADD) $(LIBS)
+m_capab.la: $(m_capab_la_OBJECTS) $(m_capab_la_DEPENDENCIES) $(EXTRA_m_capab_la_DEPENDENCIES)
+ $(m_capab_la_LINK) -rpath $(modulesdir) $(m_capab_la_OBJECTS) $(m_capab_la_LIBADD) $(LIBS)
+m_challenge.la: $(m_challenge_la_OBJECTS) $(m_challenge_la_DEPENDENCIES) $(EXTRA_m_challenge_la_DEPENDENCIES)
+ $(m_challenge_la_LINK) -rpath $(modulesdir) $(m_challenge_la_OBJECTS) $(m_challenge_la_LIBADD) $(LIBS)
+m_close.la: $(m_close_la_OBJECTS) $(m_close_la_DEPENDENCIES) $(EXTRA_m_close_la_DEPENDENCIES)
+ $(m_close_la_LINK) -rpath $(modulesdir) $(m_close_la_OBJECTS) $(m_close_la_LIBADD) $(LIBS)
+m_connect.la: $(m_connect_la_OBJECTS) $(m_connect_la_DEPENDENCIES) $(EXTRA_m_connect_la_DEPENDENCIES)
+ $(m_connect_la_LINK) -rpath $(modulesdir) $(m_connect_la_OBJECTS) $(m_connect_la_LIBADD) $(LIBS)
+m_dline.la: $(m_dline_la_OBJECTS) $(m_dline_la_DEPENDENCIES) $(EXTRA_m_dline_la_DEPENDENCIES)
+ $(m_dline_la_LINK) -rpath $(modulesdir) $(m_dline_la_OBJECTS) $(m_dline_la_LIBADD) $(LIBS)
+m_encap.la: $(m_encap_la_OBJECTS) $(m_encap_la_DEPENDENCIES) $(EXTRA_m_encap_la_DEPENDENCIES)
+ $(m_encap_la_LINK) -rpath $(modulesdir) $(m_encap_la_OBJECTS) $(m_encap_la_LIBADD) $(LIBS)
+m_eob.la: $(m_eob_la_OBJECTS) $(m_eob_la_DEPENDENCIES) $(EXTRA_m_eob_la_DEPENDENCIES)
+ $(m_eob_la_LINK) -rpath $(modulesdir) $(m_eob_la_OBJECTS) $(m_eob_la_LIBADD) $(LIBS)
+m_etrace.la: $(m_etrace_la_OBJECTS) $(m_etrace_la_DEPENDENCIES) $(EXTRA_m_etrace_la_DEPENDENCIES)
+ $(m_etrace_la_LINK) -rpath $(modulesdir) $(m_etrace_la_OBJECTS) $(m_etrace_la_LIBADD) $(LIBS)
+m_gline.la: $(m_gline_la_OBJECTS) $(m_gline_la_DEPENDENCIES) $(EXTRA_m_gline_la_DEPENDENCIES)
+ $(m_gline_la_LINK) -rpath $(modulesdir) $(m_gline_la_OBJECTS) $(m_gline_la_LIBADD) $(LIBS)
+m_globops.la: $(m_globops_la_OBJECTS) $(m_globops_la_DEPENDENCIES) $(EXTRA_m_globops_la_DEPENDENCIES)
+ $(m_globops_la_LINK) -rpath $(modulesdir) $(m_globops_la_OBJECTS) $(m_globops_la_LIBADD) $(LIBS)
+m_hash.la: $(m_hash_la_OBJECTS) $(m_hash_la_DEPENDENCIES) $(EXTRA_m_hash_la_DEPENDENCIES)
+ $(m_hash_la_LINK) -rpath $(modulesdir) $(m_hash_la_OBJECTS) $(m_hash_la_LIBADD) $(LIBS)
+m_help.la: $(m_help_la_OBJECTS) $(m_help_la_DEPENDENCIES) $(EXTRA_m_help_la_DEPENDENCIES)
+ $(m_help_la_LINK) -rpath $(modulesdir) $(m_help_la_OBJECTS) $(m_help_la_LIBADD) $(LIBS)
+m_info.la: $(m_info_la_OBJECTS) $(m_info_la_DEPENDENCIES) $(EXTRA_m_info_la_DEPENDENCIES)
+ $(m_info_la_LINK) -rpath $(modulesdir) $(m_info_la_OBJECTS) $(m_info_la_LIBADD) $(LIBS)
+m_invite.la: $(m_invite_la_OBJECTS) $(m_invite_la_DEPENDENCIES) $(EXTRA_m_invite_la_DEPENDENCIES)
+ $(m_invite_la_LINK) -rpath $(modulesdir) $(m_invite_la_OBJECTS) $(m_invite_la_LIBADD) $(LIBS)
+m_ison.la: $(m_ison_la_OBJECTS) $(m_ison_la_DEPENDENCIES) $(EXTRA_m_ison_la_DEPENDENCIES)
+ $(m_ison_la_LINK) -rpath $(modulesdir) $(m_ison_la_OBJECTS) $(m_ison_la_LIBADD) $(LIBS)
+m_kline.la: $(m_kline_la_OBJECTS) $(m_kline_la_DEPENDENCIES) $(EXTRA_m_kline_la_DEPENDENCIES)
+ $(m_kline_la_LINK) -rpath $(modulesdir) $(m_kline_la_OBJECTS) $(m_kline_la_LIBADD) $(LIBS)
+m_knock.la: $(m_knock_la_OBJECTS) $(m_knock_la_DEPENDENCIES) $(EXTRA_m_knock_la_DEPENDENCIES)
+ $(m_knock_la_LINK) -rpath $(modulesdir) $(m_knock_la_OBJECTS) $(m_knock_la_LIBADD) $(LIBS)
+m_links.la: $(m_links_la_OBJECTS) $(m_links_la_DEPENDENCIES) $(EXTRA_m_links_la_DEPENDENCIES)
+ $(m_links_la_LINK) -rpath $(modulesdir) $(m_links_la_OBJECTS) $(m_links_la_LIBADD) $(LIBS)
+m_list.la: $(m_list_la_OBJECTS) $(m_list_la_DEPENDENCIES) $(EXTRA_m_list_la_DEPENDENCIES)
+ $(m_list_la_LINK) -rpath $(modulesdir) $(m_list_la_OBJECTS) $(m_list_la_LIBADD) $(LIBS)
+m_locops.la: $(m_locops_la_OBJECTS) $(m_locops_la_DEPENDENCIES) $(EXTRA_m_locops_la_DEPENDENCIES)
+ $(m_locops_la_LINK) -rpath $(modulesdir) $(m_locops_la_OBJECTS) $(m_locops_la_LIBADD) $(LIBS)
+m_lusers.la: $(m_lusers_la_OBJECTS) $(m_lusers_la_DEPENDENCIES) $(EXTRA_m_lusers_la_DEPENDENCIES)
+ $(m_lusers_la_LINK) -rpath $(modulesdir) $(m_lusers_la_OBJECTS) $(m_lusers_la_LIBADD) $(LIBS)
+m_map.la: $(m_map_la_OBJECTS) $(m_map_la_DEPENDENCIES) $(EXTRA_m_map_la_DEPENDENCIES)
+ $(m_map_la_LINK) -rpath $(modulesdir) $(m_map_la_OBJECTS) $(m_map_la_LIBADD) $(LIBS)
+m_module.la: $(m_module_la_OBJECTS) $(m_module_la_DEPENDENCIES) $(EXTRA_m_module_la_DEPENDENCIES)
+ $(m_module_la_LINK) -rpath $(modulesdir) $(m_module_la_OBJECTS) $(m_module_la_LIBADD) $(LIBS)
+m_motd.la: $(m_motd_la_OBJECTS) $(m_motd_la_DEPENDENCIES) $(EXTRA_m_motd_la_DEPENDENCIES)
+ $(m_motd_la_LINK) -rpath $(modulesdir) $(m_motd_la_OBJECTS) $(m_motd_la_LIBADD) $(LIBS)
+m_names.la: $(m_names_la_OBJECTS) $(m_names_la_DEPENDENCIES) $(EXTRA_m_names_la_DEPENDENCIES)
+ $(m_names_la_LINK) -rpath $(modulesdir) $(m_names_la_OBJECTS) $(m_names_la_LIBADD) $(LIBS)
+m_oper.la: $(m_oper_la_OBJECTS) $(m_oper_la_DEPENDENCIES) $(EXTRA_m_oper_la_DEPENDENCIES)
+ $(m_oper_la_LINK) -rpath $(modulesdir) $(m_oper_la_OBJECTS) $(m_oper_la_LIBADD) $(LIBS)
+m_operwall.la: $(m_operwall_la_OBJECTS) $(m_operwall_la_DEPENDENCIES) $(EXTRA_m_operwall_la_DEPENDENCIES)
+ $(m_operwall_la_LINK) -rpath $(modulesdir) $(m_operwall_la_OBJECTS) $(m_operwall_la_LIBADD) $(LIBS)
+m_pass.la: $(m_pass_la_OBJECTS) $(m_pass_la_DEPENDENCIES) $(EXTRA_m_pass_la_DEPENDENCIES)
+ $(m_pass_la_LINK) -rpath $(modulesdir) $(m_pass_la_OBJECTS) $(m_pass_la_LIBADD) $(LIBS)
+m_ping.la: $(m_ping_la_OBJECTS) $(m_ping_la_DEPENDENCIES) $(EXTRA_m_ping_la_DEPENDENCIES)
+ $(m_ping_la_LINK) -rpath $(modulesdir) $(m_ping_la_OBJECTS) $(m_ping_la_LIBADD) $(LIBS)
+m_pong.la: $(m_pong_la_OBJECTS) $(m_pong_la_DEPENDENCIES) $(EXTRA_m_pong_la_DEPENDENCIES)
+ $(m_pong_la_LINK) -rpath $(modulesdir) $(m_pong_la_OBJECTS) $(m_pong_la_LIBADD) $(LIBS)
+m_post.la: $(m_post_la_OBJECTS) $(m_post_la_DEPENDENCIES) $(EXTRA_m_post_la_DEPENDENCIES)
+ $(m_post_la_LINK) -rpath $(modulesdir) $(m_post_la_OBJECTS) $(m_post_la_LIBADD) $(LIBS)
+m_rehash.la: $(m_rehash_la_OBJECTS) $(m_rehash_la_DEPENDENCIES) $(EXTRA_m_rehash_la_DEPENDENCIES)
+ $(m_rehash_la_LINK) -rpath $(modulesdir) $(m_rehash_la_OBJECTS) $(m_rehash_la_LIBADD) $(LIBS)
+m_restart.la: $(m_restart_la_OBJECTS) $(m_restart_la_DEPENDENCIES) $(EXTRA_m_restart_la_DEPENDENCIES)
+ $(m_restart_la_LINK) -rpath $(modulesdir) $(m_restart_la_OBJECTS) $(m_restart_la_LIBADD) $(LIBS)
+m_resv.la: $(m_resv_la_OBJECTS) $(m_resv_la_DEPENDENCIES) $(EXTRA_m_resv_la_DEPENDENCIES)
+ $(m_resv_la_LINK) -rpath $(modulesdir) $(m_resv_la_OBJECTS) $(m_resv_la_LIBADD) $(LIBS)
+m_services.la: $(m_services_la_OBJECTS) $(m_services_la_DEPENDENCIES) $(EXTRA_m_services_la_DEPENDENCIES)
+ $(m_services_la_LINK) -rpath $(modulesdir) $(m_services_la_OBJECTS) $(m_services_la_LIBADD) $(LIBS)
+m_set.la: $(m_set_la_OBJECTS) $(m_set_la_DEPENDENCIES) $(EXTRA_m_set_la_DEPENDENCIES)
+ $(m_set_la_LINK) -rpath $(modulesdir) $(m_set_la_OBJECTS) $(m_set_la_LIBADD) $(LIBS)
+m_stats.la: $(m_stats_la_OBJECTS) $(m_stats_la_DEPENDENCIES) $(EXTRA_m_stats_la_DEPENDENCIES)
+ $(m_stats_la_LINK) -rpath $(modulesdir) $(m_stats_la_OBJECTS) $(m_stats_la_LIBADD) $(LIBS)
+m_svinfo.la: $(m_svinfo_la_OBJECTS) $(m_svinfo_la_DEPENDENCIES) $(EXTRA_m_svinfo_la_DEPENDENCIES)
+ $(m_svinfo_la_LINK) -rpath $(modulesdir) $(m_svinfo_la_OBJECTS) $(m_svinfo_la_LIBADD) $(LIBS)
+m_svsmode.la: $(m_svsmode_la_OBJECTS) $(m_svsmode_la_DEPENDENCIES) $(EXTRA_m_svsmode_la_DEPENDENCIES)
+ $(m_svsmode_la_LINK) -rpath $(modulesdir) $(m_svsmode_la_OBJECTS) $(m_svsmode_la_LIBADD) $(LIBS)
+m_svsnick.la: $(m_svsnick_la_OBJECTS) $(m_svsnick_la_DEPENDENCIES) $(EXTRA_m_svsnick_la_DEPENDENCIES)
+ $(m_svsnick_la_LINK) -rpath $(modulesdir) $(m_svsnick_la_OBJECTS) $(m_svsnick_la_LIBADD) $(LIBS)
+m_tburst.la: $(m_tburst_la_OBJECTS) $(m_tburst_la_DEPENDENCIES) $(EXTRA_m_tburst_la_DEPENDENCIES)
+ $(m_tburst_la_LINK) -rpath $(modulesdir) $(m_tburst_la_OBJECTS) $(m_tburst_la_LIBADD) $(LIBS)
+m_testline.la: $(m_testline_la_OBJECTS) $(m_testline_la_DEPENDENCIES) $(EXTRA_m_testline_la_DEPENDENCIES)
+ $(m_testline_la_LINK) -rpath $(modulesdir) $(m_testline_la_OBJECTS) $(m_testline_la_LIBADD) $(LIBS)
+m_testmask.la: $(m_testmask_la_OBJECTS) $(m_testmask_la_DEPENDENCIES) $(EXTRA_m_testmask_la_DEPENDENCIES)
+ $(m_testmask_la_LINK) -rpath $(modulesdir) $(m_testmask_la_OBJECTS) $(m_testmask_la_LIBADD) $(LIBS)
+m_time.la: $(m_time_la_OBJECTS) $(m_time_la_DEPENDENCIES) $(EXTRA_m_time_la_DEPENDENCIES)
+ $(m_time_la_LINK) -rpath $(modulesdir) $(m_time_la_OBJECTS) $(m_time_la_LIBADD) $(LIBS)
+m_topic.la: $(m_topic_la_OBJECTS) $(m_topic_la_DEPENDENCIES) $(EXTRA_m_topic_la_DEPENDENCIES)
+ $(m_topic_la_LINK) -rpath $(modulesdir) $(m_topic_la_OBJECTS) $(m_topic_la_LIBADD) $(LIBS)
+m_trace.la: $(m_trace_la_OBJECTS) $(m_trace_la_DEPENDENCIES) $(EXTRA_m_trace_la_DEPENDENCIES)
+ $(m_trace_la_LINK) -rpath $(modulesdir) $(m_trace_la_OBJECTS) $(m_trace_la_LIBADD) $(LIBS)
+m_user.la: $(m_user_la_OBJECTS) $(m_user_la_DEPENDENCIES) $(EXTRA_m_user_la_DEPENDENCIES)
+ $(m_user_la_LINK) -rpath $(modulesdir) $(m_user_la_OBJECTS) $(m_user_la_LIBADD) $(LIBS)
+m_userhost.la: $(m_userhost_la_OBJECTS) $(m_userhost_la_DEPENDENCIES) $(EXTRA_m_userhost_la_DEPENDENCIES)
+ $(m_userhost_la_LINK) -rpath $(modulesdir) $(m_userhost_la_OBJECTS) $(m_userhost_la_LIBADD) $(LIBS)
+m_users.la: $(m_users_la_OBJECTS) $(m_users_la_DEPENDENCIES) $(EXTRA_m_users_la_DEPENDENCIES)
+ $(m_users_la_LINK) -rpath $(modulesdir) $(m_users_la_OBJECTS) $(m_users_la_LIBADD) $(LIBS)
+m_version.la: $(m_version_la_OBJECTS) $(m_version_la_DEPENDENCIES) $(EXTRA_m_version_la_DEPENDENCIES)
+ $(m_version_la_LINK) -rpath $(modulesdir) $(m_version_la_OBJECTS) $(m_version_la_LIBADD) $(LIBS)
+m_wallops.la: $(m_wallops_la_OBJECTS) $(m_wallops_la_DEPENDENCIES) $(EXTRA_m_wallops_la_DEPENDENCIES)
+ $(m_wallops_la_LINK) -rpath $(modulesdir) $(m_wallops_la_OBJECTS) $(m_wallops_la_LIBADD) $(LIBS)
+m_watch.la: $(m_watch_la_OBJECTS) $(m_watch_la_DEPENDENCIES) $(EXTRA_m_watch_la_DEPENDENCIES)
+ $(m_watch_la_LINK) -rpath $(modulesdir) $(m_watch_la_OBJECTS) $(m_watch_la_LIBADD) $(LIBS)
+m_who.la: $(m_who_la_OBJECTS) $(m_who_la_DEPENDENCIES) $(EXTRA_m_who_la_DEPENDENCIES)
+ $(m_who_la_LINK) -rpath $(modulesdir) $(m_who_la_OBJECTS) $(m_who_la_LIBADD) $(LIBS)
+m_whois.la: $(m_whois_la_OBJECTS) $(m_whois_la_DEPENDENCIES) $(EXTRA_m_whois_la_DEPENDENCIES)
+ $(m_whois_la_LINK) -rpath $(modulesdir) $(m_whois_la_OBJECTS) $(m_whois_la_LIBADD) $(LIBS)
+m_whowas.la: $(m_whowas_la_OBJECTS) $(m_whowas_la_DEPENDENCIES) $(EXTRA_m_whowas_la_DEPENDENCIES)
+ $(m_whowas_la_LINK) -rpath $(modulesdir) $(m_whowas_la_OBJECTS) $(m_whowas_la_LIBADD) $(LIBS)
+m_xline.la: $(m_xline_la_OBJECTS) $(m_xline_la_DEPENDENCIES) $(EXTRA_m_xline_la_DEPENDENCIES)
+ $(m_xline_la_LINK) -rpath $(modulesdir) $(m_xline_la_OBJECTS) $(m_xline_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_accept.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_admin.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_away.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_cap.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_capab.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_challenge.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_close.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_connect.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_dline.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_encap.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_eob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_etrace.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_gline.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_globops.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_hash.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_help.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_info.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_invite.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_ison.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_kline.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_knock.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_links.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_list.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_locops.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_lusers.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_map.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_module.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_motd.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_names.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_oper.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_operwall.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_pass.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_ping.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_pong.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_post.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_rehash.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_restart.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_resv.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_services.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_set.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_stats.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_svinfo.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_svsmode.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_svsnick.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_tburst.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_testline.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_testmask.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_time.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_topic.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_trace.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_user.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_userhost.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_users.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_version.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_wallops.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_watch.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_who.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_whois.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_whowas.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m_xline.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
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(RECURSIVE_TARGETS) $(RECURSIVE_CLEAN_TARGETS):
+ @fail= failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+cscopelist-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) cscopelist); \
+ done
+
+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: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ 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: ctags-recursive $(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: cscopelist-recursive $(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
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(LTLIBRARIES)
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(modulesdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+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-recursive
+
+clean-am: clean-generic clean-libtool clean-modulesLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-modulesLTLIBRARIES
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-modulesLTLIBRARIES
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) \
+ cscopelist-recursive ctags-recursive install-am install-strip \
+ tags-recursive
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+ all all-am check check-am clean clean-generic clean-libtool \
+ clean-modulesLTLIBRARIES cscopelist cscopelist-recursive ctags \
+ ctags-recursive distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-modulesLTLIBRARIES \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \
+ uninstall uninstall-am uninstall-modulesLTLIBRARIES
+
+
+modules: $(modules_LTLIBRARIES)
+
+# 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/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
+};
diff --git a/modules/m_accept.c b/modules/m_accept.c
new file mode 100644
index 0000000..3fff6c1
--- /dev/null
+++ b/modules/m_accept.c
@@ -0,0 +1,221 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ *
+ * Copyright (C) 2002 by the past and present ircd coders, and others.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/*! \file m_accept.c
+ * \brief Includes required functions for processing the ACCEPT command.
+ * \version $Id$
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "list.h"
+#include "numeric.h"
+#include "conf.h"
+#include "s_serv.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+
+
+/*! \brief Creates and sends a list of nick!user\@host masks a Client
+ * has on its acceptlist.
+ *
+ * \param source_p The actual Client the list will be sent to.
+ */
+static void
+list_accepts(struct Client *source_p)
+{
+ int len = 0;
+ char nicks[IRCD_BUFSIZE] = { '\0' };
+ char *t = nicks;
+ const dlink_node *ptr = NULL;
+
+ len = strlen(me.name) + strlen(source_p->name) + 12;
+
+ DLINK_FOREACH(ptr, source_p->localClient->acceptlist.head)
+ {
+ const struct split_nuh_item *accept_p = ptr->data;
+ size_t masklen = strlen(accept_p->nickptr) +
+ strlen(accept_p->userptr) +
+ strlen(accept_p->hostptr) + 2 /* !@ */ ;
+
+ if ((t - nicks) + masklen + len > IRCD_BUFSIZE)
+ {
+ *(t - 1) = '\0';
+ sendto_one(source_p, form_str(RPL_ACCEPTLIST),
+ me.name, source_p->name, nicks);
+ t = nicks;
+ }
+
+ t += ircsprintf(t, "%s!%s@%s ",
+ accept_p->nickptr,
+ accept_p->userptr, accept_p->hostptr);
+ }
+
+ if (nicks[0] != '\0')
+ {
+ *(t - 1) = '\0';
+ sendto_one(source_p, form_str(RPL_ACCEPTLIST),
+ me.name, source_p->name, nicks);
+ }
+
+ sendto_one(source_p, form_str(RPL_ENDOFACCEPT),
+ me.name, source_p->name);
+}
+
+/*! \brief Allocates and adds a split_nuh_item holding a nick!user\@host
+ * mask to a Client's acceptlist.
+ *
+ * \param nuh A split_nuh_item already prepared with required masks.
+ * \param source_p The actual Client the new accept is added to.
+ */
+static void
+add_accept(const struct split_nuh_item *nuh, struct Client *source_p)
+{
+ struct split_nuh_item *accept_p = MyMalloc(sizeof(*accept_p));
+
+ DupString(accept_p->nickptr, nuh->nickptr);
+ DupString(accept_p->userptr, nuh->userptr);
+ DupString(accept_p->hostptr, nuh->hostptr);
+
+ dlinkAdd(accept_p, &accept_p->node, &source_p->localClient->acceptlist);
+
+ list_accepts(source_p);
+}
+
+/*! \brief ACCEPT command handler
+ *
+ * \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] = list of masks to be accepted or removed (optional)
+ */
+static void
+m_accept(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ char *mask = NULL;
+ char *p = NULL;
+ char nick[NICKLEN + 1];
+ char user[USERLEN + 1];
+ char host[HOSTLEN + 1];
+ struct split_nuh_item nuh;
+ struct split_nuh_item *accept_p = NULL;
+
+ if (EmptyString(parv[1]) || !irccmp(parv[1], "*"))
+ {
+ list_accepts(source_p);
+ return;
+ }
+
+ for (mask = strtoken(&p, parv[1], ","); mask != NULL;
+ mask = strtoken(&p, NULL, ","))
+ {
+ if (*mask == '-' && *++mask != '\0')
+ {
+ nuh.nuhmask = mask;
+ nuh.nickptr = nick;
+ nuh.userptr = user;
+ nuh.hostptr = host;
+
+ nuh.nicksize = sizeof(nick);
+ nuh.usersize = sizeof(user);
+ nuh.hostsize = sizeof(host);
+
+ split_nuh(&nuh);
+
+ if ((accept_p = find_accept(nick, user, host, source_p, 0)) == NULL)
+ {
+ sendto_one(source_p, form_str(ERR_ACCEPTNOT),
+ me.name, source_p->name, nick, user, host);
+ continue;
+ }
+
+ del_accept(accept_p, source_p);
+ }
+ else if (*mask != '\0')
+ {
+ if (dlink_list_length(&source_p->localClient->acceptlist) >=
+ ConfigFileEntry.max_accept)
+ {
+ sendto_one(source_p, form_str(ERR_ACCEPTFULL),
+ me.name, source_p->name);
+ return;
+ }
+
+ nuh.nuhmask = mask;
+ nuh.nickptr = nick;
+ nuh.userptr = user;
+ nuh.hostptr = host;
+
+ nuh.nicksize = sizeof(nick);
+ nuh.usersize = sizeof(user);
+ nuh.hostsize = sizeof(host);
+
+ split_nuh(&nuh);
+
+ if ((accept_p = find_accept(nick, user, host, source_p, 0)) != NULL)
+ {
+ sendto_one(source_p, form_str(ERR_ACCEPTEXIST),
+ me.name, source_p->name, nick, user, host);
+ continue;
+ }
+
+ add_accept(&nuh, source_p);
+ }
+ }
+}
+
+static struct Message accept_msgtab = {
+ "ACCEPT", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_accept, m_ignore, m_ignore, m_accept, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&accept_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&accept_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_admin.c b/modules/m_admin.c
new file mode 100644
index 0000000..b66f649
--- /dev/null
+++ b/modules/m_admin.c
@@ -0,0 +1,157 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ *
+ * Copyright (C) 2002 by the past and present ircd coders, and others.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/*! \file m_admin.c
+ * \brief Includes required functions for processing the ADMIN command.
+ * \version $Id$
+ */
+
+#include "stdinc.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 "irc_string.h"
+
+
+
+/*! \brief Sends administrative information about this server.
+ *
+ * \param source_p Pointer to client to report to
+ */
+static void
+do_admin(struct Client *source_p)
+{
+ const char *me_name = ID_or_name(&me, source_p->from);
+ const char *nick = ID_or_name(source_p, source_p->from);
+
+ sendto_realops_flags(UMODE_SPY, L_ALL,
+ "ADMIN requested by %s (%s@%s) [%s]",
+ source_p->name, source_p->username,
+ source_p->host, source_p->servptr->name);
+
+ sendto_one(source_p, form_str(RPL_ADMINME),
+ me_name, nick, me.name);
+
+ if (AdminInfo.name != NULL)
+ sendto_one(source_p, form_str(RPL_ADMINLOC1),
+ me_name, nick, AdminInfo.name);
+ if (AdminInfo.description != NULL)
+ sendto_one(source_p, form_str(RPL_ADMINLOC2),
+ me_name, nick, AdminInfo.description);
+ if (AdminInfo.email != NULL)
+ sendto_one(source_p, form_str(RPL_ADMINEMAIL),
+ me_name, nick, AdminInfo.email);
+}
+
+/*! \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/servername
+ */
+static void
+m_admin(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ static time_t last_used = 0;
+
+ if ((last_used + ConfigFileEntry.pace_wait_simple) > CurrentTime)
+ {
+ sendto_one(source_p,form_str(RPL_LOAD2HI),
+ me.name, source_p->name);
+ return;
+ }
+
+ last_used = CurrentTime;
+
+ if (!ConfigFileEntry.disable_remote)
+ if (hunt_server(client_p, source_p, ":%s ADMIN :%s", 1,
+ parc, parv) != HUNTED_ISME)
+ return;
+
+ do_admin(source_p);
+}
+
+/*! \brief ADMIN command handler (called by operators 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:
+ * - parv[0] = sender prefix
+ * - parv[1] = nickname/servername
+ */
+static void
+ms_admin(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (hunt_server(client_p, source_p, ":%s ADMIN :%s", 1,
+ parc, parv) != HUNTED_ISME)
+ return;
+
+ if (IsClient(source_p))
+ do_admin(source_p);
+}
+
+static struct Message admin_msgtab = {
+ "ADMIN", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_admin, ms_admin, m_ignore, ms_admin, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&admin_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&admin_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_away.c b/modules/m_away.c
new file mode 100644
index 0000000..700494f
--- /dev/null
+++ b/modules/m_away.c
@@ -0,0 +1,144 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_away.c: Sets/removes away status on 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 "client.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+#include "conf.h"
+#include "s_serv.h"
+#include "packet.h"
+#include "s_user.h"
+
+
+/*
+ * m_away
+ * parv[0] = sender prefix
+ * parv[1] = away message
+ */
+static void
+m_away(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (!IsFloodDone(source_p))
+ flood_endgrace(source_p);
+
+ if (parc < 2 || EmptyString(parv[1]))
+ {
+ /* Marking as not away */
+ if (source_p->away[0])
+ {
+ /* we now send this only if they were away before --is */
+ sendto_server(client_p, CAP_TS6, NOCAPS,
+ ":%s AWAY", ID(source_p));
+ sendto_server(client_p, NOCAPS, CAP_TS6,
+ ":%s AWAY", source_p->name);
+ source_p->away[0] = '\0';
+ }
+
+ sendto_one(source_p, form_str(RPL_UNAWAY),
+ me.name, source_p->name);
+ return;
+ }
+
+ if ((CurrentTime - source_p->localClient->last_away) < ConfigFileEntry.pace_wait)
+ {
+ sendto_one(source_p, form_str(RPL_LOAD2HI),
+ me.name, source_p->name);
+ return;
+ }
+
+ source_p->localClient->last_away = CurrentTime;
+ strlcpy(source_p->away, parv[1], sizeof(source_p->away));
+
+ sendto_server(client_p, CAP_TS6, NOCAPS,
+ ":%s AWAY :%s", ID(source_p), source_p->away);
+ sendto_server(client_p, NOCAPS, CAP_TS6,
+ ":%s AWAY :%s", source_p->name, source_p->away);
+ sendto_one(source_p, form_str(RPL_NOWAWAY), me.name, source_p->name);
+}
+
+static void
+ms_away(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (!IsClient(source_p))
+ return;
+
+ if (parc < 2 || EmptyString(parv[1]))
+ {
+ /* Marking as not away */
+ if (source_p->away[0])
+ {
+ /* we now send this only if they were away before --is */
+ sendto_server(client_p, CAP_TS6, NOCAPS,
+ ":%s AWAY", ID(source_p));
+ sendto_server(client_p, NOCAPS, CAP_TS6,
+ ":%s AWAY", source_p->name);
+ source_p->away[0] = '\0';
+ }
+
+ return;
+ }
+
+ strlcpy(source_p->away, parv[1], sizeof(source_p->away));
+
+ sendto_server(client_p, CAP_TS6, NOCAPS,
+ ":%s AWAY :%s", ID(source_p), source_p->away);
+ sendto_server(client_p, NOCAPS, CAP_TS6,
+ ":%s AWAY :%s", source_p->name, source_p->away);
+}
+
+static struct Message away_msgtab = {
+ "AWAY", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_away, ms_away, m_ignore, m_away, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&away_msgtab);
+ add_isupport("AWAYLEN", NULL, AWAYLEN);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&away_msgtab);
+ delete_isupport("AWAYLEN");
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_cap.c b/modules/m_cap.c
new file mode 100644
index 0000000..0633da3
--- /dev/null
+++ b/modules/m_cap.c
@@ -0,0 +1,433 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ *
+ * Copyright (C) 2004 Kevin L. Mitchell <klmitch@mit.edu>
+ * Copyright (C) 2006-2012 Hybrid Development Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * $Id$
+ */
+
+/** @file
+ * @brief Capability negotiation commands
+ * @version $Id$
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "conf.h"
+#include "s_user.h"
+#include "s_serv.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+#include "packet.h"
+#include "irc_string.h"
+
+
+#define CAPFL_HIDDEN 0x0001 /**< Do not advertize this capability */
+#define CAPFL_PROHIBIT 0x0002 /**< Client may not set this capability */
+#define CAPFL_PROTO 0x0004 /**< Cap must be acknowledged by client */
+#define CAPFL_STICKY 0x0008 /**< Cap may not be cleared once set */
+
+typedef int (*bqcmp)(const void *, const void *);
+
+static struct capabilities
+{
+ unsigned int cap;
+ unsigned int flags;
+ const char *name;
+ size_t namelen;
+} capab_list[] = {
+#define _CAP(cap, flags, name) \
+ { (cap), (flags), (name), sizeof(name) - 1 }
+ _CAP(CAP_MULTI_PREFIX, 0, "multi-prefix")
+#undef _CAP
+};
+
+#define CAPAB_LIST_LEN (sizeof(capab_list) / sizeof(struct capabilities))
+
+static int
+capab_sort(const struct capabilities *cap1, const struct capabilities *cap2)
+{
+ return strcasecmp(cap1->name, cap2->name);
+}
+
+static int
+capab_search(const char *key, const struct capabilities *cap)
+{
+ const char *rb = cap->name;
+
+ while (ToLower(*key) == ToLower(*rb)) /* walk equivalent part of strings */
+ if (*key++ == '\0') /* hit the end, all right... */
+ return 0;
+ else /* OK, let's move on... */
+ rb++;
+
+ /*
+ * If the character they differ on happens to be a space, and it happens
+ * to be the same length as the capability name, then we've found a
+ * match; otherwise, return the difference of the two.
+ */
+ return (IsSpace(*key) && *rb == '\0') ? 0 : (ToLower(*key) - ToLower(*rb));
+}
+
+static struct capabilities *
+find_cap(const char **caplist_p, int *neg_p)
+{
+ static int inited = 0;
+ const char *caplist = *caplist_p;
+ struct capabilities *cap = NULL;
+
+ *neg_p = 0; /* clear negative flag... */
+
+ if (!inited)
+ {
+ /* First, let's sort the array... */
+ qsort(capab_list, CAPAB_LIST_LEN, sizeof(struct capabilities), (bqcmp)capab_sort);
+ ++inited;
+ }
+
+ /* Next, find first non-whitespace character... */
+ while (*caplist && IsSpace(*caplist))
+ ++caplist;
+
+ /* We are now at the beginning of an element of the list; is it negative? */
+ if (*caplist == '-')
+ {
+ ++caplist; /* yes; step past the flag... */
+ *neg_p = 1; /* remember that it is negative... */
+ }
+
+ /* OK, now see if we can look up the capability... */
+ if (*caplist)
+ {
+ if (!(cap = bsearch(caplist, capab_list, CAPAB_LIST_LEN,
+ sizeof(struct capabilities),
+ (bqcmp)capab_search)))
+ {
+ /* Couldn't find the capability; advance to first whitespace character */
+ while (*caplist && !IsSpace(*caplist))
+ ++caplist;
+ }
+ else
+ caplist += cap->namelen; /* advance to end of capability name */
+ }
+
+ assert(caplist != *caplist_p || !*caplist); /* we *must* advance */
+
+ /* move ahead in capability list string--or zero pointer if we hit end */
+ *caplist_p = *caplist ? caplist : 0;
+
+ return cap; /* and return the capability (if any) */
+}
+
+/** Send a CAP \a subcmd list of capability changes to \a source_p.
+ * If more than one line is necessary, each line before the last has
+ * an added "*" parameter before that line's capability list.
+ * @param[in] source_p Client receiving capability list.
+ * @param[in] set Capabilities to show as set (with ack and sticky modifiers).
+ * @param[in] rem Capabalities to show as removed (with no other modifier).
+ * @param[in] subcmd Name of capability subcommand.
+ */
+static int
+send_caplist(struct Client *source_p, unsigned int set,
+ unsigned int rem, const char *subcmd)
+{
+ char capbuf[IRCD_BUFSIZE] = "", pfx[16];
+ char cmdbuf[IRCD_BUFSIZE] = "";
+ unsigned int i, loc, len, flags, pfx_len, clen;
+
+ /* set up the buffer for the final LS message... */
+ clen = snprintf(cmdbuf, sizeof(capbuf), ":%s CAP %s %s ", me.name,
+ source_p->name[0] ? source_p->name : "*", subcmd);
+
+ for (i = 0, loc = 0; i < CAPAB_LIST_LEN; ++i)
+ {
+ flags = capab_list[i].flags;
+
+ /*
+ * This is a little bit subtle, but just involves applying de
+ * Morgan's laws to the obvious check: We must display the
+ * capability if (and only if) it is set in \a rem or \a set, or
+ * if both are null and the capability is hidden.
+ */
+ if (!(rem && (rem & capab_list[i].cap)) &&
+ !(set && (set & capab_list[i].cap)) &&
+ (rem || set || (flags & CAPFL_HIDDEN)))
+ continue;
+
+ /* Build the prefix (space separator and any modifiers needed). */
+ pfx_len = 0;
+
+ if (loc)
+ pfx[pfx_len++] = ' ';
+ if (rem && (rem & capab_list[i].cap))
+ pfx[pfx_len++] = '-';
+ else
+ {
+ if (flags & CAPFL_PROTO)
+ pfx[pfx_len++] = '~';
+ if (flags & CAPFL_STICKY)
+ pfx[pfx_len++] = '=';
+ }
+
+ pfx[pfx_len] = '\0';
+
+ len = capab_list[i].namelen + pfx_len; /* how much we'd add... */
+
+ if (sizeof(capbuf) < (clen + loc + len + 15))
+ {
+ /* would add too much; must flush */
+ sendto_one(source_p, "%s* :%s", cmdbuf, capbuf);
+ capbuf[(loc = 0)] = '\0'; /* re-terminate the buffer... */
+ }
+
+ loc += snprintf(capbuf + loc, sizeof(capbuf) - loc,
+ "%s%s", pfx, capab_list[i].name);
+ }
+
+ sendto_one(source_p, "%s:%s", cmdbuf, capbuf);
+
+ return 0; /* convenience return */
+}
+
+static int
+cap_ls(struct Client *source_p, const char *caplist)
+{
+ if (IsUnknown(source_p)) /* registration hasn't completed; suspend it... */
+ source_p->localClient->registration |= REG_NEED_CAP;
+
+ return send_caplist(source_p, 0, 0, "LS"); /* send list of capabilities */
+}
+
+static int
+cap_req(struct Client *source_p, const char *caplist)
+{
+ const char *cl = caplist;
+ struct capabilities *cap = NULL;
+ unsigned int set = 0, rem = 0;
+ unsigned int cs = source_p->localClient->cap_client; /* capability set */
+ unsigned int as = source_p->localClient->cap_active; /* active set */
+ int neg = 0;
+
+ if (IsUnknown(source_p)) /* registration hasn't completed; suspend it... */
+ source_p->localClient->registration |= REG_NEED_CAP;
+
+ while (cl) { /* walk through the capabilities list... */
+ if (!(cap = find_cap(&cl, &neg)) /* look up capability... */
+ || (!neg && (cap->flags & CAPFL_PROHIBIT)) /* is it prohibited? */
+ || (neg && (cap->flags & CAPFL_STICKY))) { /* is it sticky? */
+ sendto_one(source_p, ":%s CAP %s NAK :%s", me.name,
+ source_p->name[0] ? source_p->name : "*", caplist);
+ return 0; /* can't complete requested op... */
+ }
+
+ if (neg)
+ {
+ /* set or clear the capability... */
+ rem |= cap->cap;
+ set &= ~cap->cap;
+ cs &= ~cap->cap;
+
+ if (!(cap->flags & CAPFL_PROTO))
+ as &= ~cap->cap;
+ }
+ else
+ {
+ rem &= ~cap->cap;
+ set |= cap->cap;
+ cs |= cap->cap;
+
+ if (!(cap->flags & CAPFL_PROTO))
+ as |= cap->cap;
+ }
+ }
+
+ /* Notify client of accepted changes and copy over results. */
+ send_caplist(source_p, set, rem, "ACK");
+
+ source_p->localClient->cap_client = cs;
+ source_p->localClient->cap_active = as;
+
+ return 0;
+}
+
+static int
+cap_ack(struct Client *source_p, const char *caplist)
+{
+ const char *cl = caplist;
+ struct capabilities *cap = NULL;
+ int neg = 0;
+
+ /*
+ * Coming from the client, this generally indicates that the client
+ * is using a new backwards-incompatible protocol feature. As such,
+ * it does not require further response from the server.
+ */
+ while (cl)
+ {
+ /* walk through the capabilities list... */
+ if (!(cap = find_cap(&cl, &neg)) || /* look up capability... */
+ (neg ? (source_p->localClient->cap_active & cap->cap) :
+ !(source_p->localClient->cap_active & cap->cap))) /* uh... */
+ continue;
+
+ if (neg) /* set or clear the active capability... */
+ source_p->localClient->cap_active &= ~cap->cap;
+ else
+ source_p->localClient->cap_active |= cap->cap;
+ }
+
+ return 0;
+}
+
+static int
+cap_clear(struct Client *source_p, const char *caplist)
+{
+ struct capabilities *cap = NULL;
+ unsigned int ii;
+ unsigned int cleared = 0;
+
+ for (ii = 0; ii < CAPAB_LIST_LEN; ++ii)
+ {
+ cap = &capab_list[ii];
+
+ /* Only clear active non-sticky capabilities. */
+ if (!(source_p->localClient->cap_active & cap->cap) || (cap->flags & CAPFL_STICKY))
+ continue;
+
+ cleared |= cap->cap;
+ source_p->localClient->cap_client &= ~cap->cap;
+
+ if (!(cap->flags & CAPFL_PROTO))
+ source_p->localClient->cap_active &= ~cap->cap;
+ }
+
+ return send_caplist(source_p, 0, cleared, "ACK");
+}
+
+static int
+cap_end(struct Client *source_p, const char *caplist)
+{
+ if (!IsUnknown(source_p)) /* registration has completed... */
+ return 0; /* so just ignore the message... */
+
+ /* capability negotiation is now done... */
+ source_p->localClient->registration &= ~REG_NEED_CAP;
+
+ /* if client is now done... */
+ if (!source_p->localClient->registration)
+ {
+ register_local_user(source_p);
+ return 0;
+ }
+
+ return 0; /* Can't do registration yet... */
+}
+
+static int
+cap_list(struct Client *source_p, const char *caplist)
+{
+ /* Send the list of the client's capabilities */
+ return send_caplist(source_p, source_p->localClient->cap_client, 0, "LIST");
+}
+
+static struct subcmd
+{
+ const char *cmd;
+ int (*proc)(struct Client *, const char *);
+} cmdlist[] = {
+ { "ACK", cap_ack },
+ { "CLEAR", cap_clear },
+ { "END", cap_end },
+ { "LIST", cap_list },
+ { "LS", cap_ls },
+ { "NAK", NULL },
+ { "REQ", cap_req }
+};
+
+static int
+subcmd_search(const char *cmd, const struct subcmd *elem)
+{
+ return strcasecmp(cmd, elem->cmd);
+}
+
+/** Handle a capability request or response from a client.
+ * \param client_p Client that sent us the message.
+ * \param source_p Original source of message.
+ * \param parc Number of arguments.
+ * \param parv Argument vector.
+ */
+static void
+m_cap(struct Client *client_p, struct Client *source_p, int parc, char *parv[])
+{
+ const char *subcmd = NULL, *caplist = NULL;
+ struct subcmd *cmd = NULL;
+
+ if (EmptyString(parv[1])) /* a subcommand is required */
+ return;
+
+ subcmd = parv[1];
+
+ if (parc > 2) /* a capability list was provided */
+ caplist = parv[2];
+
+ /* find the subcommand handler */
+ if (!(cmd = bsearch(subcmd, cmdlist,
+ sizeof(cmdlist) / sizeof(struct subcmd),
+ sizeof(struct subcmd), (bqcmp)subcmd_search)))
+ {
+ sendto_one(source_p, form_str(ERR_INVALIDCAPCMD), me.name,
+ source_p->name[0] ? source_p->name : "*", subcmd);
+ return;
+ }
+
+ /* then execute it... */
+ if (cmd->proc)
+ (cmd->proc)(source_p, caplist);
+}
+
+static struct Message cap_msgtab = {
+ "CAP", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
+ { m_cap, m_cap, m_ignore, m_ignore, m_cap, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&cap_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&cap_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_capab.c b/modules/m_capab.c
new file mode 100644
index 0000000..7714ce2
--- /dev/null
+++ b/modules/m_capab.c
@@ -0,0 +1,89 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_capab.c: Negotiates capabilities with a remote 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 "irc_string.h"
+#include "s_serv.h"
+#include "conf.h"
+#include "parse.h"
+#include "modules.h"
+
+
+/*
+ * mr_capab - CAPAB message handler
+ * parv[0] = sender prefix
+ * parv[1] = space-separated list of capabilities
+ *
+ */
+static void
+mr_capab(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ int i;
+ int cap;
+ char *p = NULL;
+ char *s = NULL;
+
+ if (client_p->localClient->caps && !(IsCapable(client_p, CAP_TS6)))
+ {
+ exit_client(client_p, client_p, "CAPAB received twice");
+ return;
+ }
+
+ SetCapable(client_p, CAP_CAP);
+
+ for (i = 1; i < parc; ++i)
+ for (s = strtoken(&p, parv[i], " "); s;
+ s = strtoken(&p, NULL, " "))
+ if ((cap = find_capability(s)))
+ SetCapable(client_p, cap);
+}
+
+static struct Message capab_msgtab = {
+ "CAPAB", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ { mr_capab, m_ignore, m_ignore, m_ignore, m_ignore, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&capab_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&capab_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_challenge.c b/modules/m_challenge.c
new file mode 100644
index 0000000..4c24b3a
--- /dev/null
+++ b/modules/m_challenge.c
@@ -0,0 +1,207 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_challenge.c: Allows an IRC Operator to securely authenticate.
+ *
+ * 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 "modules.h"
+#include "numeric.h"
+#include "send.h"
+#include "conf.h"
+#include "rsa.h"
+#include "parse.h"
+#include "irc_string.h"
+#include "log.h"
+#include "s_user.h"
+
+
+#ifdef HAVE_LIBCRYPTO
+/* failed_challenge_notice()
+ *
+ * inputs - pointer to client doing /oper ...
+ * - pointer to nick they tried to oper as
+ * - pointer to reason they have failed
+ * output - nothing
+ * side effects - notices all opers of the failed oper attempt if enabled
+ */
+static void
+failed_challenge_notice(struct Client *source_p, const char *name,
+ const char *reason)
+{
+ if (ConfigFileEntry.failed_oper_notice)
+ sendto_realops_flags(UMODE_ALL, L_ALL, "Failed CHALLENGE attempt as %s "
+ "by %s (%s@%s) - %s", name, source_p->name,
+ source_p->username, source_p->host, reason);
+
+ ilog(LOG_TYPE_OPER, "Failed CHALLENGE attempt as %s "
+ "by %s (%s@%s) - %s", name, source_p->name,
+ source_p->username, source_p->host, reason);
+}
+
+/*
+ * m_challenge - generate RSA challenge for wouldbe oper
+ * parv[0] = sender prefix
+ * parv[1] = operator to challenge for, or +response
+ *
+ */
+static void
+m_challenge(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ char *challenge = NULL;
+ struct ConfItem *conf = NULL;
+ struct AccessItem *aconf = NULL;
+
+ if (*parv[1] == '+')
+ {
+ /* Ignore it if we aren't expecting this... -A1kmm */
+ if (source_p->localClient->response == NULL)
+ return;
+
+ if (irccmp(source_p->localClient->response, ++parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_PASSWDMISMATCH), me.name,
+ source_p->name);
+ failed_challenge_notice(source_p, source_p->localClient->auth_oper,
+ "challenge failed");
+ return;
+ }
+
+ conf = find_exact_name_conf(OPER_TYPE, source_p,
+ source_p->localClient->auth_oper, NULL, NULL);
+ if (conf == NULL)
+ {
+ /* XXX: logging */
+ sendto_one (source_p, form_str(ERR_NOOPERHOST), me.name, source_p->name);
+ return;
+ }
+
+ if (attach_conf(source_p, conf) != 0)
+ {
+ sendto_one(source_p,":%s NOTICE %s :Can't attach conf!",
+ me.name, source_p->name);
+ failed_challenge_notice(source_p, conf->name, "can't attach conf!");
+ return;
+ }
+
+ oper_up(source_p);
+
+ ilog(LOG_TYPE_OPER, "OPER %s by %s!%s@%s",
+ source_p->localClient->auth_oper, source_p->name, source_p->username,
+ source_p->host);
+
+ MyFree(source_p->localClient->response);
+ MyFree(source_p->localClient->auth_oper);
+ source_p->localClient->response = NULL;
+ source_p->localClient->auth_oper = NULL;
+ return;
+ }
+
+ MyFree(source_p->localClient->response);
+ MyFree(source_p->localClient->auth_oper);
+ source_p->localClient->response = NULL;
+ source_p->localClient->auth_oper = NULL;
+
+ if ((conf = find_conf_exact(OPER_TYPE,
+ parv[1], source_p->username, source_p->host
+ )) != NULL)
+ aconf = map_to_conf(conf);
+ else if ((conf = find_conf_exact(OPER_TYPE,
+ parv[1], source_p->username,
+ source_p->sockhost)) != NULL)
+ aconf = map_to_conf(conf);
+
+ if (aconf == NULL)
+ {
+ sendto_one (source_p, form_str(ERR_NOOPERHOST), me.name, source_p->name);
+ conf = find_exact_name_conf(OPER_TYPE, NULL, parv[1], NULL, NULL);
+ failed_challenge_notice(source_p, parv[1], (conf != NULL)
+ ? "host mismatch" : "no oper {} block");
+ return;
+ }
+
+ if (aconf->rsa_public_key == NULL)
+ {
+ sendto_one (source_p, ":%s NOTICE %s :I'm sorry, PK authentication "
+ "is not enabled for your oper{} block.", me.name,
+ source_p->name);
+ return;
+ }
+
+ if (!generate_challenge(&challenge, &(source_p->localClient->response),
+ aconf->rsa_public_key))
+ sendto_one(source_p, form_str(RPL_RSACHALLENGE),
+ me.name, source_p->name, challenge);
+
+ DupString(source_p->localClient->auth_oper, conf->name);
+ MyFree(challenge);
+}
+
+static void
+mo_challenge(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ sendto_one(source_p, form_str(RPL_YOUREOPER),
+ me.name, source_p->name);
+}
+
+static struct Message challenge_msgtab = {
+ "CHALLENGE", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_challenge, m_ignore, m_ignore, mo_challenge, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&challenge_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&challenge_msgtab);
+}
+
+#else
+
+static void
+module_init(void)
+{
+}
+
+static void
+module_exit(void)
+{
+}
+#endif
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_close.c b/modules/m_close.c
new file mode 100644
index 0000000..4395935
--- /dev/null
+++ b/modules/m_close.c
@@ -0,0 +1,90 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_close.c: Closes all unregistered connections.
+ *
+ * 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 "send.h"
+#include "parse.h"
+#include "modules.h"
+
+
+/*
+ * mo_close - CLOSE message handler
+ * - added by Darren Reed Jul 13 1992.
+ */
+static void
+mo_close(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ dlink_node *ptr = NULL, *ptr_next = NULL;
+ unsigned int closed = dlink_list_length(&unknown_list);
+
+
+ DLINK_FOREACH_SAFE(ptr, ptr_next, unknown_list.head)
+ {
+ struct Client *target_p = ptr->data;
+
+ sendto_one(source_p, form_str(RPL_CLOSING), me.name, source_p->name,
+ get_client_name(target_p, SHOW_IP), target_p->status);
+
+ /*
+ * exit here is safe, because it is guaranteed not to be source_p
+ * because it is unregistered and source_p is an oper.
+ */
+ exit_client(target_p, target_p, "Oper Closing");
+ }
+
+ sendto_one(source_p, form_str(RPL_CLOSEEND),
+ me.name, source_p->name, closed);
+}
+
+static struct Message close_msgtab = {
+ "CLOSE", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_not_oper, m_ignore, m_ignore, mo_close, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&close_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&close_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_connect.c b/modules/m_connect.c
new file mode 100644
index 0000000..10870e1
--- /dev/null
+++ b/modules/m_connect.c
@@ -0,0 +1,322 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_connect.c: Connects to a remote IRC 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 "fdlist.h"
+#include "s_bsd.h"
+#include "conf.h"
+#include "log.h"
+#include "s_serv.h"
+#include "send.h"
+#include "parse.h"
+#include "hash.h"
+#include "modules.h"
+
+
+/*
+ * mo_connect - CONNECT command handler
+ *
+ * Added by Jto 11 Feb 1989
+ *
+ * m_connect
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ * parv[2] = port number
+ * parv[3] = remote server
+ */
+static void
+mo_connect(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ int port;
+ int tmpport;
+ struct ConfItem *conf = NULL;
+ struct AccessItem *aconf = NULL;
+ const struct Client *target_p = NULL;
+
+ if (EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, "CONNECT");
+ return;
+ }
+
+ if (parc > 3)
+ {
+ if (!HasOFlag(source_p, OPER_FLAG_REMOTE))
+ {
+ sendto_one(source_p, form_str(ERR_NOPRIVS),
+ me.name, source_p->name, "connect");
+ return;
+ }
+
+ if (hunt_server(client_p, source_p, ":%s CONNECT %s %s :%s", 3,
+ parc, parv) != HUNTED_ISME)
+ return;
+ }
+
+ if ((target_p = hash_find_server(parv[1])))
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :Connect: Server %s already exists from %s.",
+ me.name, source_p->name, parv[1], target_p->from->name);
+ return;
+ }
+
+ /*
+ * try to find the name, then host, if both fail notify ops and bail
+ */
+ if ((conf = find_matching_name_conf(SERVER_TYPE,
+ parv[1], NULL, NULL, 0)) != NULL)
+ aconf = (struct AccessItem *)map_to_conf(conf);
+ else if ((conf = find_matching_name_conf(SERVER_TYPE,
+ NULL, NULL, parv[1], 0)) != NULL)
+ aconf = (struct AccessItem *)map_to_conf(conf);
+
+ if (conf == NULL || aconf == NULL)
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :Connect: Host %s not listed in ircd.conf",
+ me.name, source_p->name, parv[1]);
+ return;
+ }
+
+ /* Get port number from user, if given. If not specified,
+ * use the default form configuration structure. If missing
+ * from there, then use the precompiled default.
+ */
+ tmpport = port = aconf->port;
+
+ if (parc > 2 && !EmptyString(parv[2]))
+ {
+ if ((port = atoi(parv[2])) <= 0)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :Connect: Illegal port number",
+ me.name, source_p->name);
+ return;
+ }
+ }
+ else if (port <= 0 && (port = PORTNUM) <= 0)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :Connect: missing port number",
+ me.name, source_p->name);
+ return;
+ }
+
+ if (find_servconn_in_progress(conf->name))
+ {
+ sendto_one(source_p, ":%s NOTICE %s :Connect: a connection to %s "
+ "is already in progress.", me.name, source_p->name, conf->name);
+ return;
+ }
+
+ /*
+ * Notify all operators about remote connect requests
+ */
+ ilog(LOG_TYPE_IRCD, "CONNECT From %s : %s %s",
+ source_p->name, parv[1], parv[2] ? parv[2] : "");
+
+ aconf->port = port;
+
+ /* at this point we should be calling connect_server with a valid
+ * C:line and a valid port in the C:line
+ */
+ if (serv_connect(aconf, source_p))
+ {
+ if (!ConfigServerHide.hide_server_ips && HasUMode(source_p, UMODE_ADMIN))
+ sendto_one(source_p, ":%s NOTICE %s :*** Connecting to %s[%s].%d",
+ me.name, source_p->name, aconf->host,
+ conf->name, aconf->port);
+ else
+ sendto_one(source_p, ":%s NOTICE %s :*** Connecting to %s.%d",
+ me.name, source_p->name, conf->name, aconf->port);
+ }
+ else
+ {
+ sendto_one(source_p, ":%s NOTICE %s :*** Couldn't connect to %s.%d",
+ me.name, source_p->name, conf->name, aconf->port);
+ }
+
+ /* client is either connecting with all the data it needs or has been
+ * destroyed
+ */
+ aconf->port = tmpport;
+}
+
+/*
+ * ms_connect - CONNECT command handler
+ *
+ * Added by Jto 11 Feb 1989
+ *
+ * m_connect
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ * parv[2] = port number
+ * parv[3] = remote server
+ */
+static void
+ms_connect(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ int port;
+ int tmpport;
+ struct ConfItem *conf = NULL;
+ struct AccessItem *aconf = NULL;
+ const struct Client *target_p = NULL;
+
+ if (hunt_server(client_p, source_p,
+ ":%s CONNECT %s %s :%s", 3, parc, parv) != HUNTED_ISME)
+ return;
+
+ if (EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, "CONNECT");
+ return;
+ }
+
+ if ((target_p = hash_find_server(parv[1])))
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :Connect: Server %s already exists from %s.",
+ me.name, source_p->name, parv[1], target_p->from->name);
+ return;
+ }
+
+ /*
+ * try to find the name, then host, if both fail notify ops and bail
+ */
+ if ((conf = find_matching_name_conf(SERVER_TYPE,
+ parv[1], NULL, NULL, 0)) != NULL)
+ aconf = map_to_conf(conf);
+ else if ((conf = find_matching_name_conf(SERVER_TYPE,
+ NULL, NULL, parv[1], 0)) != NULL)
+ aconf = map_to_conf(conf);
+
+ if (conf == NULL || aconf == NULL)
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :Connect: Host %s not listed in ircd.conf",
+ me.name, source_p->name, parv[1]);
+ return;
+ }
+
+ /* Get port number from user, if given. If not specified,
+ * use the default form configuration structure. If missing
+ * from there, then use the precompiled default.
+ */
+ tmpport = port = aconf->port;
+
+ if (parc > 2 && !EmptyString(parv[2]))
+ {
+ port = atoi(parv[2]);
+
+ /* if someone sends port 0, and we have a config port.. use it */
+ if (port == 0 && aconf->port)
+ port = aconf->port;
+ else if (port <= 0)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :Connect: Illegal port number",
+ me.name, source_p->name);
+ return;
+ }
+ }
+ else if (port <= 0 && (port = PORTNUM) <= 0)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :Connect: missing port number",
+ me.name, source_p->name);
+ return;
+ }
+
+ if (find_servconn_in_progress(conf->name))
+ {
+ sendto_one(source_p, ":%s NOTICE %s :Connect: a connection to %s "
+ "is already in progress.", me.name, source_p->name, conf->name);
+ return;
+ }
+
+ /*
+ * Notify all operators about remote connect requests
+ */
+ sendto_wallops_flags(UMODE_WALLOP, &me, "Remote CONNECT %s %d from %s",
+ parv[1], port, source_p->name);
+ sendto_server(NULL, NOCAPS, CAP_TS6,
+ ":%s WALLOPS :Remote CONNECT %s %d from %s",
+ me.name, parv[1], port, source_p->name);
+ sendto_server(NULL, CAP_TS6, NOCAPS,
+ ":%s WALLOPS :Remote CONNECT %s %d from %s",
+ me.id, parv[1], port, source_p->name);
+
+ ilog(LOG_TYPE_IRCD, "CONNECT From %s : %s %d",
+ source_p->name, parv[1], port);
+
+ aconf->port = port;
+
+ /*
+ * At this point we should be calling connect_server with a valid
+ * C:line and a valid port in the C:line
+ */
+ if (serv_connect(aconf, source_p))
+ sendto_one(source_p, ":%s NOTICE %s :*** Connecting to %s.%d",
+ me.name, source_p->name, conf->name, aconf->port);
+ else
+ sendto_one(source_p, ":%s NOTICE %s :*** Couldn't connect to %s.%d",
+ me.name, source_p->name, conf->name, aconf->port);
+ /*
+ * Client is either connecting with all the data it needs or has been
+ * destroyed
+ */
+ aconf->port = tmpport;
+}
+
+static struct Message connect_msgtab = {
+ "CONNECT", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_not_oper, ms_connect, m_ignore, mo_connect, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&connect_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&connect_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_dline.c b/modules/m_dline.c
new file mode 100644
index 0000000..182489b
--- /dev/null
+++ b/modules/m_dline.c
@@ -0,0 +1,592 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_dline.c: Bans 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 "channel.h"
+#include "client.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "hostmask.h"
+#include "numeric.h"
+#include "fdlist.h"
+#include "s_bsd.h"
+#include "conf.h"
+#include "log.h"
+#include "s_misc.h"
+#include "send.h"
+#include "hash.h"
+#include "s_serv.h"
+#include "s_gline.h"
+#include "parse.h"
+#include "modules.h"
+
+
+/* apply_tdline()
+ *
+ * inputs -
+ * output - NONE
+ * side effects - tkline as given is placed
+ */
+static void
+apply_tdline(struct Client *source_p, struct ConfItem *conf,
+ const char *current_date, int tkline_time)
+{
+ struct AccessItem *aconf;
+
+ aconf = map_to_conf(conf);
+ aconf->hold = CurrentTime + tkline_time;
+ SetConfTemporary(aconf);
+ add_conf_by_address(CONF_DLINE, aconf);
+
+
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s added temporary %d min. D-Line for [%s] [%s]",
+ get_oper_name(source_p), tkline_time/60,
+ aconf->host, aconf->reason);
+
+ sendto_one(source_p, ":%s NOTICE %s :Added temporary %d min. D-Line [%s]",
+ MyConnect(source_p) ? me.name : ID_or_name(&me, source_p->from),
+ source_p->name, tkline_time/60, aconf->host);
+ ilog(LOG_TYPE_DLINE, "%s added temporary %d min. D-Line for [%s] [%s]",
+ source_p->name, tkline_time/60, aconf->host, aconf->reason);
+
+ rehashed_klines = 1;
+}
+
+/* static int remove_tdline_match(const char *host, const char *user)
+ * Input: An ip to undline.
+ * Output: returns YES on success, NO if no tdline removed.
+ * Side effects: Any matching tdlines are removed.
+ */
+static int
+remove_tdline_match(const char *host)
+{
+ struct irc_ssaddr iphost, *piphost;
+ struct AccessItem *aconf;
+ int t;
+
+ if ((t = parse_netmask(host, &iphost, NULL)) != HM_HOST)
+ {
+#ifdef IPV6
+ if (t == HM_IPV6)
+ t = AF_INET6;
+ else
+#endif
+ t = AF_INET;
+ piphost = &iphost;
+ }
+ else
+ {
+ t = 0;
+ piphost = NULL;
+ }
+
+ if ((aconf = find_conf_by_address(host, piphost, CONF_DLINE, t, NULL, NULL, 0)))
+ {
+ if (IsConfTemporary(aconf))
+ {
+ delete_one_address_conf(host, aconf);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* mo_dline()
+ *
+ * inputs - pointer to server
+ * - pointer to client
+ * - parameter count
+ * - parameter list
+ * output -
+ * side effects - D line is added
+ *
+ */
+static void
+mo_dline(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ char def_reason[] = "<No reason specified>";
+ char *dlhost = NULL, *oper_reason = NULL, *reason = NULL;
+ char *target_server = NULL;
+ const char *creason;
+ const struct Client *target_p = NULL;
+ struct irc_ssaddr daddr;
+ struct ConfItem *conf=NULL;
+ struct AccessItem *aconf=NULL;
+ time_t tkline_time=0;
+ int bits, t;
+ const char *current_date = NULL;
+ time_t cur_time;
+ char hostip[HOSTIPLEN + 1];
+ char buffer[IRCD_BUFSIZE];
+
+ if (!HasOFlag(source_p, OPER_FLAG_DLINE))
+ {
+ sendto_one(source_p, form_str(ERR_NOPRIVS),
+ me.name, source_p->name, "dline");
+ return;
+ }
+
+ if (parse_aline("DLINE", source_p, parc, parv, AWILD, &dlhost,
+ NULL, &tkline_time, &target_server, &reason) < 0)
+ return;
+
+ if (target_server != NULL)
+ {
+ if (HasID(source_p))
+ {
+ sendto_server(NULL, CAP_DLN|CAP_TS6, NOCAPS,
+ ":%s DLINE %s %lu %s :%s",
+ source_p->id, target_server, (unsigned long)tkline_time,
+ dlhost, reason);
+ sendto_server(NULL, CAP_DLN, CAP_TS6,
+ ":%s DLINE %s %lu %s :%s",
+ source_p->name, target_server, (unsigned long)tkline_time,
+ dlhost, reason);
+ }
+ else
+ sendto_server(NULL, CAP_DLN, NOCAPS,
+ ":%s DLINE %s %lu %s :%s",
+ source_p->name, target_server, (unsigned long)tkline_time,
+ dlhost, reason);
+
+ /* Allow ON to apply local kline as well if it matches */
+ if (!match(target_server, me.name))
+ return;
+ }
+ else
+ cluster_a_line(source_p, "DLINE", CAP_DLN, SHARED_DLINE,
+ "%d %s :%s", tkline_time, dlhost, reason);
+
+ if ((t = parse_netmask(dlhost, NULL, &bits)) == HM_HOST)
+ {
+ if ((target_p = find_chasing(client_p, source_p, dlhost, NULL)) == NULL)
+ return;
+
+ if (!MyConnect(target_p))
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :Can't DLINE nick on another server",
+ me.name, source_p->name);
+ return;
+ }
+
+ if (IsExemptKline(target_p))
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :%s is E-lined", me.name,
+ source_p->name, target_p->name);
+ return;
+ }
+
+ getnameinfo((struct sockaddr *)&target_p->localClient->ip,
+ target_p->localClient->ip.ss_len, hostip,
+ sizeof(hostip), NULL, 0, NI_NUMERICHOST);
+ dlhost = hostip;
+ t = parse_netmask(dlhost, NULL, &bits);
+ assert(t == HM_IPV4 || t == HM_IPV6);
+ }
+
+ if (bits < 8)
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :For safety, bitmasks less than 8 require conf access.",
+ me.name, source_p->name);
+ return;
+ }
+
+#ifdef IPV6
+ if (t == HM_IPV6)
+ t = AF_INET6;
+ else
+#endif
+ t = AF_INET;
+
+ parse_netmask(dlhost, &daddr, NULL);
+
+ if ((aconf = find_dline_conf(&daddr, t)) != NULL)
+ {
+ creason = aconf->reason ? aconf->reason : def_reason;
+ if (IsConfExemptKline(aconf))
+ sendto_one(source_p,
+ ":%s NOTICE %s :[%s] is (E)d-lined by [%s] - %s",
+ me.name, source_p->name, dlhost, aconf->host, creason);
+ else
+ sendto_one(source_p,
+ ":%s NOTICE %s :[%s] already D-lined by [%s] - %s",
+ me.name, source_p->name, dlhost, aconf->host, creason);
+ return;
+ }
+
+ cur_time = CurrentTime;
+ current_date = smalldate(cur_time);
+
+ /* Look for an oper reason */
+ if ((oper_reason = strchr(reason, '|')) != NULL)
+ *oper_reason++ = '\0';
+
+ if (!valid_comment(source_p, reason, 1))
+ return;
+
+ conf = make_conf_item(DLINE_TYPE);
+ aconf = map_to_conf(conf);
+ DupString(aconf->host, dlhost);
+
+ if (tkline_time != 0)
+ {
+ snprintf(buffer, sizeof(buffer), "Temporary D-line %d min. - %s (%s)",
+ (int)(tkline_time/60), reason, current_date);
+ DupString(aconf->reason, buffer);
+ if (oper_reason != NULL)
+ DupString(aconf->oper_reason, oper_reason);
+ apply_tdline(source_p, conf, current_date, tkline_time);
+ }
+ else
+ {
+ snprintf(buffer, sizeof(buffer), "%s (%s)", reason, current_date);
+ DupString(aconf->reason, buffer);
+ if (oper_reason != NULL)
+ DupString(aconf->oper_reason, oper_reason);
+ add_conf_by_address(CONF_DLINE, aconf);
+ write_conf_line(source_p, conf, current_date, cur_time);
+ }
+
+ rehashed_klines = 1;
+}
+
+static void
+ms_dline(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ char def_reason[] = "<No reason specified>";
+ char *dlhost, *oper_reason, *reason;
+ const char *creason;
+ const struct Client *target_p = NULL;
+ struct irc_ssaddr daddr;
+ struct ConfItem *conf=NULL;
+ struct AccessItem *aconf=NULL;
+ time_t tkline_time=0;
+ int bits, t;
+ const char *current_date = NULL;
+ time_t cur_time;
+ char hostip[HOSTIPLEN + 1];
+ char buffer[IRCD_BUFSIZE];
+
+ if (parc != 5 || EmptyString(parv[4]))
+ return;
+
+ /* parv[0] parv[1] parv[2] parv[3] parv[4] */
+ /* oper target_server tkline_time host reason */
+ sendto_match_servs(source_p, parv[1], CAP_DLN,
+ "DLINE %s %s %s :%s",
+ parv[1], parv[2], parv[3], parv[4]);
+
+ if (!match(parv[1], me.name))
+ return;
+
+ tkline_time = valid_tkline(parv[2], TK_SECONDS);
+ dlhost = parv[3];
+ reason = parv[4];
+
+ if (HasFlag(source_p, FLAGS_SERVICE) || find_matching_name_conf(ULINE_TYPE, source_p->servptr->name,
+ source_p->username, source_p->host,
+ SHARED_DLINE))
+ {
+ if (!IsClient(source_p))
+ return;
+ if ((t = parse_netmask(dlhost, NULL, &bits)) == HM_HOST)
+ {
+ if ((target_p = find_chasing(client_p, source_p, dlhost, NULL)) == NULL)
+ return;
+
+ if (!MyConnect(target_p))
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :Can't DLINE nick on another server",
+ me.name, source_p->name);
+ return;
+ }
+
+ if (IsExemptKline(target_p))
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :%s is E-lined", me.name,
+ source_p->name, target_p->name);
+ return;
+ }
+
+ getnameinfo((struct sockaddr *)&target_p->localClient->ip,
+ target_p->localClient->ip.ss_len, hostip,
+ sizeof(hostip), NULL, 0, NI_NUMERICHOST);
+ dlhost = hostip;
+ t = parse_netmask(dlhost, NULL, &bits);
+ assert(t == HM_IPV4 || t == HM_IPV6);
+ }
+
+ if (bits < 8)
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :For safety, bitmasks less than 8 require conf access.",
+ me.name, source_p->name);
+ return;
+ }
+
+#ifdef IPV6
+ if (t == HM_IPV6)
+ t = AF_INET6;
+ else
+#endif
+ t = AF_INET;
+
+ parse_netmask(dlhost, &daddr, NULL);
+
+ if ((aconf = find_dline_conf(&daddr, t)) != NULL)
+ {
+ creason = aconf->reason ? aconf->reason : def_reason;
+ if (IsConfExemptKline(aconf))
+ sendto_one(source_p,
+ ":%s NOTICE %s :[%s] is (E)d-lined by [%s] - %s",
+ me.name, source_p->name, dlhost, aconf->host, creason);
+ else
+ sendto_one(source_p,
+ ":%s NOTICE %s :[%s] already D-lined by [%s] - %s",
+ me.name, source_p->name, dlhost, aconf->host, creason);
+ return;
+ }
+
+ cur_time = CurrentTime;
+ current_date = smalldate(cur_time);
+
+ /* Look for an oper reason */
+ if ((oper_reason = strchr(reason, '|')) != NULL)
+ *oper_reason++ = '\0';
+
+ if (!valid_comment(source_p, reason, 1))
+ return;
+
+ conf = make_conf_item(DLINE_TYPE);
+ aconf = map_to_conf(conf);
+ DupString(aconf->host, dlhost);
+
+ if (tkline_time != 0)
+ {
+ snprintf(buffer, sizeof(buffer), "Temporary D-line %d min. - %s (%s)",
+ (int)(tkline_time/60), reason, current_date);
+ DupString(aconf->reason, buffer);
+ if (oper_reason != NULL)
+ DupString(aconf->oper_reason, oper_reason);
+ apply_tdline(source_p, conf, current_date, tkline_time);
+ }
+ else
+ {
+ snprintf(buffer, sizeof(buffer), "%s (%s)", reason, current_date);
+ DupString(aconf->reason, buffer);
+ if (oper_reason != NULL)
+ DupString(aconf->oper_reason, oper_reason);
+ add_conf_by_address(CONF_DLINE, aconf);
+ write_conf_line(source_p, conf, current_date, cur_time);
+ }
+
+ rehashed_klines = 1;
+ }
+}
+
+/*
+** m_undline
+** added May 28th 2000 by Toby Verrall <toot@melnet.co.uk>
+** based totally on m_unkline
+** added to hybrid-7 7/11/2000 --is
+**
+** parv[0] = sender nick
+** parv[1] = dline to remove
+*/
+static void
+mo_undline(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ char *addr = NULL, *user = NULL;
+ char *target_server = NULL;
+
+ if (!HasOFlag(source_p, OPER_FLAG_UNDLINE))
+ {
+ sendto_one(source_p, form_str(ERR_NOPRIVS),
+ me.name, source_p->name, "undline");
+ return;
+ }
+
+ if (parc < 2 || EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, "UNDLINE");
+ return;
+ }
+
+ if (parse_aline("UNDLINE", source_p, parc, parv, 0, &user,
+ &addr, NULL, &target_server, NULL) < 0)
+ return;
+
+ if (target_server != NULL)
+ {
+ sendto_match_servs(source_p, target_server, CAP_UNDLN,
+ "UNDLINE %s %s", target_server, addr);
+
+ /* Allow ON to apply local unkline as well if it matches */
+ if (!match(target_server, me.name))
+ return;
+ }
+ else
+ cluster_a_line(source_p, "UNDLINE", CAP_UNDLN, SHARED_UNDLINE,
+ "%s", addr);
+
+ if (remove_tdline_match(addr))
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :Un-Dlined [%s] from temporary D-Lines",
+ me.name, source_p->name, addr);
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s has removed the temporary D-Line for: [%s]",
+ get_oper_name(source_p), addr);
+ ilog(LOG_TYPE_DLINE, "%s removed temporary D-Line for [%s]",
+ source_p->name, addr);
+ return;
+ }
+
+ if (remove_conf_line(DLINE_TYPE, source_p, addr, NULL) > 0)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :D-Line for [%s] is removed",
+ me.name, source_p->name, addr);
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s has removed the D-Line for: [%s]",
+ get_oper_name(source_p), addr);
+ ilog(LOG_TYPE_DLINE, "%s removed D-Line for [%s]",
+ get_oper_name(source_p), addr);
+ }
+ else
+ sendto_one(source_p, ":%s NOTICE %s :No D-Line for [%s] found",
+ me.name, source_p->name, addr);
+}
+
+static void
+me_undline(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ const char *addr = NULL;
+
+ if (parc != 3 || EmptyString(parv[2]))
+ return;
+
+ addr = parv[2];
+
+ if (!IsClient(source_p) || !match(parv[1], me.name))
+ return;
+
+ if (HasFlag(source_p, FLAGS_SERVICE) || find_matching_name_conf(ULINE_TYPE,
+ source_p->servptr->name,
+ source_p->username, source_p->host,
+ SHARED_UNDLINE))
+ {
+ if (remove_tdline_match(addr))
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :Un-Dlined [%s] from temporary D-Lines",
+ me.name, source_p->name, addr);
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s has removed the temporary D-Line for: [%s]",
+ get_oper_name(source_p), addr);
+ ilog(LOG_TYPE_DLINE, "%s removed temporary D-Line for [%s]",
+ source_p->name, addr);
+ return;
+ }
+
+ if (remove_conf_line(DLINE_TYPE, source_p, addr, NULL) > 0)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :D-Line for [%s] is removed",
+ me.name, source_p->name, addr);
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s has removed the D-Line for: [%s]",
+ get_oper_name(source_p), addr);
+ ilog(LOG_TYPE_DLINE, "%s removed D-Line for [%s]",
+ get_oper_name(source_p), addr);
+ }
+ else
+ sendto_one(source_p, ":%s NOTICE %s :No D-Line for [%s] found",
+ me.name, source_p->name, addr);
+ }
+}
+
+static void
+ms_undline(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (parc != 3 || EmptyString(parv[2]))
+ return;
+
+ sendto_match_servs(source_p, parv[1], CAP_UNDLN,
+ "UNDLINE %s %s %s",
+ parv[1], parv[2]);
+
+ me_undline(client_p, source_p, parc, parv);
+}
+
+static struct Message dline_msgtab = {
+ "DLINE", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_not_oper, ms_dline, m_ignore, mo_dline, m_ignore}
+};
+
+static struct Message undline_msgtab = {
+ "UNDLINE", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_not_oper, ms_undline, m_ignore, mo_undline, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&dline_msgtab);
+ mod_add_cmd(&undline_msgtab);
+ add_capability("DLN", CAP_DLN, 1);
+ add_capability("UNDLN", CAP_UNDLN, 1);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&dline_msgtab);
+ mod_del_cmd(&undline_msgtab);
+ delete_capability("UNDLN");
+ delete_capability("DLN");
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_encap.c b/modules/m_encap.c
new file mode 100644
index 0000000..bb312d4
--- /dev/null
+++ b/modules/m_encap.c
@@ -0,0 +1,138 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_encap.c: encapsulated command propagation and parsing
+ *
+ * Copyright (C) 2003 by the past and present ircd coders, and others.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * $Id$
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "parse.h"
+#include "sprintf_irc.h"
+#include "s_serv.h"
+#include "send.h"
+#include "modules.h"
+#include "irc_string.h"
+
+
+/*
+ * ms_encap()
+ *
+ * inputs - destination server, subcommand, parameters
+ * output - none
+ * side effects - propagates subcommand to locally connected servers
+ */
+static void
+ms_encap(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ char buffer[IRCD_BUFSIZE], *ptr = buffer;
+ unsigned int cur_len = 0, len, i;
+#ifdef NOT_USED_YET
+ int paramcount, mpara = 0;
+#endif
+ struct Message *mptr = NULL;
+ MessageHandler handler = 0;
+
+ for (i = 1; i < (unsigned int)parc - 1; i++)
+ {
+ len = strlen(parv[i]) + 1;
+
+ if ((cur_len + len) >= sizeof(buffer))
+ return;
+
+ snprintf(ptr, sizeof(buffer) - cur_len, "%s ", parv[i]);
+ cur_len += len;
+ ptr += len;
+ }
+
+ len = strlen(parv[i]);
+
+ /*
+ * if the final parameter crosses our buffer size, should we bail,
+ * like the rest, or should we truncate? ratbox seems to think truncate,
+ * so i'll do that for now until i can talk to lee. -bill
+ */
+
+ if (parc == 3)
+ snprintf(ptr, sizeof(buffer) - cur_len, "%s", parv[2]);
+ else
+ snprintf(ptr, sizeof(buffer) - cur_len, ":%s", parv[parc - 1]);
+
+ if ((cur_len + len) >= sizeof(buffer))
+ buffer[sizeof(buffer) - 1] = '\0';
+
+ sendto_match_servs(source_p, parv[1], CAP_ENCAP,
+ "ENCAP %s", buffer);
+
+ if (!match(parv[1], me.name))
+ return;
+
+ if ((mptr = find_command(parv[2])) == NULL)
+ return;
+
+#ifdef NOT_USED_YET
+ paramcount = mptr->parameters;
+ mpara = mptr->maxpara;
+#endif
+ mptr->bytes += strlen(buffer);
+
+ /*
+ * yes this is an ugly hack, but it is quicker than copying the entire array again
+ * note: this hack wouldnt be needed if parv[0] were set to the command name, rather
+ * than being derived from the prefix, as it should have been from the beginning.
+ */
+ ptr = parv[0];
+ parv += 2;
+ parc -= 2;
+ parv[0] = ptr;
+
+ if ((handler = mptr->handlers[ENCAP_HANDLER]))
+ (*handler)(client_p, source_p, parc, parv);
+}
+
+static struct Message encap_msgtab = {
+ "ENCAP", 0, 0, 3, MAXPARA, MFLG_SLOW, 0,
+ {m_ignore, m_ignore, ms_encap, m_ignore, m_ignore, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&encap_msgtab);
+ add_capability("ENCAP", CAP_ENCAP, 1);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&encap_msgtab);
+ delete_capability("ENCAP");
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_eob.c b/modules/m_eob.c
new file mode 100644
index 0000000..ceeff0c
--- /dev/null
+++ b/modules/m_eob.c
@@ -0,0 +1,76 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_eob.c: Signifies the end of a server burst.
+ *
+ * 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 "parse.h"
+#include "modules.h"
+
+
+/*
+ * ms_eob - EOB command handler
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+static void
+ms_eob(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ assert(IsServer(source_p));
+ assert(client_p == source_p);
+
+ sendto_realops_flags(UMODE_ALL, L_ALL, "End of burst from %s (%u seconds)",
+ source_p->name,
+ (unsigned int)(CurrentTime - source_p->localClient->firsttime));
+ AddFlag(source_p, FLAGS_EOB);
+}
+
+static struct Message eob_msgtab = {
+ "EOB", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_ignore, ms_eob, m_ignore, m_ignore, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&eob_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&eob_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_etrace.c b/modules/m_etrace.c
new file mode 100644
index 0000000..28b80ae
--- /dev/null
+++ b/modules/m_etrace.c
@@ -0,0 +1,233 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_etrace.c: Traces a path to a client/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"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "fdlist.h"
+#include "s_bsd.h"
+#include "s_serv.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+#include "conf.h"
+
+
+static void report_this_status(struct Client *, struct Client *, int);
+
+/*
+ * do_etrace()
+ */
+static void
+do_etrace(struct Client *source_p, int parc, char *parv[])
+{
+ const char *tname = NULL;
+ struct Client *target_p = NULL;
+ int wilds = 0;
+ int do_all = 0;
+ int full_etrace = 0;
+ dlink_node *ptr;
+
+ sendto_realops_flags(UMODE_SPY, L_ALL,
+ "ETRACE requested by %s (%s@%s) [%s]",
+ source_p->name, source_p->username,
+ source_p->host, source_p->servptr->name);
+
+ if (parc > 1)
+ {
+ if (irccmp(parv[1], "-full") == 0)
+ {
+ ++parv;
+ --parc;
+ full_etrace = 1;
+ }
+ }
+
+ if (parc > 1)
+ {
+ tname = parv[1];
+
+ if (tname != NULL)
+ wilds = has_wildcards(tname);
+ else
+ tname = "*";
+ }
+ else
+ {
+ do_all = 1;
+ tname = "*";
+ }
+
+ if (HasUMode(source_p, UMODE_CCONN_FULL))
+ full_etrace = 1;
+
+ if (!wilds && !do_all)
+ {
+ target_p = hash_find_client(tname);
+
+ if (target_p && MyClient(target_p))
+ report_this_status(source_p, target_p, full_etrace);
+
+ sendto_one(source_p, form_str(RPL_ENDOFTRACE), me.name,
+ source_p->name, tname);
+ return;
+ }
+
+ DLINK_FOREACH(ptr, local_client_list.head)
+ {
+ target_p = ptr->data;
+
+ if (wilds)
+ {
+ if (match(tname, target_p->name))
+ report_this_status(source_p, target_p, full_etrace);
+ }
+ else
+ report_this_status(source_p, target_p, full_etrace);
+ }
+
+ sendto_one(source_p, form_str(RPL_ENDOFTRACE), me.name,
+ source_p->name, tname);
+}
+
+/* mo_etrace()
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+static void
+mo_etrace(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ do_etrace(source_p, parc, parv);
+}
+
+/* report_this_status()
+ *
+ * inputs - pointer to client to report to
+ * - pointer to client to report about
+ * - flag full etrace or not
+ * output - NONE
+ * side effects - NONE
+ */
+static void
+report_this_status(struct Client *source_p, struct Client *target_p,
+ int full_etrace)
+{
+ const char *name;
+ const char *class_name;
+
+ name = get_client_name(target_p, HIDE_IP);
+ class_name = get_client_class(target_p);
+
+ set_time();
+
+ if (target_p->status == STAT_CLIENT)
+ {
+ if (full_etrace)
+ {
+ if (ConfigFileEntry.hide_spoof_ips)
+ sendto_one(source_p, form_str(RPL_ETRACE_FULL),
+ me.name,
+ source_p->name,
+ HasUMode(target_p, UMODE_OPER) ? "Oper" : "User",
+ class_name,
+ target_p->name,
+ target_p->username,
+ target_p->host,
+ IsIPSpoof(target_p) ? "255.255.255.255" : target_p->sockhost,
+ IsIPSpoof(target_p) ? "<hidden>" : target_p->localClient->client_host,
+ IsIPSpoof(target_p) ? "<hidden>" : target_p->localClient->client_server,
+ target_p->info);
+ else
+ sendto_one(source_p, form_str(RPL_ETRACE_FULL),
+ me.name,
+ source_p->name,
+ HasUMode(target_p, UMODE_OPER) ? "Oper" : "User",
+ class_name,
+ target_p->name,
+ target_p->username,
+ target_p->host,
+ target_p->sockhost,
+ target_p->localClient->client_host,
+ target_p->localClient->client_server,
+ target_p->info);
+ }
+ else
+ {
+ if (ConfigFileEntry.hide_spoof_ips)
+ sendto_one(source_p, form_str(RPL_ETRACE),
+ me.name,
+ source_p->name,
+ HasUMode(target_p, UMODE_OPER) ? "Oper" : "User",
+ class_name,
+ target_p->name,
+ target_p->username,
+ target_p->host,
+ IsIPSpoof(target_p) ? "255.255.255.255" : target_p->sockhost,
+ target_p->info);
+ else
+ sendto_one(source_p, form_str(RPL_ETRACE),
+ me.name,
+ source_p->name,
+ HasUMode(target_p, UMODE_OPER) ? "Oper" : "User",
+ class_name,
+ target_p->name,
+ target_p->username,
+ target_p->host,
+ target_p->sockhost,
+ target_p->info);
+ }
+ }
+}
+
+static struct Message etrace_msgtab = {
+ "ETRACE", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_not_oper, m_ignore, m_ignore, mo_etrace, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&etrace_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&etrace_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_gline.c b/modules/m_gline.c
new file mode 100644
index 0000000..1b29445
--- /dev/null
+++ b/modules/m_gline.c
@@ -0,0 +1,575 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ *
+ * Copyright (C) 2002 by the past and present ircd coders, and others.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/*! \file m_gline.c
+ * \brief Includes required functions for processing the GLINE command.
+ * \version $Id$
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "s_gline.h"
+#include "channel.h"
+#include "client.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "hostmask.h"
+#include "numeric.h"
+#include "s_bsd.h"
+#include "conf.h"
+#include "s_misc.h"
+#include "send.h"
+#include "s_serv.h"
+#include "hash.h"
+#include "parse.h"
+#include "modules.h"
+#include "log.h"
+
+#define GLINE_NOT_PLACED 0
+#define GLINE_ALREADY_VOTED -1
+#define GLINE_PLACED 1
+
+
+/*! \brief Adds a GLINE to the configuration subsystem.
+ *
+ * \param source_p Operator requesting gline
+ * \param user Username covered by the gline
+ * \param host Hostname covered by the gline
+ * \param reason Reason for the gline
+ */
+static void
+set_local_gline(const struct Client *source_p, const char *user,
+ const char *host, const char *reason)
+{
+ char buffer[IRCD_BUFSIZE];
+ struct ConfItem *conf;
+ struct AccessItem *aconf;
+
+
+ conf = make_conf_item(GLINE_TYPE);
+ aconf = map_to_conf(conf);
+
+ snprintf(buffer, sizeof(buffer), "%s (%s)", reason, smalldate(CurrentTime));
+ DupString(aconf->reason, buffer);
+ DupString(aconf->user, user);
+ DupString(aconf->host, host);
+
+ aconf->hold = CurrentTime + ConfigFileEntry.gline_time;
+ SetConfTemporary(aconf);
+ add_conf_by_address(CONF_GLINE, aconf);
+
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s added G-Line for [%s@%s] [%s]",
+ get_oper_name(source_p),
+ aconf->user, aconf->host, aconf->reason);
+ ilog(LOG_TYPE_GLINE, "%s added G-Line for [%s@%s] [%s]",
+ get_oper_name(source_p), aconf->user, aconf->host, aconf->reason);
+
+ /* Now, activate gline against current online clients */
+ rehashed_klines = 1;
+}
+
+/*! \brief Removes a GLINE from the configuration subsystem.
+ *
+ * \param user Username covered by the gline
+ * \param host Hostname covered by the gline
+ */
+static int
+remove_gline_match(const char *user, const char *host)
+{
+ struct irc_ssaddr iphost, *piphost;
+ struct AccessItem *aconf;
+ int t;
+
+ if ((t = parse_netmask(host, &iphost, NULL)) != HM_HOST)
+ {
+#ifdef IPV6
+ if (t == HM_IPV6)
+ t = AF_INET6;
+ else
+#endif
+ t = AF_INET;
+ piphost = &iphost;
+ }
+ else
+ {
+ t = 0;
+ piphost = NULL;
+ }
+
+ if ((aconf = find_conf_by_address(host, piphost, CONF_GLINE, t, user, NULL, 0)))
+ {
+ if (IsConfTemporary(aconf))
+ {
+ delete_one_address_conf(host, aconf);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/*! \brief This function is called once a majority of opers have agreed on a
+ * GLINE/GUNGLINE, and it can be placed. The information about an
+ * operator being passed to us happens to be the operator who pushed us
+ * over the "majority" level needed. See check_majority() for more
+ * information.
+ *
+ * \param source_p Operator requesting gline
+ * \param user Username covered by the gline
+ * \param host Hostname covered by the gline
+ * \param reason Reason for the gline
+ * \param type Valid values are either GLINE_PENDING_ADD_TYPE, or
+ * GLINE_PENDING_DEL_TYPE
+ */
+static void
+add_new_majority(const struct Client *source_p, const char *user,
+ const char *host, const char *reason, const unsigned int type)
+{
+ struct gline_pending *pending = MyMalloc(sizeof(struct gline_pending));
+
+ strlcpy(pending->vote_1.oper_nick, source_p->name, sizeof(pending->vote_1.oper_nick));
+ strlcpy(pending->vote_1.oper_user, source_p->username, sizeof(pending->vote_1.oper_user));
+ strlcpy(pending->vote_1.oper_host, source_p->host, sizeof(pending->vote_1.oper_host));
+ strlcpy(pending->vote_1.oper_server, source_p->servptr->name, sizeof(pending->vote_1.oper_server));
+
+ strlcpy(pending->user, user, sizeof(pending->user));
+ strlcpy(pending->host, host, sizeof(pending->host));
+ strlcpy(pending->vote_1.reason, reason, sizeof(pending->vote_1.reason));
+
+ pending->last_gline_time = CurrentTime;
+ pending->vote_1.time_request = CurrentTime;
+
+ dlinkAdd(pending, &pending->node, &pending_glines[type]);
+}
+
+/*! \brief See if there is a majority agreement on a GLINE on the given user.
+ * There must be at least 3 different opers agreeing on this
+ * GLINE/GUNGLINE
+ *
+ * \param source_p Operator requesting gline
+ * \param user Username covered by the gline
+ * \param host Hostname covered by the gline
+ * \param reason Reason for the gline
+ * \param type Valid values are either GLINE_PENDING_ADD_TYPE, or
+ * GLINE_PENDING_DEL_TYPE
+ *
+ * \return
+ * - GLINE_ALREADY_VOTED returned if oper/server has already voted
+ * - GLINE_PLACED returned if this triggers a gline
+ * - GLINE_NOT_PLACED returned if not triggered
+ */
+static int
+check_majority(const struct Client *source_p, const char *user,
+ const char *host, const char *reason, const int type)
+{
+ dlink_node *dn_ptr = NULL;
+
+ cleanup_glines(NULL);
+
+ /* if its already glined, why bother? :) -- fl_ */
+ if ((type == GLINE_PENDING_ADD_TYPE) && find_is_glined(host, user))
+ return GLINE_NOT_PLACED;
+
+ DLINK_FOREACH(dn_ptr, pending_glines[type].head)
+ {
+ struct gline_pending *gp_ptr = dn_ptr->data;
+
+ if (irccmp(gp_ptr->user, user) ||
+ irccmp(gp_ptr->host, host))
+ continue;
+
+ if ((!irccmp(gp_ptr->vote_1.oper_user, source_p->username) &&
+ !irccmp(gp_ptr->vote_1.oper_host, source_p->host)) ||
+ !irccmp(gp_ptr->vote_1.oper_server, source_p->servptr->name))
+ return GLINE_ALREADY_VOTED;
+
+ if (gp_ptr->vote_2.oper_user[0] != '\0')
+ {
+ /* if two other opers on two different servers have voted yes */
+ if ((!irccmp(gp_ptr->vote_2.oper_user, source_p->username) &&
+ !irccmp(gp_ptr->vote_2.oper_host, source_p->host)) ||
+ !irccmp(gp_ptr->vote_2.oper_server, source_p->servptr->name))
+ return GLINE_ALREADY_VOTED;
+
+ if (type == GLINE_PENDING_DEL_TYPE)
+ {
+ if (remove_gline_match(user, host))
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s has removed the G-Line for: [%s@%s]",
+ get_oper_name(source_p), user, host);
+ ilog(LOG_TYPE_GLINE, "%s removed G-Line for [%s@%s]",
+ get_oper_name(source_p), user, host);
+ }
+ }
+ else
+ /* trigger the gline using the original reason --fl */
+ set_local_gline(source_p, user, host, gp_ptr->vote_1.reason);
+
+ cleanup_glines(gp_ptr);
+ return GLINE_PLACED;
+ }
+
+ strlcpy(gp_ptr->vote_2.oper_nick, source_p->name,
+ sizeof(gp_ptr->vote_2.oper_nick));
+ strlcpy(gp_ptr->vote_2.oper_user, source_p->username,
+ sizeof(gp_ptr->vote_2.oper_user));
+ strlcpy(gp_ptr->vote_2.oper_host, source_p->host,
+ sizeof(gp_ptr->vote_2.oper_host));
+ strlcpy(gp_ptr->vote_2.reason, reason,
+ sizeof(gp_ptr->vote_2.reason));
+ strlcpy(gp_ptr->vote_2.oper_server, source_p->servptr->name,
+ sizeof(gp_ptr->vote_2.oper_server));
+ gp_ptr->last_gline_time = CurrentTime;
+ gp_ptr->vote_2.time_request = CurrentTime;
+ return GLINE_NOT_PLACED;
+ }
+
+ /*
+ * Didn't find this user@host gline in pending gline list
+ * so add it.
+ */
+ add_new_majority(source_p, user, host, reason, type);
+ return GLINE_NOT_PLACED;
+}
+
+static void
+do_sgline(struct Client *source_p, int parc, char *parv[], int prop)
+{
+ const char *reason = NULL; /* reason for "victims" demise */
+ const char *user = NULL;
+ const char *host = NULL; /* user and host of GLINE "victim" */
+
+ if (!IsClient(source_p))
+ return;
+
+ if (parc != 4 || EmptyString(parv[3]))
+ return;
+
+ assert(source_p->servptr != NULL);
+
+ user = parv[1];
+ host = parv[2];
+ reason = parv[3];
+
+ sendto_server(source_p->from, CAP_GLN|CAP_TS6, NOCAPS,
+ ":%s GLINE %s %s :%s",
+ ID(source_p), user, host, reason);
+ sendto_server(source_p->from, CAP_GLN, CAP_TS6,
+ ":%s GLINE %s %s :%s",
+ source_p->name, user, host, reason);
+
+ if (ConfigFileEntry.glines)
+ {
+ if (!valid_wild_card(source_p, 1, 2, user, host))
+ return;
+
+ if (IsClient(source_p))
+ {
+ const char *p = NULL;
+
+ if ((p = strchr(host, '/')))
+ {
+ int bitlen = strtol(++p, NULL, 10);
+ int min_bitlen = strchr(host, ':') ? ConfigFileEntry.gline_min_cidr6 :
+ ConfigFileEntry.gline_min_cidr;
+
+ if (bitlen < min_bitlen)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL, "%s!%s@%s on %s is requesting "
+ "a GLINE with a CIDR mask < %d for [%s@%s] [%s]",
+ source_p->name, source_p->username, source_p->host,
+ source_p->servptr->name, min_bitlen, user, host, reason);
+ return;
+ }
+ }
+ }
+
+ /* If at least 3 opers agree this user should be G lined then do it */
+ if (check_majority(source_p, user, host, reason, GLINE_PENDING_ADD_TYPE) ==
+ GLINE_ALREADY_VOTED)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL, "oper or server has already voted");
+ return;
+ }
+
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s requesting G-Line for [%s@%s] [%s]",
+ get_oper_name(source_p),
+ user, host, reason);
+ ilog(LOG_TYPE_GLINE, "#gline for %s@%s [%s] requested by %s",
+ user, host, reason, get_oper_name(source_p));
+ }
+}
+
+
+/*! \brief GLINE command handler (called by operators)
+ *
+ * \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] = user\@host mask
+ * - parv[2] = reason
+ */
+static void
+mo_gline(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ char *user = NULL;
+ char *host = NULL;
+ char *reason = NULL;
+ char *p;
+
+ if (!HasOFlag(source_p, OPER_FLAG_GLINE))
+ {
+ sendto_one(source_p, form_str(ERR_NOPRIVS),
+ me.name, source_p->name, "gline");
+ return;
+ }
+
+ if (!ConfigFileEntry.glines)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :GLINE disabled",
+ me.name, source_p->name);
+ return;
+ }
+
+ if (parse_aline("GLINE", source_p, parc, parv, AWILD,
+ &user, &host, NULL, NULL, &reason) < 0)
+ return;
+
+ if ((p = strchr(host, '/')) != NULL)
+ {
+ int bitlen = strtol(++p, NULL, 10);
+ int min_bitlen = strchr(host, ':') ? ConfigFileEntry.gline_min_cidr6 :
+ ConfigFileEntry.gline_min_cidr;
+ if (bitlen < min_bitlen)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :Cannot set G-Lines with CIDR length < %d",
+ me.name, source_p->name, min_bitlen);
+ return;
+ }
+ }
+
+ /* If at least 3 opers agree this user should be G lined then do it */
+ if (check_majority(source_p, user, host, reason, GLINE_PENDING_ADD_TYPE) ==
+ GLINE_ALREADY_VOTED)
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :This server or oper has already voted",
+ me.name, source_p->name);
+ return;
+ }
+
+ /*
+ * call these two functions first so the 'requesting' notice always comes
+ * before the 'has triggered' notice. -bill
+ */
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s requesting G-Line for [%s@%s] [%s]",
+ get_oper_name(source_p),
+ user, host, reason);
+ ilog(LOG_TYPE_GLINE, "#gline for %s@%s [%s] requested by %s!%s@%s",
+ user, host, reason, source_p->name, source_p->username,
+ source_p->host);
+
+ /* 4 param version for hyb-7 servers */
+ sendto_server(NULL, CAP_GLN|CAP_TS6, NOCAPS,
+ ":%s GLINE %s %s :%s",
+ ID(source_p), user, host, reason);
+ sendto_server(NULL, CAP_GLN, CAP_TS6,
+ ":%s GLINE %s %s :%s",
+ source_p->name, user, host, reason);
+}
+
+/* ms_gline()
+ * me_gline()
+ * do_sgline()
+ *
+ * inputs - The usual for a m_ function
+ * output -
+ * side effects -
+ *
+ * Place a G line if 3 opers agree on the identical user@host
+ *
+ * Allow this server to pass along GLINE if received and
+ * GLINES is not defined.
+ *
+ * ENCAP'd GLINES are propagated by encap code.
+ */
+
+static void
+ms_gline(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ do_sgline(source_p, parc, parv, 1);
+}
+
+static void
+me_gline(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ do_sgline(source_p, parc, parv, 0);
+}
+
+static void
+do_sungline(struct Client *source_p, const char *user,
+ const char *host, const char *reason, int prop)
+{
+ assert(source_p->servptr != NULL);
+
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s requesting UNG-Line for [%s@%s] [%s]",
+ get_oper_name(source_p), user, host, reason);
+ ilog(LOG_TYPE_GLINE, "#ungline for %s@%s [%s] requested by %s",
+ user, host, reason, get_oper_name(source_p));
+
+ /* If at least 3 opers agree this user should be un G lined then do it */
+ if (check_majority(source_p, user, host, reason, GLINE_PENDING_DEL_TYPE) ==
+ GLINE_ALREADY_VOTED)
+ sendto_realops_flags(UMODE_ALL, L_ALL, "oper or server has already voted");
+
+ if (prop)
+ {
+ sendto_server(source_p->from, CAP_ENCAP|CAP_TS6, NOCAPS,
+ ":%s ENCAP * GUNGLINE %s %s :%s",
+ ID(source_p), user, host, reason);
+ sendto_server(source_p->from, CAP_ENCAP, CAP_TS6,
+ ":%s ENCAP * GUNGLINE %s %s :%s",
+ source_p->name, user, host, reason);
+ }
+}
+
+/*! \brief GUNGLINE command handler (called in response to an encapsulated
+ * GUNGLINE command)
+ *
+ * \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] = username
+ * - parv[2] = hostname
+ * - parv[3] = reason
+ */
+static void
+me_gungline(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (ConfigFileEntry.glines)
+ do_sungline(source_p, parv[1], parv[2], parv[3], 0);
+}
+
+/*! \brief GUNGLINE command handler (called by operators)
+ *
+ * \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] = user\@host mask
+ * - parv[2] = reason
+ */
+static void
+mo_gungline(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ char *user = NULL;
+ char *host = NULL;
+ char *reason = NULL;
+
+ if (!HasOFlag(source_p, OPER_FLAG_GLINE))
+ {
+ sendto_one(source_p, form_str(ERR_NOPRIVS),
+ me.name, source_p->name, "gline");
+ return;
+ }
+
+ if (!ConfigFileEntry.glines)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :GUNGLINE disabled",
+ me.name, source_p->name);
+ return;
+ }
+
+ if (parse_aline("GUNGLINE", source_p, parc, parv, 0, &user,
+ &host, NULL, NULL, &reason) < 0)
+ return;
+
+ do_sungline(source_p, user, host, reason, 1);
+}
+
+/*
+ * gline enforces 3 parameters to force operator to give a reason
+ * a gline is not valid with "No reason"
+ * -db
+ */
+static struct Message gline_msgtab = {
+ "GLINE", 0, 0, 3, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_not_oper, ms_gline, me_gline, mo_gline, m_ignore }
+};
+
+static struct Message ungline_msgtab = {
+ "GUNGLINE", 0, 0, 3, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_not_oper, m_ignore, me_gungline, mo_gungline, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&gline_msgtab);
+ mod_add_cmd(&ungline_msgtab);
+ add_capability("GLN", CAP_GLN, 1);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&gline_msgtab);
+ mod_del_cmd(&ungline_msgtab);
+ delete_capability("GLN");
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_globops.c b/modules/m_globops.c
new file mode 100644
index 0000000..9f9c2eb
--- /dev/null
+++ b/modules/m_globops.c
@@ -0,0 +1,112 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ *
+ * Copyright (C) 2002 by the past and present ircd coders, and others.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * $Id$
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "ircd.h"
+#include "irc_string.h"
+#include "numeric.h"
+#include "send.h"
+#include "s_user.h"
+#include "s_serv.h"
+#include "parse.h"
+#include "modules.h"
+
+
+/*
+ * mo_globops - GLOBOPS message handler
+ * (write to *all* local opers currently online)
+ * parv[0] = sender prefix
+ * parv[1] = message text
+ */
+static void
+mo_globops(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ const char *message = parv[1];
+
+ if (!HasOFlag(source_p, OPER_FLAG_GLOBOPS))
+ {
+ sendto_one(source_p, form_str(ERR_NOPRIVS),
+ me.name, source_p->name, "globops");
+ return;
+ }
+
+ if (EmptyString(message))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, "GLOBOPS");
+ return;
+ }
+
+ sendto_server(NULL, CAP_TS6, NOCAPS,
+ ":%s GLOBOPS :%s", ID(source_p), message);
+ sendto_server(NULL, NOCAPS, CAP_TS6,
+ ":%s GLOBOPS :%s", source_p->name, message);
+
+ sendto_globops_flags(UMODE_ALL, L_ALL, "from: %s: %s",
+ source_p->name, message);
+}
+
+static void
+ms_globops(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (EmptyString(parv[1]))
+ return;
+
+ sendto_server(client_p, CAP_TS6, NOCAPS, ":%s GLOBOPS :%s",
+ ID(source_p), parv[1]);
+ sendto_server(client_p, NOCAPS, CAP_TS6, ":%s GLOBOPS :%s",
+ source_p->name, parv[1]);
+
+ sendto_globops_flags(UMODE_ALL, L_ALL, "from: %s: %s",
+ source_p->name, parv[1]);
+}
+
+static struct Message globops_msgtab = {
+ "GLOBOPS", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_not_oper, ms_globops, m_ignore, mo_globops, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&globops_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&globops_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_hash.c b/modules/m_hash.c
new file mode 100644
index 0000000..89bc89b
--- /dev/null
+++ b/modules/m_hash.c
@@ -0,0 +1,190 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ *
+ * Copyright (C) 2002 by the past and present ircd coders, and others.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * $Id$
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "client.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_user.h"
+#include "resv.h"
+#include "userhost.h"
+
+
+static void
+mo_hash(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ int i;
+ int max_chain = 0;
+ int buckets = 0;
+ int count = 0;
+ struct Client *cl;
+ struct Client *icl;
+ struct Channel *ch;
+ struct UserHost *ush;
+ struct ResvChannel *rch;
+
+ for (i = 0; i < HASHSIZE; ++i)
+ {
+ if ((cl = hash_get_bucket(HASH_TYPE_CLIENT, i)) != NULL)
+ {
+ int len = 0;
+
+ ++buckets;
+ for (; cl != NULL; cl = cl->hnext)
+ ++len;
+ if (len > max_chain)
+ max_chain = len;
+ count += len;
+ }
+ }
+
+ sendto_one(source_p, ":%s NOTICE %s :Client: entries: %d buckets: %d "
+ "max chain: %d", me.name, source_p->name, count, buckets,
+ max_chain);
+
+ count = 0;
+ buckets = 0;
+ max_chain = 0;
+
+ for (i = 0; i < HASHSIZE; ++i)
+ {
+ if ((ch = hash_get_bucket(HASH_TYPE_CHANNEL, i)) != NULL)
+ {
+ int len = 0;
+
+ ++buckets;
+ for (; ch != NULL; ch = ch->hnextch)
+ ++len;
+ if (len > max_chain)
+ max_chain = len;
+ count += len;
+ }
+ }
+
+ sendto_one(source_p, ":%s NOTICE %s :Channel: entries: %d buckets: %d "
+ "max chain: %d", me.name, source_p->name, count, buckets,
+ max_chain);
+
+ count = 0;
+ buckets = 0;
+ max_chain = 0;
+
+ for (i = 0; i < HASHSIZE; ++i)
+ {
+ if ((rch = hash_get_bucket(HASH_TYPE_RESERVED, i)) != NULL)
+ {
+ int len = 0;
+
+ ++buckets;
+ for (; rch != NULL; rch = rch->hnext)
+ ++len;
+ if (len > max_chain)
+ max_chain = len;
+ count += len;
+ }
+ }
+
+ sendto_one(source_p, ":%s NOTICE %s :Resv: entries: %d buckets: %d "
+ "max chain: %d", me.name, source_p->name, count, buckets,
+ max_chain);
+
+ count = 0;
+ buckets = 0;
+ max_chain = 0;
+
+ for (i = 0; i < HASHSIZE; ++i)
+ {
+ if ((icl = hash_get_bucket(HASH_TYPE_ID, i)) != NULL)
+ {
+ int len = 0;
+
+ ++buckets;
+ for (; icl != NULL; icl = icl->idhnext)
+ ++len;
+ if (len > max_chain)
+ max_chain = len;
+ count += len;
+ }
+ }
+
+ sendto_one(source_p, ":%s NOTICE %s :Id: entries: %d buckets: %d "
+ "max chain: %d", me.name, source_p->name, count, buckets,
+ max_chain);
+
+ count = 0;
+ buckets = 0;
+ max_chain = 0;
+
+ for (i = 0; i < HASHSIZE; ++i)
+ {
+ if ((ush = hash_get_bucket(HASH_TYPE_USERHOST, i)) != NULL)
+ {
+ int len = 0;
+
+ ++buckets;
+ for (; ush != NULL; ush = ush->next)
+ ++len;
+ if (len > max_chain)
+ max_chain = len;
+ count += len;
+ }
+ }
+
+ sendto_one(source_p, ":%s NOTICE %s :UserHost: entries: %d buckets: %d "
+ "max chain: %d", me.name, source_p->name, count, buckets,
+ max_chain);
+}
+
+static struct Message hash_msgtab = {
+ "HASH", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_not_oper, m_ignore, m_ignore, mo_hash, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&hash_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&hash_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_help.c b/modules/m_help.c
new file mode 100644
index 0000000..2bd47a1
--- /dev/null
+++ b/modules/m_help.c
@@ -0,0 +1,230 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_help.c: Provides help information to a user/operator.
+ *
+ * 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 "numeric.h"
+#include "send.h"
+#include "conf.h"
+#include "parse.h"
+#include "modules.h"
+#include "irc_string.h"
+
+#define HELPLEN 400
+
+static void dohelp(struct Client *, const char *, char *);
+static void sendhelpfile(struct Client *, const char *, const char *);
+
+
+/*
+ * m_help - HELP message handler
+ * parv[0] = sender prefix
+ */
+static void
+m_help(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ static time_t last_used = 0;
+
+ /* HELP is always local */
+ if ((last_used + ConfigFileEntry.pace_wait_simple) > CurrentTime)
+ {
+ /* safe enough to give this on a local connect only */
+ sendto_one(source_p,form_str(RPL_LOAD2HI),
+ me.name, source_p->name);
+ return;
+ }
+
+ last_used = CurrentTime;
+
+ dohelp(source_p, UHPATH, parv[1]);
+}
+
+/*
+ * mo_help - HELP message handler
+ * parv[0] = sender prefix
+ */
+static void
+mo_help(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ dohelp(source_p, HPATH, parv[1]);
+}
+
+/*
+ * mo_uhelp - HELP message handler
+ * This is used so that opers can view the user help file without deopering
+ * parv[0] = sender prefix
+ */
+static void
+mo_uhelp(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ dohelp(source_p, UHPATH, parv[1]);
+}
+
+static void
+dohelp(struct Client *source_p, const char *hpath, char *topic)
+{
+ char h_index[] = "index";
+ char path[PATH_MAX + 1];
+ struct stat sb;
+ int i;
+
+ if (topic != NULL)
+ {
+ if (*topic == '\0')
+ topic = h_index;
+ else
+ {
+ /* convert to lower case */
+ for (i = 0; topic[i] != '\0'; ++i)
+ topic[i] = ToLower(topic[i]);
+ }
+ }
+ else
+ topic = h_index; /* list available help topics */
+
+ if (strpbrk(topic, "/\\"))
+ {
+ sendto_one(source_p, form_str(ERR_HELPNOTFOUND),
+ me.name, source_p->name, topic);
+ return;
+ }
+
+ if (strlen(hpath) + strlen(topic) + 1 > PATH_MAX)
+ {
+ sendto_one(source_p, form_str(ERR_HELPNOTFOUND),
+ me.name, source_p->name, topic);
+ return;
+ }
+
+ snprintf(path, sizeof(path), "%s/%s", hpath, topic);
+
+ if (stat(path, &sb) < 0)
+ {
+ sendto_one(source_p, form_str(ERR_HELPNOTFOUND),
+ me.name, source_p->name, topic);
+ return;
+ }
+
+ if (!S_ISREG(sb.st_mode))
+ {
+ sendto_one(source_p, form_str(ERR_HELPNOTFOUND),
+ me.name, source_p->name, topic);
+ return;
+ }
+
+ sendhelpfile(source_p, path, topic);
+}
+
+static void
+sendhelpfile(struct Client *source_p, const char *path, const char *topic)
+{
+ FILE *file;
+ char line[HELPLEN];
+ char started = 0;
+ int type;
+
+ if ((file = fopen(path, "r")) == NULL)
+ {
+ sendto_one(source_p, form_str(ERR_HELPNOTFOUND),
+ me.name, source_p->name, topic);
+ return;
+ }
+
+ if (fgets(line, sizeof(line), file) == NULL)
+ {
+ sendto_one(source_p, form_str(ERR_HELPNOTFOUND),
+ me.name, source_p->name, topic);
+ return;
+ }
+
+ else if (line[0] != '#')
+ {
+ line[strlen(line) - 1] = '\0';
+ sendto_one(source_p, form_str(RPL_HELPSTART),
+ me.name, source_p->name, topic, line);
+ started = 1;
+ }
+
+ while (fgets(line, sizeof(line), file))
+ {
+ line[strlen(line) - 1] = '\0';
+ if (line[0] != '#')
+ {
+ if (!started)
+ {
+ type = RPL_HELPSTART;
+ started = 1;
+ }
+ else
+ type = RPL_HELPTXT;
+
+ sendto_one(source_p, form_str(RPL_HELPTXT),
+ me.name, source_p->name, topic, line);
+ }
+ }
+
+ fclose(file);
+ sendto_one(source_p, form_str(RPL_HELPTXT),
+ me.name, source_p->name, topic, "");
+ sendto_one(source_p, form_str(RPL_ENDOFHELP),
+ me.name, source_p->name, topic);
+}
+
+static struct Message help_msgtab = {
+ "HELP", 0, 0, 0, 0, MFLG_SLOW, 0,
+ {m_unregistered, m_help, m_ignore, m_ignore, mo_help, m_ignore}
+};
+
+static struct Message uhelp_msgtab = {
+ "UHELP", 0, 0, 0, 0, MFLG_SLOW, 0,
+ {m_unregistered, m_help, m_ignore, m_ignore, mo_uhelp, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&help_msgtab);
+ mod_add_cmd(&uhelp_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&help_msgtab);
+ mod_del_cmd(&uhelp_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_info.c b/modules/m_info.c
new file mode 100644
index 0000000..c3e81d7
--- /dev/null
+++ b/modules/m_info.c
@@ -0,0 +1,733 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_info.c: Sends information about the server.
+ *
+ * Copyright (C) 2005 by the past and present ircd coders, and others.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * $Id$
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "channel.h"
+#include "client.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_serv.h"
+#include "s_user.h"
+#include "send.h"
+#include "conf.h"
+#include "parse.h"
+#include "modules.h"
+
+
+static void send_conf_options(struct Client *);
+static void send_birthdate_online_time(struct Client *);
+static void send_info_text(struct Client *);
+
+/*
+ * jdc -- Structure for our configuration value table
+ */
+struct InfoStruct
+{
+ const char *name; /* Displayed variable name */
+ unsigned int output_type; /* See below #defines */
+ void *option; /* Pointer reference to the value */
+ const char *desc; /* ASCII description of the variable */
+};
+
+/* Types for output_type in InfoStruct */
+#define OUTPUT_STRING 0x0001 /* Output option as %s w/ dereference */
+#define OUTPUT_STRING_PTR 0x0002 /* Output option as %s w/out deference */
+#define OUTPUT_DECIMAL 0x0004 /* Output option as decimal (%d) */
+#define OUTPUT_BOOLEAN 0x0008 /* Output option as "ON" or "OFF" */
+#define OUTPUT_BOOLEAN_YN 0x0010 /* Output option as "YES" or "NO" */
+#define OUTPUT_BOOLEAN2 0x0020 /* Output option as "YES/NO/MASKED" */
+
+static const struct InfoStruct info_table[] =
+{
+ /* --[ START OF TABLE ]-------------------------------------------- */
+
+ {
+ "CPATH",
+ OUTPUT_STRING,
+ &ConfigFileEntry.configfile,
+ "Path to Main Configuration File"
+ },
+ {
+ "DPATH",
+ OUTPUT_STRING,
+ &ConfigFileEntry.dpath,
+ "Directory Containing Configuration Files"
+ },
+ {
+ "DLPATH",
+ OUTPUT_STRING,
+ &ConfigFileEntry.dlinefile,
+ "Path to D-line File"
+ },
+ {
+ "KPATH",
+ OUTPUT_STRING,
+ &ConfigFileEntry.klinefile,
+ "Path to K-line File"
+ },
+ {
+ "network_name",
+ OUTPUT_STRING,
+ &ServerInfo.network_name,
+ "Network name"
+ },
+ {
+ "network_desc",
+ OUTPUT_STRING,
+ &ServerInfo.network_desc,
+ "Network description"
+ },
+ {
+ "hub",
+ OUTPUT_BOOLEAN_YN,
+ &ServerInfo.hub,
+ "Server is a hub"
+ },
+ {
+ "use_logging",
+ OUTPUT_BOOLEAN_YN,
+ &ConfigLoggingEntry.use_logging,
+ "Enable logging"
+ },
+ {
+ "restrict_channels",
+ OUTPUT_BOOLEAN_YN,
+ &ConfigChannel.restrict_channels,
+ "Only reserved channels are allowed"
+ },
+ {
+ "knock_delay",
+ OUTPUT_DECIMAL,
+ &ConfigChannel.knock_delay,
+ "Delay between a users KNOCK attempts"
+ },
+ {
+ "knock_delay_channel",
+ OUTPUT_DECIMAL,
+ &ConfigChannel.knock_delay_channel,
+ "Delay between KNOCK attempts to a channel"
+ },
+ {
+ "max_chans_per_user",
+ OUTPUT_DECIMAL,
+ &ConfigChannel.max_chans_per_user,
+ "Maximum number of channels a user can join"
+ },
+ {
+ "max_chans_per_oper",
+ OUTPUT_DECIMAL,
+ &ConfigChannel.max_chans_per_oper,
+ "Maximum number of channels an oper can join"
+ },
+ {
+ "quiet_on_ban",
+ OUTPUT_BOOLEAN_YN,
+ &ConfigChannel.quiet_on_ban,
+ "Banned users may not send text to a channel"
+ },
+ {
+ "max_bans",
+ OUTPUT_DECIMAL,
+ &ConfigChannel.max_bans,
+ "Total +b/e/I modes allowed in a channel"
+ },
+ {
+ "default_split_user_count",
+ OUTPUT_DECIMAL,
+ &ConfigChannel.default_split_user_count,
+ "Startup value of SPLITUSERS"
+ },
+ {
+ "default_split_server_count",
+ OUTPUT_DECIMAL,
+ &ConfigChannel.default_split_server_count,
+ "Startup value of SPLITNUM"
+ },
+ {
+ "no_create_on_split",
+ OUTPUT_BOOLEAN_YN,
+ &ConfigChannel.no_create_on_split,
+ "Disallow creation of channels when split"
+ },
+ {
+ "no_join_on_split",
+ OUTPUT_BOOLEAN_YN,
+ &ConfigChannel.no_join_on_split,
+ "Disallow joining channels when split"
+ },
+ {
+ "flatten_links",
+ OUTPUT_BOOLEAN_YN,
+ &ConfigServerHide.flatten_links,
+ "Flatten /links list"
+ },
+ {
+ "links_delay",
+ OUTPUT_DECIMAL,
+ &ConfigServerHide.links_delay,
+ "Links rehash delay"
+ },
+ {
+ "hidden",
+ OUTPUT_BOOLEAN_YN,
+ &ConfigServerHide.hidden,
+ "Hide this server from a flattened /links on remote servers"
+ },
+ {
+ "hide_servers",
+ OUTPUT_BOOLEAN_YN,
+ &ConfigServerHide.hide_servers,
+ "Hide servernames from users"
+ },
+ {
+ "hidden_name",
+ OUTPUT_STRING,
+ &ConfigServerHide.hidden_name,
+ "Server name users see if hide_servers = yes"
+ },
+ {
+ "hide_server_ips",
+ OUTPUT_BOOLEAN_YN,
+ &ConfigServerHide.hide_server_ips,
+ "Prevent people from seeing server IPs"
+ },
+ {
+ "gline_min_cidr",
+ OUTPUT_DECIMAL,
+ &ConfigFileEntry.gline_min_cidr,
+ "Minimum required length of a CIDR bitmask for IPv4 G-Lines"
+ },
+ {
+ "gline_min_cidr6",
+ OUTPUT_DECIMAL,
+ &ConfigFileEntry.gline_min_cidr6,
+ "Minimum required length of a CIDR bitmask for IPv6 G-Lines"
+ },
+ {
+ "invisible_on_connect",
+ OUTPUT_BOOLEAN_YN,
+ &ConfigFileEntry.invisible_on_connect,
+ "Automatically set mode +i on connecting users"
+ },
+ {
+ "kill_chase_time_limit",
+ OUTPUT_DECIMAL,
+ &ConfigFileEntry.kill_chase_time_limit,
+ "Nick Change Tracker for KILL"
+ },
+ {
+ "hide_spoof_ips",
+ OUTPUT_BOOLEAN_YN,
+ &ConfigFileEntry.hide_spoof_ips,
+ "Hide spoofed IP's"
+ },
+ {
+ "ignore_bogus_ts",
+ OUTPUT_BOOLEAN_YN,
+ &ConfigFileEntry.ignore_bogus_ts,
+ "Ignore bogus timestamps from other servers"
+ },
+ {
+ "disable_auth",
+ OUTPUT_BOOLEAN_YN,
+ &ConfigFileEntry.disable_auth,
+ "Completely disable ident lookups"
+ },
+ {
+ "disable_remote_commands",
+ OUTPUT_BOOLEAN_YN,
+ &ConfigFileEntry.disable_remote,
+ "Prevent users issuing commands on remote servers"
+ },
+ {
+ "tkline_expire_notices",
+ OUTPUT_BOOLEAN_YN,
+ &ConfigFileEntry.tkline_expire_notices,
+ "Show temporary kline/xline expire notices"
+ },
+ {
+ "default_floodcount",
+ OUTPUT_DECIMAL,
+ &ConfigFileEntry.default_floodcount,
+ "Startup value of FLOODCOUNT"
+ },
+ {
+ "failed_oper_notice",
+ OUTPUT_BOOLEAN,
+ &ConfigFileEntry.failed_oper_notice,
+ "Inform opers if someone /oper's with the wrong password"
+ },
+ {
+ "dots_in_ident",
+ OUTPUT_DECIMAL,
+ &ConfigFileEntry.dots_in_ident,
+ "Number of permissable dots in an ident"
+ },
+ {
+ "min_nonwildcard",
+ OUTPUT_DECIMAL,
+ &ConfigFileEntry.min_nonwildcard,
+ "Minimum non-wildcard chars in K/G lines"
+ },
+ {
+ "min_nonwildcard_simple",
+ OUTPUT_DECIMAL,
+ &ConfigFileEntry.min_nonwildcard_simple,
+ "Minimum non-wildcards in gecos bans"
+ },
+ {
+ "max_accept",
+ OUTPUT_DECIMAL,
+ &ConfigFileEntry.max_accept,
+ "Maximum nicknames on accept list"
+ },
+ {
+ "anti_nick_flood",
+ OUTPUT_BOOLEAN,
+ &ConfigFileEntry.anti_nick_flood,
+ "NICK flood protection"
+ },
+ {
+ "max_nick_time",
+ OUTPUT_DECIMAL,
+ &ConfigFileEntry.max_nick_time,
+ "NICK flood protection time interval"
+ },
+ {
+ "max_nick_changes",
+ OUTPUT_DECIMAL,
+ &ConfigFileEntry.max_nick_changes,
+ "NICK change threshhold setting"
+ },
+ {
+ "anti_spam_exit_message_time",
+ OUTPUT_DECIMAL,
+ &ConfigFileEntry.anti_spam_exit_message_time,
+ "Duration a client must be connected for to have an exit message"
+ },
+ {
+ "ts_warn_delta",
+ OUTPUT_DECIMAL,
+ &ConfigFileEntry.ts_warn_delta,
+ "Maximum permitted TS delta before displaying a warning"
+ },
+ {
+ "ts_max_delta",
+ OUTPUT_DECIMAL,
+ &ConfigFileEntry.ts_max_delta,
+ "Maximum permitted TS delta from another server"
+ },
+ {
+ "warn_no_nline",
+ OUTPUT_BOOLEAN,
+ &ConfigFileEntry.warn_no_nline,
+ "Display warning if connecting server lacks N-line"
+ },
+ {
+ "stats_o_oper_only",
+ OUTPUT_BOOLEAN_YN,
+ &ConfigFileEntry.stats_o_oper_only,
+ "STATS O output is only shown to operators"
+ },
+ {
+ "stats_P_oper_only",
+ OUTPUT_BOOLEAN_YN,
+ &ConfigFileEntry.stats_P_oper_only,
+ "STATS P is only shown to operators"
+ },
+ {
+ "stats_i_oper_only",
+ OUTPUT_BOOLEAN2,
+ &ConfigFileEntry.stats_i_oper_only,
+ "STATS I output is only shown to operators"
+ },
+ {
+ "stats_k_oper_only",
+ OUTPUT_BOOLEAN2,
+ &ConfigFileEntry.stats_k_oper_only,
+ "STATS K output is only shown to operators"
+ },
+ {
+ "caller_id_wait",
+ OUTPUT_DECIMAL,
+ &ConfigFileEntry.caller_id_wait,
+ "Minimum delay between notifying UMODE +g users of messages"
+ },
+ {
+ "opers_bypass_callerid",
+ OUTPUT_BOOLEAN_YN,
+ &ConfigFileEntry.opers_bypass_callerid,
+ "Allows IRC operators to message users who are +g (callerid)"
+ },
+ {
+ "pace_wait_simple",
+ OUTPUT_DECIMAL,
+ &ConfigFileEntry.pace_wait_simple,
+ "Minimum delay between less intensive commands"
+ },
+ {
+ "pace_wait",
+ OUTPUT_DECIMAL,
+ &ConfigFileEntry.pace_wait,
+ "Minimum delay between uses of certain commands"
+ },
+ {
+ "short_motd",
+ OUTPUT_BOOLEAN_YN,
+ &ConfigFileEntry.short_motd,
+ "Do not show MOTD; only tell clients they should read it"
+ },
+ {
+ "ping_cookie",
+ OUTPUT_BOOLEAN,
+ &ConfigFileEntry.ping_cookie,
+ "Require ping cookies to connect"
+ },
+ {
+ "no_oper_flood",
+ OUTPUT_BOOLEAN,
+ &ConfigFileEntry.no_oper_flood,
+ "Reduce flood control for operators"
+ },
+ {
+ "true_no_oper_flood",
+ OUTPUT_BOOLEAN,
+ &ConfigFileEntry.true_no_oper_flood,
+ "Completely disable flood control for operators"
+ },
+ {
+ "oper_pass_resv",
+ OUTPUT_BOOLEAN_YN,
+ &ConfigFileEntry.oper_pass_resv,
+ "Opers can over-ride RESVs"
+ },
+ {
+ "max_targets",
+ OUTPUT_DECIMAL,
+ &ConfigFileEntry.max_targets,
+ "The maximum number of PRIVMSG/NOTICE targets"
+ },
+ {
+ "throttle_time",
+ OUTPUT_DECIMAL,
+ &ConfigFileEntry.throttle_time,
+ "Minimum time between client reconnects"
+ },
+ {
+ "glines",
+ OUTPUT_BOOLEAN,
+ &ConfigFileEntry.glines,
+ "G-line (network-wide K-line) support"
+ },
+ {
+ "gline_duration",
+ OUTPUT_DECIMAL,
+ &ConfigFileEntry.gline_time,
+ "Expiry time for G-lines"
+ },
+
+ {
+ "gline_request_duration",
+ OUTPUT_DECIMAL,
+ &ConfigFileEntry.gline_request_time,
+ "Expiry time for pending G-lines"
+ },
+
+ /* --[ END OF TABLE ]---------------------------------------------- */
+ {
+ NULL,
+ 0,
+ NULL,
+ 0
+ }
+};
+
+/*
+** m_info()
+** parv[0] = sender prefix
+** parv[1] = servername
+*/
+static void
+m_info(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ static time_t last_used = 0;
+
+ if ((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
+ {
+ /* safe enough to give this on a local connect only */
+ sendto_one(source_p, form_str(RPL_LOAD2HI),
+ me.name, source_p->name);
+ return;
+ }
+
+ last_used = CurrentTime;
+
+ if (!ConfigFileEntry.disable_remote)
+ if (hunt_server(client_p,source_p, ":%s INFO :%s", 1,
+ parc, parv) != HUNTED_ISME)
+ return;
+
+ send_info_text(source_p);
+}
+
+/*
+** mo_info()
+** parv[0] = sender prefix
+** parv[1] = servername
+*/
+static void
+mo_info(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (hunt_server(client_p, source_p, ":%s INFO :%s", 1,
+ parc, parv) != HUNTED_ISME)
+ return;
+
+ send_info_text(source_p);
+}
+
+/*
+** ms_info()
+** parv[0] = sender prefix
+** parv[1] = servername
+*/
+static void
+ms_info(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (!IsClient(source_p))
+ return;
+
+ if (hunt_server(client_p, source_p, ":%s INFO :%s", 1,
+ parc, parv) != HUNTED_ISME)
+ return;
+
+ send_info_text(source_p);
+}
+
+/* send_info_text()
+ *
+ * inputs - client pointer to send info text to
+ * output - NONE
+ * side effects - info text is sent to client
+ */
+static void
+send_info_text(struct Client *source_p)
+{
+ const char **text = infotext;
+ char *source, *target;
+
+ sendto_realops_flags(UMODE_SPY, L_ALL,
+ "INFO requested by %s (%s@%s) [%s]",
+ source_p->name, source_p->username,
+ source_p->host, source_p->servptr->name);
+
+ if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) &&
+ HasID(source_p))
+ source = me.id, target = source_p->id;
+ else
+ source = me.name, target = source_p->name;
+
+ while (*text)
+ {
+ const char *line = *text++;
+
+ if (*line == '\0')
+ line = " ";
+
+ sendto_one(source_p, form_str(RPL_INFO),
+ source, target, line);
+ }
+
+ if (HasUMode(source_p, UMODE_OPER))
+ send_conf_options(source_p);
+
+ send_birthdate_online_time(source_p);
+
+ sendto_one(source_p, form_str(RPL_ENDOFINFO),
+ me.name, source_p->name);
+}
+
+/* send_birthdate_online_time()
+ *
+ * inputs - client pointer to send to
+ * output - NONE
+ * side effects - birthdate and online time are sent
+ */
+static void
+send_birthdate_online_time(struct Client *source_p)
+{
+ if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
+ {
+ sendto_one(source_p, ":%s %d %s :On-line since %s",
+ me.id, RPL_INFO, source_p->id,
+ myctime(me.localClient->firsttime));
+ }
+ else
+ {
+ sendto_one(source_p, ":%s %d %s :On-line since %s",
+ me.name, RPL_INFO, source_p->name,
+ myctime(me.localClient->firsttime));
+ }
+}
+
+/* send_conf_options()
+ *
+ * inputs - client pointer to send to
+ * output - NONE
+ * side effects - send config options to client
+ */
+static void
+send_conf_options(struct Client *source_p)
+{
+ const char *from, *to;
+ const struct InfoStruct *iptr = NULL;
+
+ /* Now send them a list of all our configuration options
+ * (mostly from defaults.h and config.h)
+ */
+ if (!MyClient(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;
+ }
+
+ /*
+ * Parse the info_table[] and do the magic.
+ */
+ for (iptr = info_table; iptr->name; ++iptr)
+ {
+ switch (iptr->output_type)
+ {
+ /* For "char *" references */
+ case OUTPUT_STRING:
+ {
+ const char *option = *((char **)iptr->option);
+
+ sendto_one(source_p, ":%s %d %s :%-30s %-5s [%-30s]",
+ from, RPL_INFO, to,
+ iptr->name, option ? option : "NONE",
+ iptr->desc ? iptr->desc : "<none>");
+ break;
+ }
+
+ /* For "char foo[]" references */
+ case OUTPUT_STRING_PTR:
+ {
+ const char *option = iptr->option;
+
+ sendto_one(source_p, ":%s %d %s :%-30s %-5s [%-30s]",
+ from, RPL_INFO, to,
+ iptr->name, option ? option : "NONE",
+ iptr->desc ? iptr->desc : "<none>");
+ break;
+ }
+
+ /* Output info_table[i].option as a decimal value. */
+ case OUTPUT_DECIMAL:
+ {
+ const int option = *((int *)iptr->option);
+
+ sendto_one(source_p, ":%s %d %s :%-30s %-5d [%-30s]",
+ from, RPL_INFO, to, iptr->name,
+ option, iptr->desc ? iptr->desc : "<none>");
+ break;
+ }
+
+ /* Output info_table[i].option as "ON" or "OFF" */
+ case OUTPUT_BOOLEAN:
+ {
+ const int option = *((int *)iptr->option);
+
+ sendto_one(source_p, ":%s %d %s :%-30s %-5s [%-30s]",
+ from, RPL_INFO, to,
+ iptr->name, option ? "ON" : "OFF",
+ iptr->desc ? iptr->desc : "<none>");
+
+ break;
+ }
+
+ /* Output info_table[i].option as "YES" or "NO" */
+ case OUTPUT_BOOLEAN_YN:
+ {
+ int option = *((int *)iptr->option);
+
+ sendto_one(source_p, ":%s %d %s :%-30s %-5s [%-30s]",
+ from, RPL_INFO, to,
+ iptr->name, option ? "YES" : "NO",
+ iptr->desc ? iptr->desc : "<none>");
+ break;
+ }
+
+ case OUTPUT_BOOLEAN2:
+ {
+ int option = *((int *)iptr->option);
+
+ sendto_one(source_p, ":%s %d %s :%-30s %-5s [%-30s]",
+ from, RPL_INFO, to,
+ iptr->name, option ? ((option == 1) ? "MASK" : "YES") : "NO",
+ iptr->desc ? iptr->desc : "<none>");
+ break;
+ }
+ }
+ }
+
+ sendto_one(source_p, form_str(RPL_INFO),
+ from, to, "");
+}
+
+static struct Message info_msgtab = {
+ "INFO", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_info, ms_info, m_ignore, mo_info, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&info_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&info_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_invite.c b/modules/m_invite.c
new file mode 100644
index 0000000..45ec444
--- /dev/null
+++ b/modules/m_invite.c
@@ -0,0 +1,179 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_invite.c: Invites the user to join 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 "conf.h"
+#include "s_serv.h"
+#include "parse.h"
+#include "modules.h"
+#include "packet.h"
+
+
+/*
+** m_invite
+** parv[0] - sender prefix
+** parv[1] - user to invite
+** parv[2] - channel name
+** parv[3] - invite timestamp
+*/
+static void
+m_invite(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *target_p = NULL;
+ struct Channel *chptr = NULL;
+ struct Membership *ms = NULL;
+
+ if (IsServer(source_p))
+ return;
+
+ if (EmptyString(parv[2]))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, "INVITE");
+ return;
+ }
+
+ if (MyClient(source_p) && !IsFloodDone(source_p))
+ flood_endgrace(source_p);
+
+ if ((target_p = find_person(client_p, parv[1])) == NULL)
+ {
+ sendto_one(source_p, form_str(ERR_NOSUCHNICK),
+ me.name, source_p->name, parv[1]);
+ return;
+ }
+
+ if ((chptr = hash_find_channel(parv[2])) == NULL)
+ {
+ sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
+ me.name, source_p->name, parv[2]);
+ return;
+ }
+
+ if (MyConnect(source_p) && (ms = find_channel_link(source_p, chptr)) == NULL)
+ {
+ sendto_one(source_p, form_str(ERR_NOTONCHANNEL),
+ me.name, source_p->name, chptr->chname);
+ return;
+ }
+
+ if (MyConnect(source_p) && !has_member_flags(ms, CHFL_CHANOP))
+ {
+ sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
+ me.name, source_p->name, chptr->chname);
+ return;
+ }
+
+ if (IsMember(target_p, chptr))
+ {
+ sendto_one(source_p, form_str(ERR_USERONCHANNEL),
+ me.name, source_p->name, target_p->name, chptr->chname);
+ return;
+ }
+
+ if (MyConnect(source_p))
+ {
+ sendto_one(source_p, form_str(RPL_INVITING), me.name,
+ source_p->name, target_p->name, chptr->chname);
+
+ if (target_p->away[0])
+ sendto_one(source_p, form_str(RPL_AWAY),
+ me.name, source_p->name, target_p->name,
+ target_p->away);
+ }
+ else if (parc > 3 && IsDigit(*parv[3]))
+ if (atoi(parv[3]) > chptr->channelts)
+ return;
+
+ if (MyConnect(target_p))
+ {
+ sendto_one(target_p, ":%s!%s@%s INVITE %s :%s",
+ source_p->name, source_p->username,
+ source_p->host,
+ target_p->name, chptr->chname);
+
+ if (chptr->mode.mode & MODE_INVITEONLY)
+ {
+ sendto_channel_local(CHFL_CHANOP, 0, chptr,
+ ":%s NOTICE @%s :%s is inviting %s to %s.",
+ me.name, chptr->chname, source_p->name,
+ target_p->name, chptr->chname);
+
+ sendto_channel_remote(source_p, client_p, CHFL_CHANOP,
+ CAP_TS6, NOCAPS, chptr,
+ ":%s NOTICE @%s :%s is inviting %s to %s.",
+ ID(&me), chptr->chname, source_p->name,
+ target_p->name, chptr->chname);
+ sendto_channel_remote(source_p, client_p, CHFL_CHANOP,
+ NOCAPS, CAP_TS6, chptr,
+ ":%s NOTICE @%s :%s is inviting %s to %s.",
+ me.name, chptr->chname, source_p->name,
+ target_p->name, chptr->chname);
+ /* Add the invite if channel is +i */
+ add_invite(chptr, target_p);
+ }
+ }
+ else if (target_p->from != client_p)
+ sendto_one(target_p, ":%s INVITE %s %s %lu",
+ ID_or_name(source_p, target_p->from),
+ ID_or_name(target_p, target_p->from),
+ chptr->chname, (unsigned long)chptr->channelts);
+}
+
+static struct Message invite_msgtab = {
+ "INVITE", 0, 0, 3, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_invite, m_invite, m_ignore, m_invite, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&invite_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&invite_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_ison.c b/modules/m_ison.c
new file mode 100644
index 0000000..bcd0c8e
--- /dev/null
+++ b/modules/m_ison.c
@@ -0,0 +1,134 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_ison.c: Provides a single line answer of whether a user is online.
+ *
+ * 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 "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+
+
+static void
+do_ison(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *target_p = NULL;
+ char *nick;
+ char *p = NULL;
+ char *current_insert_point = NULL;
+ char buf[IRCD_BUFSIZE];
+ int len;
+ int i;
+ int done = 0;
+
+ len = snprintf(buf, sizeof(buf), form_str(RPL_ISON), me.name, source_p->name);
+ current_insert_point = buf + len;
+
+ /*
+ * rfc1459 is ambigious about how to handle ISON
+ * this should handle both interpretations.
+ */
+ for (i = 1; i < parc; i++)
+ {
+ for (nick = strtoken(&p, parv[i], " "); nick;
+ nick = strtoken(&p, NULL, " "))
+ {
+ if ((target_p = find_person(client_p, nick)))
+ {
+ len = strlen(target_p->name);
+
+ if ((current_insert_point + (len + 5)) < (buf + sizeof(buf)))
+ {
+ memcpy(current_insert_point, target_p->name, len);
+ current_insert_point += len;
+ *current_insert_point++ = ' ';
+ }
+ else
+ {
+ done = 1;
+ break;
+ }
+ }
+ }
+
+ if (done)
+ break;
+ }
+
+ /*
+ * current_insert_point--;
+ * Do NOT take out the trailing space, it breaks ircII
+ * --Rodder
+ */
+ *current_insert_point = '\0';
+
+ sendto_one(source_p, "%s", buf);
+}
+
+/*
+ * m_ison added by Darren Reed 13/8/91 to act as an efficent user indicator
+ * with respect to cpu/bandwidth used. Implemented for NOTIFY feature in
+ * clients. Designed to reduce number of whois requests. Can process
+ * nicknames in batches as long as the maximum buffer length.
+ *
+ * format:
+ * ISON :nicklist
+ */
+static void
+m_ison(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ do_ison(client_p, source_p, parc, parv);
+}
+
+static struct Message ison_msgtab = {
+ "ISON", 0, 0, 1, 1, MFLG_SLOW, 0,
+ {m_unregistered, m_ison, m_ignore, m_ignore, m_ison, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&ison_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&ison_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_kline.c b/modules/m_kline.c
new file mode 100644
index 0000000..8833fe5
--- /dev/null
+++ b/modules/m_kline.c
@@ -0,0 +1,563 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_kline.c: Bans 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 "channel.h"
+#include "client.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "hostmask.h"
+#include "numeric.h"
+#include "fdlist.h"
+#include "s_bsd.h"
+#include "conf.h"
+#include "log.h"
+#include "s_misc.h"
+#include "send.h"
+#include "hash.h"
+#include "s_serv.h"
+#include "s_gline.h"
+#include "parse.h"
+#include "modules.h"
+
+
+static int already_placed_kline(struct Client *, const char *, const char *, int);
+static void apply_kline(struct Client *, struct ConfItem *, const char *, time_t);
+static void apply_tkline(struct Client *, struct ConfItem *, int);
+
+static char buffer[IRCD_BUFSIZE];
+static int remove_tkline_match(const char *, const char *);
+
+
+/* mo_kline()
+ *
+ * inputs - pointer to server
+ * - pointer to client
+ * - parameter count
+ * - parameter list
+ * output -
+ * side effects - k line is added
+ */
+static void
+mo_kline(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ char *reason = NULL;
+ char *oper_reason;
+ char *user = NULL;
+ char *host = NULL;
+ const char *current_date;
+ char *target_server = NULL;
+ struct ConfItem *conf;
+ struct AccessItem *aconf;
+ time_t tkline_time = 0;
+ time_t cur_time;
+
+ if (!HasOFlag(source_p, OPER_FLAG_K))
+ {
+ sendto_one(source_p, form_str(ERR_NOPRIVS),
+ me.name, source_p->name, "kline");
+ return;
+ }
+
+ if (parse_aline("KLINE", source_p, parc, parv,
+ AWILD, &user, &host, &tkline_time, &target_server, &reason) < 0)
+ return;
+
+ if (target_server != NULL)
+ {
+ if (HasID(source_p))
+ {
+ sendto_server(NULL, CAP_KLN|CAP_TS6, NOCAPS,
+ ":%s KLINE %s %lu %s %s :%s",
+ source_p->id, target_server, (unsigned long)tkline_time,
+ user, host, reason);
+ sendto_server(NULL, CAP_KLN, CAP_TS6,
+ ":%s KLINE %s %lu %s %s :%s",
+ source_p->name, target_server, (unsigned long)tkline_time,
+ user, host, reason);
+ }
+ else
+ sendto_server(NULL, CAP_KLN, NOCAPS,
+ ":%s KLINE %s %lu %s %s :%s",
+ source_p->name, target_server, (unsigned long)tkline_time,
+ user, host, reason);
+
+ /* Allow ON to apply local kline as well if it matches */
+ if (!match(target_server, me.name))
+ return;
+ }
+ else
+ cluster_a_line(source_p, "KLINE", CAP_KLN, SHARED_KLINE,
+ "%d %s %s :%s", tkline_time, user, host, reason);
+
+ if (already_placed_kline(source_p, user, host, 1))
+ return;
+
+ /* Look for an oper reason */
+ if ((oper_reason = strchr(reason, '|')) != NULL)
+ *oper_reason++ = '\0';
+
+ cur_time = CurrentTime;
+ current_date = smalldate(cur_time);
+ conf = make_conf_item(KLINE_TYPE);
+ aconf = map_to_conf(conf);
+
+ DupString(aconf->host, host);
+ DupString(aconf->user, user);
+
+ if (tkline_time != 0)
+ {
+ snprintf(buffer, sizeof(buffer), "Temporary K-line %d min. - %s (%s)",
+ (int)(tkline_time/60), reason, current_date);
+ DupString(aconf->reason, buffer);
+
+ if (oper_reason != NULL)
+ DupString(aconf->oper_reason, oper_reason);
+ apply_tkline(source_p, conf, tkline_time);
+ }
+ else
+ {
+ snprintf(buffer, sizeof(buffer), "%s (%s)", reason, current_date);
+ DupString(aconf->reason, buffer);
+
+ if (oper_reason != NULL)
+ DupString(aconf->oper_reason, oper_reason);
+ apply_kline(source_p, conf, current_date, cur_time);
+ }
+}
+
+/* me_kline - handle remote kline. no propagation */
+static void
+me_kline(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct ConfItem *conf=NULL;
+ struct AccessItem *aconf=NULL;
+ int tkline_time;
+ const char* current_date;
+ time_t cur_time;
+ char *kuser, *khost, *kreason, *oper_reason;
+
+ if (parc != 6 || EmptyString(parv[5]))
+ return;
+
+ if (!match(parv[1], me.name))
+ return;
+
+ tkline_time = valid_tkline(parv[2], TK_SECONDS);
+ kuser = parv[3];
+ khost = parv[4];
+ kreason = parv[5];
+
+ if ((oper_reason = strchr(kreason, '|')) != NULL)
+ *oper_reason++ = '\0';
+
+ cur_time = CurrentTime;
+ current_date = smalldate(cur_time);
+
+ if (HasFlag(source_p, FLAGS_SERVICE) || find_matching_name_conf(ULINE_TYPE, source_p->servptr->name,
+ source_p->username, source_p->host,
+ SHARED_KLINE))
+ {
+ if (!IsClient(source_p) ||
+ already_placed_kline(source_p, kuser, khost, 1))
+ return;
+
+ conf = make_conf_item(KLINE_TYPE);
+ aconf = map_to_conf(conf);
+ DupString(aconf->host, khost);
+ DupString(aconf->user, kuser);
+
+ if (tkline_time != 0)
+ {
+ snprintf(buffer, sizeof(buffer), "Temporary K-line %d min. - %s (%s)",
+ (int)(tkline_time/60), kreason, current_date);
+ DupString(aconf->reason, buffer);
+
+ if (oper_reason != NULL)
+ DupString(aconf->oper_reason, oper_reason);
+ apply_tkline(source_p, conf, tkline_time);
+ }
+ else
+ {
+ snprintf(buffer, sizeof(buffer), "%s (%s)", kreason, current_date);
+ DupString(aconf->reason, buffer);
+
+ if (oper_reason != NULL)
+ DupString(aconf->oper_reason, oper_reason);
+ apply_kline(source_p, conf, current_date, cur_time);
+ }
+ }
+}
+
+static void
+ms_kline(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (parc != 6 || EmptyString(parv[5]))
+ return;
+
+ /* parv[0] parv[1] parv[2] parv[3] parv[4] parv[5] */
+ /* oper target_server tkline_time user host reason */
+ sendto_match_servs(source_p, parv[1], CAP_KLN,
+ "KLINE %s %s %s %s :%s",
+ parv[1], parv[2], parv[3], parv[4], parv[5]);
+
+ me_kline(client_p, source_p, parc, parv);
+}
+
+/* apply_kline()
+ *
+ * inputs -
+ * output - NONE
+ * side effects - kline as given, is added to the hashtable
+ * and conf file
+ */
+static void
+apply_kline(struct Client *source_p, struct ConfItem *conf,
+ const char *current_date, time_t cur_time)
+{
+ struct AccessItem *aconf = map_to_conf(conf);
+
+ add_conf_by_address(CONF_KLINE, aconf);
+ write_conf_line(source_p, conf, current_date, cur_time);
+ /* Now, activate kline against current online clients */
+ rehashed_klines = 1;
+}
+
+/* apply_tkline()
+ *
+ * inputs -
+ * output - NONE
+ * side effects - tkline as given is placed
+ */
+static void
+apply_tkline(struct Client *source_p, struct ConfItem *conf,
+ int tkline_time)
+{
+ struct AccessItem *aconf;
+
+ aconf = (struct AccessItem *)map_to_conf(conf);
+ aconf->hold = CurrentTime + tkline_time;
+ SetConfTemporary(aconf);
+ add_conf_by_address(CONF_KLINE, aconf);
+
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s added temporary %d min. K-Line for [%s@%s] [%s]",
+ get_oper_name(source_p), tkline_time/60,
+ aconf->user, aconf->host,
+ aconf->reason);
+ sendto_one(source_p, ":%s NOTICE %s :Added temporary %d min. K-Line [%s@%s]",
+ MyConnect(source_p) ? me.name : ID_or_name(&me, source_p->from),
+ source_p->name, tkline_time/60, aconf->user, aconf->host);
+ ilog(LOG_TYPE_KLINE, "%s added temporary %d min. K-Line for [%s@%s] [%s]",
+ source_p->name, tkline_time/60,
+ aconf->user, aconf->host, aconf->reason);
+
+ rehashed_klines = 1;
+}
+
+/* already_placed_kline()
+ * inputs - user to complain to, username & host to check for
+ * outputs - returns 1 on existing K-line, 0 if doesn't exist
+ * side effects - notifies source_p if the K-line already exists
+ */
+/*
+ * Note: This currently works if the new K-line is a special case of an
+ * existing K-line, but not the other way round. To do that we would
+ * have to walk the hash and check every existing K-line. -A1kmm.
+ */
+static int
+already_placed_kline(struct Client *source_p, const char *luser, const char *lhost, int warn)
+{
+ const char *reason;
+ struct irc_ssaddr iphost, *piphost;
+ struct AccessItem *aconf;
+ int t;
+
+ if ((t = parse_netmask(lhost, &iphost, &t)) != HM_HOST)
+ {
+#ifdef IPV6
+ if (t == HM_IPV6)
+ t = AF_INET6;
+ else
+#endif
+ t = AF_INET;
+ piphost = &iphost;
+ }
+ else
+ {
+ t = 0;
+ piphost = NULL;
+ }
+
+ if ((aconf = find_conf_by_address(lhost, piphost, CONF_KLINE, t, luser, NULL, 0)))
+ {
+ if (warn)
+ {
+ reason = aconf->reason ? aconf->reason : "No reason";
+ sendto_one(source_p,
+ ":%s NOTICE %s :[%s@%s] already K-Lined by [%s@%s] - %s",
+ me.name, source_p->name, luser, lhost, aconf->user,
+ aconf->host, reason);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+** mo_unkline
+** Added Aug 31, 1997
+** common (Keith Fralick) fralick@gate.net
+**
+** parv[0] = sender
+** parv[1] = address to remove
+*
+*
+*/
+static void
+mo_unkline(struct Client *client_p,struct Client *source_p,
+ int parc, char *parv[])
+{
+ char *target_server = NULL;
+ char *user, *host;
+
+ if (!HasOFlag(source_p, OPER_FLAG_UNKLINE))
+ {
+ sendto_one(source_p, form_str(ERR_NOPRIVS),
+ me.name, source_p->name, "unkline");
+ return;
+ }
+
+ if (parc < 2 || EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, "UNKLINE");
+ return;
+ }
+
+ if (parse_aline("UNKLINE", source_p, parc, parv, 0, &user,
+ &host, NULL, &target_server, NULL) < 0)
+ return;
+
+ if (target_server != NULL)
+ {
+ sendto_match_servs(source_p, target_server, CAP_UNKLN,
+ "UNKLINE %s %s %s",
+ target_server, user, host);
+
+ /* Allow ON to apply local unkline as well if it matches */
+ if (!match(target_server, me.name))
+ return;
+ }
+ else
+ cluster_a_line(source_p, "UNKLINE", CAP_UNKLN, SHARED_UNKLINE,
+ "%s %s", user, host);
+
+ if (remove_tkline_match(host, user))
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :Un-klined [%s@%s] from temporary K-Lines",
+ me.name, source_p->name, user, host);
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s has removed the temporary K-Line for: [%s@%s]",
+ get_oper_name(source_p), user, host);
+ ilog(LOG_TYPE_KLINE, "%s removed temporary K-Line for [%s@%s]",
+ source_p->name, user, host);
+ return;
+ }
+
+ if (remove_conf_line(KLINE_TYPE, source_p, user, host) > 0)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :K-Line for [%s@%s] is removed",
+ me.name, source_p->name, user,host);
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s has removed the K-Line for: [%s@%s]",
+ get_oper_name(source_p), user, host);
+ ilog(LOG_TYPE_KLINE, "%s removed K-Line for [%s@%s]",
+ source_p->name, user, host);
+ }
+ else
+ sendto_one(source_p, ":%s NOTICE %s :No K-Line for [%s@%s] found",
+ me.name, source_p->name, user, host);
+}
+
+/* me_unkline()
+ *
+ * inputs - server
+ * - client
+ * - parc
+ * - parv
+ * outputs - none
+ * side effects - if server is authorized, kline is removed
+ * does not propagate message
+ */
+static void
+me_unkline(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ const char *kuser, *khost;
+
+ if (parc != 4)
+ return;
+
+ kuser = parv[2];
+ khost = parv[3];
+
+ if (!IsClient(source_p) || !match(parv[1], me.name))
+ return;
+
+ if (HasFlag(source_p, FLAGS_SERVICE) || find_matching_name_conf(ULINE_TYPE,
+ source_p->servptr->name,
+ source_p->username, source_p->host,
+ SHARED_UNKLINE))
+ {
+ if (remove_tkline_match(khost, kuser))
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :Un-klined [%s@%s] from temporary K-Lines",
+ me.name, source_p->name, kuser, khost);
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s has removed the temporary K-Line for: [%s@%s]",
+ get_oper_name(source_p), kuser, khost);
+ ilog(LOG_TYPE_KLINE, "%s removed temporary K-Line for [%s@%s]",
+ source_p->name, kuser, khost);
+ return;
+ }
+
+ if (remove_conf_line(KLINE_TYPE, source_p, kuser, khost) > 0)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :K-Line for [%s@%s] is removed",
+ me.name, source_p->name, kuser, khost);
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s has removed the K-Line for: [%s@%s]",
+ get_oper_name(source_p), kuser, khost);
+
+ ilog(LOG_TYPE_KLINE, "%s removed K-Line for [%s@%s]",
+ source_p->name, kuser, khost);
+ }
+ else
+ sendto_one(source_p, ":%s NOTICE %s :No K-Line for [%s@%s] found",
+ me.name, source_p->name, kuser, khost);
+ }
+}
+
+/* ms_unkline - propagates and handles a remote unkline message */
+static void
+ms_unkline(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (parc != 4)
+ return;
+
+ sendto_match_servs(source_p, parv[1], CAP_UNKLN,
+ "UNKLINE %s %s %s",
+ parv[1], parv[2], parv[3]);
+
+ me_unkline(client_p, source_p, parc, parv);
+}
+
+/* static int remove_tkline_match(const char *host, const char *user)
+ * Input: A hostname, a username to unkline.
+ * Output: returns YES on success, NO if no tkline removed.
+ * Side effects: Any matching tklines are removed.
+ */
+static int
+remove_tkline_match(const char *host, const char *user)
+{
+ struct irc_ssaddr iphost, *piphost;
+ struct AccessItem *aconf;
+ int t;
+
+ if ((t = parse_netmask(host, &iphost, NULL)) != HM_HOST)
+ {
+#ifdef IPV6
+ if (t == HM_IPV6)
+ t = AF_INET6;
+ else
+#endif
+ t = AF_INET;
+ piphost = &iphost;
+ }
+ else
+ {
+ t = 0;
+ piphost = NULL;
+ }
+
+ if ((aconf = find_conf_by_address(host, piphost, CONF_KLINE, t, user, NULL, 0)))
+ {
+ if (IsConfTemporary(aconf))
+ {
+ delete_one_address_conf(host, aconf);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static struct Message kline_msgtab = {
+ "KLINE", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_not_oper, ms_kline, me_kline, mo_kline, m_ignore}
+};
+
+static struct Message unkline_msgtab = {
+ "UNKLINE", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_not_oper, ms_unkline, me_unkline, mo_unkline, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&kline_msgtab);
+ mod_add_cmd(&unkline_msgtab);
+ add_capability("KLN", CAP_KLN, 1);
+ add_capability("UNKLN", CAP_UNKLN, 1);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&kline_msgtab);
+ mod_del_cmd(&unkline_msgtab);
+ delete_capability("UNKLN");
+ delete_capability("KLN");
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_knock.c b/modules/m_knock.c
new file mode 100644
index 0000000..4ce31d0
--- /dev/null
+++ b/modules/m_knock.c
@@ -0,0 +1,178 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_knock.c: Requests to be invited 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 "conf.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_serv.h"
+#include "s_user.h"
+
+
+/* m_knock
+ * parv[0] = sender prefix
+ * parv[1] = channel
+ *
+ * The KNOCK command has the following syntax:
+ * :<sender> KNOCK <channel>
+ *
+ * If a user is not banned from the channel they can use the KNOCK
+ * command to have the server NOTICE the channel operators notifying
+ * they would like to join. Helpful if the channel is invite-only, the
+ * key is forgotten, or the channel is full (INVITE can bypass each one
+ * of these conditions. Concept by Dianora <db@db.net> and written by
+ * <anonymous>
+ */
+static void
+m_knock(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Channel *chptr = NULL;
+
+ if (EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, "KNOCK");
+ return;
+ }
+
+ if ((chptr = hash_find_channel(parv[1])) == NULL)
+ {
+ sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
+ me.name, source_p->name, parv[1]);
+ return;
+ }
+
+ /* Normal channel, just be sure they aren't on it */
+ if (IsMember(source_p, chptr))
+ {
+ sendto_one(source_p, form_str(ERR_KNOCKONCHAN), me.name,
+ source_p->name, chptr->chname);
+ return;
+ }
+
+ if (!((chptr->mode.mode & MODE_INVITEONLY) || (*chptr->mode.key) ||
+ (chptr->mode.limit && dlink_list_length(&chptr->members) >=
+ chptr->mode.limit)))
+ {
+ sendto_one(source_p, form_str(ERR_CHANOPEN), me.name,
+ source_p->name, chptr->chname);
+ return;
+ }
+
+ if (MyClient(source_p))
+ {
+ /*
+ * Don't allow a knock if the user is banned, or the channel is private
+ */
+ if (PrivateChannel(chptr) || is_banned(chptr, source_p))
+ {
+ sendto_one(source_p, form_str(ERR_CANNOTSENDTOCHAN),
+ me.name, source_p->name, chptr->chname);
+ return;
+ }
+
+ /*
+ * flood protection:
+ * allow one knock per user per knock_delay
+ * allow one knock per channel per knock_delay_channel
+ *
+ * we only limit local requests..
+ */
+ if ((source_p->localClient->last_knock + ConfigChannel.knock_delay) >
+ CurrentTime)
+ {
+ sendto_one(source_p, form_str(ERR_TOOMANYKNOCK), me.name,
+ source_p->name, chptr->chname, "user");
+ return;
+ }
+
+ if ((chptr->last_knock + ConfigChannel.knock_delay_channel) > CurrentTime)
+ {
+ sendto_one(source_p, form_str(ERR_TOOMANYKNOCK), me.name,
+ source_p->name, chptr->chname, "channel");
+ return;
+ }
+
+ source_p->localClient->last_knock = CurrentTime;
+
+ sendto_one(source_p, form_str(RPL_KNOCKDLVR), me.name,
+ source_p->name, chptr->chname);
+ }
+
+ chptr->last_knock = CurrentTime;
+
+ sendto_channel_local(CHFL_CHANOP, 0, chptr,
+ ":%s NOTICE @%s :KNOCK: %s (%s [%s@%s] has asked for an invite)",
+ me.name, chptr->chname, chptr->chname,
+ source_p->name,
+ source_p->username,
+ source_p->host);
+
+ sendto_server(client_p, CAP_KNOCK|CAP_TS6, NOCAPS,
+ ":%s KNOCK %s", ID(source_p), chptr->chname);
+ sendto_server(client_p, CAP_KNOCK, CAP_TS6,
+ ":%s KNOCK %s", source_p->name, chptr->chname);
+}
+
+static struct Message knock_msgtab = {
+ "KNOCK", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_knock, m_knock, m_ignore, m_knock, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&knock_msgtab);
+ add_capability("KNOCK", CAP_KNOCK, 1);
+ add_isupport("KNOCK", NULL, -1);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&knock_msgtab);
+ delete_capability("KNOCK");
+ delete_isupport("KNOCK");
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_links.c b/modules/m_links.c
new file mode 100644
index 0000000..04192d4
--- /dev/null
+++ b/modules/m_links.c
@@ -0,0 +1,191 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_links.c: Shows what servers are currently connected.
+ *
+ * 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 "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_serv.h"
+#include "send.h"
+#include "conf.h"
+#include "motd.h"
+#include "parse.h"
+#include "modules.h"
+
+
+static void
+do_links(struct Client *source_p, int parc, char *parv[])
+{
+ sendto_realops_flags(UMODE_SPY, L_ALL,
+ "LINKS requested by %s (%s@%s) [%s]",
+ source_p->name,
+ source_p->username, source_p->host,
+ source_p->servptr->name);
+
+ if (HasUMode(source_p, UMODE_OPER) || !ConfigServerHide.flatten_links)
+ {
+ const char *mask = (parc > 2 ? parv[2] : parv[1]);
+ const char *me_name, *nick;
+ dlink_node *ptr;
+
+ me_name = ID_or_name(&me, source_p->from);
+ nick = ID_or_name(source_p, source_p->from);
+
+ DLINK_FOREACH(ptr, global_serv_list.head)
+ {
+ struct Client *target_p = ptr->data;
+
+ /* skip hidden servers */
+ if (IsHidden(target_p))
+ if (!HasUMode(source_p, UMODE_OPER))
+ continue;
+
+ if (!EmptyString(mask) && !match(mask, target_p->name))
+ continue;
+
+ /*
+ * We just send the reply, as if they are here there's either no SHIDE,
+ * or they're an oper..
+ */
+ sendto_one(source_p, form_str(RPL_LINKS),
+ me_name, nick,
+ target_p->name, target_p->servptr->name,
+ target_p->hopcount, target_p->info);
+ }
+
+ sendto_one(source_p, form_str(RPL_ENDOFLINKS),
+ me_name, nick,
+ EmptyString(mask) ? "*" : mask);
+ }
+ else
+ {
+ /*
+ * Print our own info so at least it looks like a normal links
+ * then print out the file (which may or may not be empty)
+ */
+ sendto_one(source_p, form_str(RPL_LINKS),
+ ID_or_name(&me, source_p->from),
+ ID_or_name(source_p, source_p->from),
+ me.name, me.name, 0, me.info);
+ send_message_file(source_p, &ConfigFileEntry.linksfile);
+ sendto_one(source_p, form_str(RPL_ENDOFLINKS),
+ ID_or_name(&me, source_p->from),
+ ID_or_name(source_p, source_p->from), "*");
+ }
+}
+
+static void
+mo_links(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (parc > 2)
+ if (!ConfigFileEntry.disable_remote || HasUMode(source_p, UMODE_OPER))
+ if (hunt_server(client_p, source_p, ":%s LINKS %s :%s", 1,
+ parc, parv) != HUNTED_ISME)
+ return;
+
+ do_links(source_p, parc, parv);
+}
+
+/*
+ * m_links - LINKS message handler
+ * parv[0] = sender prefix
+ * parv[1] = servername mask
+ * or
+ * parv[0] = sender prefix
+ * parv[1] = server to query
+ * parv[2] = servername mask
+ */
+static void
+m_links(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ static time_t last_used = 0;
+
+ if ((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
+ {
+ sendto_one(source_p, form_str(RPL_LOAD2HI),
+ me.name, source_p->name);
+ return;
+ }
+
+ last_used = CurrentTime;
+
+ if (!ConfigServerHide.flatten_links)
+ {
+ mo_links(client_p, source_p, parc, parv);
+ return;
+ }
+
+ do_links(source_p, parc, parv);
+}
+
+/*
+ * ms_links - LINKS message handler
+ * parv[0] = sender prefix
+ * parv[1] = servername mask
+ * or
+ * parv[0] = sender prefix
+ * parv[1] = server to query
+ * parv[2] = servername mask
+ */
+static void
+ms_links(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (hunt_server(client_p, source_p, ":%s LINKS %s :%s", 1,
+ parc, parv) != HUNTED_ISME)
+ return;
+
+ if (IsClient(source_p))
+ m_links(client_p, source_p, parc, parv);
+}
+
+static struct Message links_msgtab = {
+ "LINKS", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_links, ms_links, m_ignore, mo_links, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&links_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&links_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_list.c b/modules/m_list.c
new file mode 100644
index 0000000..c35fd3b
--- /dev/null
+++ b/modules/m_list.c
@@ -0,0 +1,200 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_list.c: List channel given or all channels.
+ *
+ * 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 "conf.h"
+#include "s_serv.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_user.h"
+
+
+static void
+do_list(struct Client *source_p, int parc, char *parv[])
+{
+ struct ListTask *lt;
+ int no_masked_channels;
+
+ if (source_p->localClient->list_task != NULL)
+ {
+ free_list_task(source_p->localClient->list_task, source_p);
+ sendto_one(source_p, form_str(RPL_LISTEND), me.name, source_p->name);
+ return;
+ }
+
+ lt = MyMalloc(sizeof(struct ListTask));
+ lt->users_max = UINT_MAX;
+ lt->created_max = UINT_MAX;
+ lt->topicts_max = UINT_MAX;
+ source_p->localClient->list_task = lt;
+
+ no_masked_channels = 1;
+
+ if (parc > 1)
+ {
+ char *opt, *save = NULL;
+ dlink_list *list;
+ int i, errors = 0;
+
+ for (opt = strtoken(&save, parv[1], ","); opt != NULL;
+ opt = strtoken(&save, NULL, ","))
+ switch (*opt)
+ {
+ case '<': if ((i = atoi(opt + 1)) > 0)
+ lt->users_max = (unsigned int) i - 1;
+ else
+ errors = 1;
+ break;
+ case '>': if ((i = atoi(opt + 1)) >= 0)
+ lt->users_min = (unsigned int) i + 1;
+ else
+ errors = 1;
+ break;
+ case '-': break;
+ case 'C':
+ case 'c': switch (*++opt)
+ {
+ case '<': if ((i = atoi(opt + 1)) >= 0)
+ lt->created_max = (unsigned int) (CurrentTime
+ - 60 * i);
+ else
+ errors = 1;
+ break;
+ case '>': if ((i = atoi(opt + 1)) >= 0)
+ lt->created_min = (unsigned int) (CurrentTime
+ - 60 * i);
+ else
+ errors = 1;
+ break;
+ default: errors = 1;
+ }
+ break;
+ case 'T':
+ case 't': switch (*++opt)
+ {
+ case '<': if ((i = atoi(opt + 1)) >= 0)
+ lt->topicts_min = (unsigned int) (CurrentTime
+ - 60 * i);
+ else
+ errors = 1;
+ break;
+ case '>': if ((i = atoi(opt + 1)) >= 0)
+ lt->topicts_max = (unsigned int) (CurrentTime
+ - 60 * i);
+ else
+ errors = 1;
+ break;
+ default: errors = 1;
+ }
+ break;
+ default: if (*opt == '!')
+ {
+ list = &lt->hide_mask;
+ opt++;
+ }
+ else list = &lt->show_mask;
+
+ if (has_wildcards(opt + !!IsChanPrefix(*opt)))
+ {
+ if (list == &lt->show_mask)
+ no_masked_channels = 0;
+ }
+ else if (!IsChanPrefix(*opt))
+ errors = 1;
+ if (!errors)
+ {
+ char *s;
+ DupString(s, opt);
+ dlinkAdd(s, make_dlink_node(), list);
+ }
+ }
+ if (errors)
+ {
+ free_list_task(lt, source_p);
+ sendto_one(source_p, form_str(ERR_LISTSYNTAX),
+ me.name, source_p->name);
+ return;
+ }
+ }
+
+
+ dlinkAdd(source_p, make_dlink_node(), &listing_client_list);
+
+ sendto_one(source_p, form_str(RPL_LISTSTART),
+ me.name, source_p->name);
+ safe_list_channels(source_p, lt, no_masked_channels &&
+ lt->show_mask.head != NULL);
+}
+
+/*
+** mo_list
+** parv[0] = sender prefix
+** parv[1] = channel
+*/
+static void
+m_list(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ do_list(source_p, parc, parv);
+}
+
+static struct Message list_msgtab = {
+ "LIST", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_list, m_ignore, m_ignore, m_list, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&list_msgtab);
+ add_isupport("ELIST", "CMNTU", -1);
+ add_isupport("SAFELIST", NULL, -1);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&list_msgtab);
+ delete_isupport("ELIST");
+ delete_isupport("SAFELIST");
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_locops.c b/modules/m_locops.c
new file mode 100644
index 0000000..534758f
--- /dev/null
+++ b/modules/m_locops.c
@@ -0,0 +1,107 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_locops.c: Sends a message to all operators on the local 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 "conf.h"
+#include "s_user.h"
+#include "s_serv.h"
+#include "hash.h"
+#include "parse.h"
+#include "modules.h"
+
+
+/*
+ * mo_locops - LOCOPS message handler
+ * (write to *all* local opers currently online)
+ * parv[0] = sender prefix
+ * parv[1] = message text
+ */
+static void
+mo_locops(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ const char *message = parv[1];
+
+ if (EmptyString(message))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, "LOCOPS");
+ return;
+ }
+
+ sendto_wallops_flags(UMODE_LOCOPS, source_p, "LOCOPS - %s",
+ message);
+
+ cluster_a_line(source_p, "LOCOPS", 0, SHARED_LOCOPS, message);
+}
+
+static void
+ms_locops(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (parc != 3 || EmptyString(parv[2]))
+ return;
+
+ sendto_server(client_p, CAP_CLUSTER, 0, "LOCOPS %s :%s",
+ parv[1], parv[2]);
+
+ if (!IsClient(source_p) || !match(parv[1], me.name))
+ return;
+
+ if (find_matching_name_conf(ULINE_TYPE, source_p->servptr->name,
+ "*", "*", SHARED_LOCOPS))
+ sendto_wallops_flags(UMODE_LOCOPS, source_p, "SLOCOPS - %s", parv[2]);
+}
+
+static struct Message locops_msgtab = {
+ "LOCOPS", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_not_oper, ms_locops, m_ignore, mo_locops, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&locops_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&locops_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_lusers.c b/modules/m_lusers.c
new file mode 100644
index 0000000..c7c41c5
--- /dev/null
+++ b/modules/m_lusers.c
@@ -0,0 +1,113 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_lusers.c: Sends user statistics.
+ *
+ * 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 "numeric.h"
+#include "s_serv.h" /* hunt_server */
+#include "s_user.h" /* show_lusers */
+#include "send.h"
+#include "conf.h"
+#include "parse.h"
+#include "modules.h"
+
+
+/* m_lusers - LUSERS message handler
+ * parv[0] = sender
+ * parv[1] = host/server mask.
+ * parv[2] = server to query
+ *
+ * 199970918 JRL hacked to ignore parv[1] completely and require parc > 3
+ * to cause a force
+ *
+ * 2003 hacked parv[1] back in, by request of efnet admins/opers -Dianora
+ */
+static void
+m_lusers(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ static time_t last_used = 0;
+
+ if ((last_used + ConfigFileEntry.pace_wait_simple) > CurrentTime)
+ {
+ /* safe enough to give this on a local connect only */
+ sendto_one(source_p, form_str(RPL_LOAD2HI), me.name, source_p->name);
+ return;
+ }
+
+ last_used = CurrentTime;
+
+ if (parc > 2 && !ConfigFileEntry.disable_remote)
+ if (hunt_server(client_p, source_p, ":%s LUSERS %s :%s", 2,
+ parc, parv) != HUNTED_ISME)
+ return;
+
+ show_lusers(source_p);
+}
+
+/* ms_lusers - LUSERS message handler for servers and opers
+ * parv[0] = sender
+ * parv[1] = host/server mask.
+ * parv[2] = server to query
+ */
+static void
+ms_lusers(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (parc > 2)
+ if (hunt_server(client_p, source_p, ":%s LUSERS %s :%s", 2,
+ parc, parv) != HUNTED_ISME)
+ return;
+
+ if (IsClient(source_p))
+ show_lusers(source_p);
+}
+
+static struct Message lusers_msgtab = {
+ "LUSERS", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_lusers, ms_lusers, m_ignore, ms_lusers, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&lusers_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&lusers_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_map.c b/modules/m_map.c
new file mode 100644
index 0000000..c1969c6
--- /dev/null
+++ b/modules/m_map.c
@@ -0,0 +1,184 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_map.c: Sends an Undernet compatible map to a user.
+ *
+ * Copyright (C) 2002 by the past and present ircd coders, and others.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * $Id$
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "modules.h"
+#include "numeric.h"
+#include "send.h"
+#include "conf.h"
+#include "ircd.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "parse.h"
+
+
+static char buf[IRCD_BUFSIZE];
+
+/* dump_map()
+ * dumps server map, called recursively.
+ */
+static void
+dump_map(struct Client *client_p, const struct Client *root_p,
+ int start_len, char *pbuf)
+{
+ int cnt = 0, i = 0, l = 0, len = start_len;
+ int users, dashes;
+ const dlink_node *ptr = NULL;
+ char *pb;
+
+ *pbuf= '\0';
+ pb = pbuf;
+
+ l = ircsprintf(pb, "%s", root_p->name);
+ pb += l;
+ len += l;
+
+ if (root_p->id[0] != '\0')
+ {
+ l = ircsprintf(pb, "[%s]", root_p->id);
+ pb += l;
+ len += l;
+ }
+
+ *pb++ = ' ';
+ len++;
+ dashes = 50 - len;
+
+ for (i = 0; i < dashes; i++)
+ *pb++ = '-';
+
+ *pb++ = ' ';
+ *pb++ = '|';
+
+ users = dlink_list_length(&root_p->serv->client_list);
+
+ sprintf(pb, " Users: %5d (%1.1f%%)", users,
+ 100 * (float)users / (float)Count.total);
+
+ sendto_one(client_p, form_str(RPL_MAP), me.name, client_p->name, buf);
+
+ if (root_p->serv->server_list.head)
+ {
+ cnt += dlink_list_length(&root_p->serv->server_list);
+
+ if (cnt)
+ {
+ if (pbuf > buf + 3)
+ {
+ pbuf[-2] = ' ';
+
+ if (pbuf[-3] == '`')
+ pbuf[-3] = ' ';
+ }
+ }
+ }
+
+ i = 1;
+
+ DLINK_FOREACH(ptr, root_p->serv->server_list.head)
+ {
+ const struct Client *server_p = ptr->data;
+
+ *pbuf = ' ';
+
+ if (i < cnt)
+ *(pbuf + 1) = '|';
+ else
+ *(pbuf + 1) = '`';
+
+ *(pbuf + 2) = '-';
+ *(pbuf + 3) = ' ';
+ dump_map(client_p, server_p, start_len + 4, pbuf + 4);
+
+ ++i;
+ }
+}
+
+/* m_map()
+ * parv[0] = sender prefix
+ */
+static void
+m_map(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ static time_t last_used = 0;
+
+ if (ConfigServerHide.flatten_links)
+ {
+ m_not_oper(client_p, source_p, parc, parv);
+ return;
+ }
+
+ if ((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
+ {
+ /* safe enough to give this on a local connect only */
+ sendto_one(source_p, form_str(RPL_LOAD2HI),
+ me.name, source_p->name);
+ return;
+ }
+
+ last_used = CurrentTime;
+
+ dump_map(source_p, &me, 0, buf);
+ sendto_one(source_p, form_str(RPL_MAPEND), me.name, source_p->name);
+}
+
+/* mo_map()
+ * parv[0] = sender prefix
+ */
+static void
+mo_map(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ dump_map(source_p, &me, 0, buf);
+ sendto_one(source_p, form_str(RPL_MAPEND), me.name, source_p->name);
+}
+
+static struct Message map_msgtab = {
+ "MAP", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_map, m_ignore, m_ignore, mo_map, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&map_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&map_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_module.c b/modules/m_module.c
new file mode 100644
index 0000000..a3a2d34
--- /dev/null
+++ b/modules/m_module.c
@@ -0,0 +1,263 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ *
+ * Copyright (C) 2002 by the past and present ircd coders, and others.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/*! \file m_module.c
+ * \brief Includes required functions for processing the MODULE command.
+ * \version $Id$
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "client.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "conf.h"
+#include "log.h"
+#include "s_user.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+#include "packet.h"
+
+
+
+/*! \brief MODULE command handler (called by operators)
+ *
+ * \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] = action [LOAD, UNLOAD, RELOAD, LIST]
+ * - parv[2] = module name
+ */
+static void
+mo_module(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ const char *m_bn = NULL;
+ struct module *modp = NULL;
+ int check_core;
+
+ if (!HasOFlag(source_p, OPER_FLAG_MODULE))
+ {
+ sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
+ me.name, source_p->name);
+ return;
+ }
+
+ if (EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, "MODULE");
+ return;
+ }
+
+ if (!irccmp(parv[1], "LOAD"))
+ {
+ if (EmptyString(parv[2]))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, "MODULE");
+ return;
+ }
+
+ if (findmodule_byname((m_bn = libio_basename(parv[2]))) != NULL)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :Module %s is already loaded",
+ me.name, source_p->name, m_bn);
+ return;
+ }
+
+ load_one_module(parv[2]);
+ return;
+ }
+
+ if (!irccmp(parv[1], "UNLOAD"))
+ {
+ if (EmptyString(parv[2]))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, "MODULE");
+ return;
+ }
+
+ if ((modp = findmodule_byname((m_bn = libio_basename(parv[2])))) == NULL)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :Module %s is not loaded",
+ me.name, source_p->name, m_bn);
+ return;
+ }
+
+ if (modp->flags & MODULE_FLAG_CORE)
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :Module %s is a core module and may not be unloaded",
+ me.name, source_p->name, m_bn);
+ return;
+ }
+
+ if (modp->flags & MODULE_FLAG_NOUNLOAD)
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :Module %s is a resident module and may not be unloaded",
+ me.name, source_p->name, m_bn);
+ return;
+ }
+
+ if (unload_one_module(m_bn, 1) == -1)
+ sendto_one(source_p, ":%s NOTICE %s :Module %s is not loaded",
+ me.name, source_p->name, m_bn);
+ return;
+ }
+
+ if (!irccmp(parv[1], "RELOAD"))
+ {
+ if (EmptyString(parv[2]))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, "MODULE");
+ return;
+ }
+
+ if (!strcmp(parv[2], "*"))
+ {
+ unsigned int modnum = 0;
+ dlink_node *ptr = NULL, *ptr_next = NULL;
+
+ sendto_one(source_p, ":%s NOTICE %s :Reloading all modules",
+ me.name, source_p->name);
+
+ modnum = dlink_list_length(&modules_list);
+
+ DLINK_FOREACH_SAFE(ptr, ptr_next, modules_list.head)
+ {
+ modp = ptr->data;
+
+ if (!(modp->flags & MODULE_FLAG_NOUNLOAD))
+ unload_one_module(modp->name, 0);
+ }
+
+ load_all_modules(0);
+ load_conf_modules();
+ load_core_modules(0);
+
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Module Restart: %u modules unloaded, %u modules loaded",
+ modnum, dlink_list_length(&modules_list));
+ ilog(LOG_TYPE_IRCD, "Module Restart: %u modules unloaded, %u modules loaded",
+ modnum, dlink_list_length(&modules_list));
+ return;
+ }
+
+ if ((modp = findmodule_byname((m_bn = libio_basename(parv[2])))) == NULL)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :Module %s is not loaded",
+ me.name, source_p->name, m_bn);
+ return;
+ }
+
+ if (modp->flags & MODULE_FLAG_NOUNLOAD)
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :Module %s is a resident module and may not be unloaded",
+ me.name, source_p->name, m_bn);
+ return;
+ }
+
+ check_core = (modp->flags & MODULE_FLAG_CORE) != 0;
+
+ if (unload_one_module(m_bn, 1) == -1)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :Module %s is not loaded",
+ me.name, source_p->name, m_bn);
+ return;
+ }
+
+ if ((load_one_module(parv[2]) == -1) && check_core)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL, "Error reloading core "
+ "module: %s: terminating ircd", parv[2]);
+ ilog(LOG_TYPE_IRCD, "Error loading core module %s: terminating ircd", parv[2]);
+ exit(0);
+ }
+
+ return;
+ }
+
+ if (!irccmp(parv[1], "LIST"))
+ {
+ const dlink_node *ptr = NULL;
+
+ DLINK_FOREACH(ptr, modules_list.head)
+ {
+ modp = ptr->data;
+
+ if (parc > 2 && !match(parv[2], modp->name))
+ continue;
+
+ sendto_one(source_p, form_str(RPL_MODLIST), me.name, source_p->name,
+ modp->name, modp->handle,
+ modp->version, (modp->flags & MODULE_FLAG_CORE) ?"(core)":"");
+ }
+
+ sendto_one(source_p, form_str(RPL_ENDOFMODLIST),
+ me.name, source_p->name);
+ return;
+ }
+
+ sendto_one(source_p, ":%s NOTICE %s :%s is not a valid option. "
+ "Choose from LOAD, UNLOAD, RELOAD, LIST",
+ me.name, source_p->name, parv[1]);
+}
+
+
+static struct Message module_msgtab = {
+ "MODULE", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_not_oper, m_ignore, m_ignore, mo_module, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&module_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&module_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = MODULE_FLAG_NOUNLOAD
+};
diff --git a/modules/m_motd.c b/modules/m_motd.c
new file mode 100644
index 0000000..4e0bd1c
--- /dev/null
+++ b/modules/m_motd.c
@@ -0,0 +1,130 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_motd.c: Shows the current message of the day.
+ *
+ * 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 "motd.h"
+#include "ircd.h"
+#include "send.h"
+#include "numeric.h"
+#include "s_serv.h" /* hunt_server */
+#include "parse.h"
+#include "modules.h"
+#include "conf.h"
+
+
+static void
+do_motd(struct Client *source_p)
+{
+ sendto_realops_flags(UMODE_SPY, L_ALL,
+ "MOTD requested by %s (%s@%s) [%s]",
+ source_p->name, source_p->username,
+ source_p->host, source_p->servptr->name);
+ send_message_file(source_p, &ConfigFileEntry.motd);
+}
+
+/*
+** m_motd
+** parv[0] = sender prefix
+** parv[1] = servername
+*/
+static void
+m_motd(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ static time_t last_used = 0;
+
+ if ((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
+ {
+ /* safe enough to give this on a local connect only */
+ sendto_one(source_p, form_str(RPL_LOAD2HI),
+ me.name, source_p->name);
+ return;
+ }
+
+ last_used = CurrentTime;
+
+ /* This is safe enough to use during non hidden server mode */
+ if (!ConfigFileEntry.disable_remote && !ConfigServerHide.hide_servers)
+ if (hunt_server(client_p, source_p, ":%s MOTD :%s", 1,
+ parc, parv) != HUNTED_ISME)
+ return;
+
+ do_motd(source_p);
+}
+
+/*
+ * note regarding mo_motd being used twice:
+ * this is not a kludge. any rate limiting, shide, or whatever
+ * other access restrictions should be done by the source's server.
+ * for security's sake, still check that the source is an oper
+ * for 'oper only' information in the mo_ function(s).
+ */
+
+/*
+** mo_motd
+** parv[0] = sender prefix
+** parv[1] = servername
+*/
+static void
+mo_motd(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (!IsClient(source_p))
+ return;
+
+ if (hunt_server(client_p, source_p, ":%s MOTD :%s", 1,
+ parc, parv) != HUNTED_ISME)
+ return;
+
+ do_motd(source_p);
+}
+
+static struct Message motd_msgtab = {
+ "MOTD", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_motd, mo_motd, m_ignore, mo_motd, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&motd_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&motd_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_names.c b/modules/m_names.c
new file mode 100644
index 0000000..ce56eb2
--- /dev/null
+++ b/modules/m_names.c
@@ -0,0 +1,196 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_names.c: Shows the users who are online.
+ *
+ * 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 "parse.h"
+#include "modules.h"
+
+
+/* names_all_visible_channels()
+ *
+ * inputs - pointer to client struct requesting names
+ * output - none
+ * side effects - lists all visible channels whee!
+ */
+static void
+names_all_visible_channels(struct Client *source_p)
+{
+ dlink_node *ptr = NULL;
+
+ /*
+ * First, do all visible channels (public and the one user self is)
+ */
+ DLINK_FOREACH(ptr, global_channel_list.head)
+ /* Find users on same channel (defined by chptr) */
+ channel_member_names(source_p, ptr->data, 0);
+}
+
+/* names_non_public_non_secret()
+ *
+ * inputs - pointer to client struct requesting names
+ * output - none
+ * side effects - lists all non public non secret channels
+ */
+static void
+names_non_public_non_secret(struct Client *source_p)
+{
+ int mlen, tlen, cur_len;
+ int reply_to_send = 0;
+ int shown_already;
+ dlink_node *gc2ptr, *lp;
+ struct Client *c2ptr;
+ struct Channel *ch3ptr = NULL;
+ char buf[IRCD_BUFSIZE];
+ char *t;
+
+ mlen = snprintf(buf, sizeof(buf), form_str(RPL_NAMREPLY),
+ me.name, source_p->name, "*", "*");
+ cur_len = mlen;
+ t = buf + mlen;
+
+ /* Second, do all non-public, non-secret channels in one big sweep */
+ DLINK_FOREACH(gc2ptr, global_client_list.head)
+ {
+ c2ptr = gc2ptr->data;
+
+ if (!IsClient(c2ptr) || HasUMode(c2ptr, UMODE_INVISIBLE))
+ continue;
+
+ shown_already = 0;
+
+ /* We already know the user is not +i. If they are on no common
+ * channels with source_p, they have not been shown yet. */
+ DLINK_FOREACH(lp, c2ptr->channel.head)
+ {
+ ch3ptr = ((struct Membership *) lp->data)->chptr;
+
+ if (IsMember(source_p, ch3ptr))
+ {
+ shown_already = 1;
+ break;
+ }
+ }
+
+ if (shown_already)
+ continue;
+
+ tlen = strlen(c2ptr->name);
+ if (cur_len + tlen + 1 > IRCD_BUFSIZE - 2)
+ {
+ sendto_one(source_p, "%s", buf);
+ cur_len = mlen;
+ t = buf + mlen;
+ }
+
+ strcpy(t, c2ptr->name);
+ t += tlen;
+
+ *t++ = ' ';
+ *t = 0;
+
+ cur_len += tlen + 1;
+
+ reply_to_send = 1;
+ }
+
+ if (reply_to_send)
+ sendto_one(source_p, "%s", buf);
+}
+
+/*
+** m_names
+** parv[0] = sender prefix
+** parv[1] = channel
+*/
+static void
+m_names(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Channel *chptr = NULL;
+ char *s;
+ char *para = parc > 1 ? parv[1] : NULL;
+
+ if (!EmptyString(para))
+ {
+ while (*para == ',')
+ ++para;
+
+ if ((s = strchr(para, ',')) != NULL)
+ *s = '\0';
+
+ if (*para == '\0')
+ return;
+
+ if ((chptr = hash_find_channel(para)) != NULL)
+ channel_member_names(source_p, chptr, 1);
+ else
+ sendto_one(source_p, form_str(RPL_ENDOFNAMES),
+ me.name, source_p->name, para);
+ }
+ else
+ {
+ names_all_visible_channels(source_p);
+ names_non_public_non_secret(source_p);
+ sendto_one(source_p, form_str(RPL_ENDOFNAMES),
+ me.name, source_p->name, "*");
+ }
+}
+
+static struct Message names_msgtab = {
+ "NAMES", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_names, m_ignore, m_ignore, m_names, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&names_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&names_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_oper.c b/modules/m_oper.c
new file mode 100644
index 0000000..c325755
--- /dev/null
+++ b/modules/m_oper.c
@@ -0,0 +1,161 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_oper.c: Makes a user an IRC Operator.
+ *
+ * Copyright (C) 2002 by the past and present ircd coders, and others.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * $Id$
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "client.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "conf.h"
+#include "log.h"
+#include "s_user.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+#include "packet.h"
+
+
+
+/* failed_oper_notice()
+ *
+ * inputs - pointer to client doing /oper ...
+ * - pointer to nick they tried to oper as
+ * - pointer to reason they have failed
+ * output - nothing
+ * side effects - notices all opers of the failed oper attempt if enabled
+ */
+static void
+failed_oper_notice(struct Client *source_p, const char *name,
+ const char *reason)
+{
+ if (ConfigFileEntry.failed_oper_notice)
+ sendto_realops_flags(UMODE_ALL, L_ALL, "Failed OPER attempt as %s "
+ "by %s (%s@%s) - %s", name, source_p->name,
+ source_p->username, source_p->host, reason);
+
+ ilog(LOG_TYPE_OPER, "Failed OPER attempt as %s "
+ "by %s (%s@%s) - %s", name, source_p->name,
+ source_p->username, source_p->host, reason);
+}
+
+/*
+** m_oper
+** parv[0] = sender prefix
+** parv[1] = oper name
+** parv[2] = oper password
+*/
+static void
+m_oper(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct ConfItem *conf;
+ struct AccessItem *aconf=NULL;
+ const char *name = parv[1];
+ const char *password = parv[2];
+
+ if (EmptyString(password))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, "OPER");
+ return;
+ }
+
+ /* end the grace period */
+ if (!IsFloodDone(source_p))
+ flood_endgrace(source_p);
+
+ if ((conf = find_exact_name_conf(OPER_TYPE, source_p, name, NULL, NULL)) == NULL)
+ {
+ sendto_one(source_p, form_str(ERR_NOOPERHOST), me.name, source_p->name);
+ conf = find_exact_name_conf(OPER_TYPE, NULL, name, NULL, NULL);
+ failed_oper_notice(source_p, name, (conf != NULL) ?
+ "host mismatch" : "no oper {} block");
+ return;
+ }
+
+ aconf = map_to_conf(conf);
+
+ if (match_conf_password(password, aconf))
+ {
+ if (attach_conf(source_p, conf) != 0)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :Can't attach conf!",
+ me.name, source_p->name);
+ failed_oper_notice(source_p, name, "can't attach conf!");
+ return;
+ }
+
+ oper_up(source_p);
+
+ ilog(LOG_TYPE_OPER, "OPER %s by %s!%s@%s",
+ name, source_p->name, source_p->username, source_p->host);
+ }
+ else
+ {
+ sendto_one(source_p, form_str(ERR_PASSWDMISMATCH), me.name, source_p->name);
+ failed_oper_notice(source_p, name, "password mismatch");
+ }
+}
+
+/*
+** mo_oper
+** parv[0] = sender prefix
+** parv[1] = oper name
+** parv[2] = oper password
+*/
+static void
+mo_oper(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ sendto_one(source_p, form_str(RPL_YOUREOPER),
+ me.name, source_p->name);
+}
+
+static struct Message oper_msgtab = {
+ "OPER", 0, 0, 3, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_oper, m_ignore, m_ignore, mo_oper, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&oper_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&oper_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_operwall.c b/modules/m_operwall.c
new file mode 100644
index 0000000..4d81f1c
--- /dev/null
+++ b/modules/m_operwall.c
@@ -0,0 +1,137 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_operwall.c: Sends a message to all IRCOps.
+ *
+ * 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 "s_user.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_serv.h"
+
+
+/*
+ * mo_operwall - OPERWALL message handler
+ * (write to *all* local opers currently online)
+ * parv[0] = sender prefix
+ * parv[1] = message text
+ */
+static void
+mo_operwall(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ const char *message = parv[1];
+
+ if (!HasOFlag(source_p, OPER_FLAG_OPERWALL))
+ {
+ sendto_one(source_p, form_str(ERR_NOPRIVS),
+ me.name, source_p->name, "operwall");
+ return;
+ }
+
+ if (EmptyString(message))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, "OPERWALL");
+ return;
+ }
+
+ sendto_server(NULL, CAP_TS6, NOCAPS,
+ ":%s OPERWALL :%s", ID(source_p), message);
+ sendto_server(NULL, NOCAPS, CAP_TS6,
+ ":%s OPERWALL :%s", source_p->name, message);
+ sendto_wallops_flags(UMODE_OPERWALL, source_p, "OPERWALL - %s", message);
+}
+
+/*
+ * ms_operwall - OPERWALL message handler
+ * (write to *all* local opers currently online)
+ * parv[0] = sender prefix
+ * parv[1] = message text
+ */
+static void
+ms_operwall(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ const char *message = parv[1];
+
+ if (EmptyString(message))
+ return;
+
+ sendto_server(client_p, CAP_TS6, NOCAPS, ":%s OPERWALL :%s",
+ ID(source_p), message);
+ sendto_server(client_p, NOCAPS, CAP_TS6, ":%s OPERWALL :%s",
+ source_p->name, message);
+ sendto_wallops_flags(UMODE_OPERWALL, source_p, "OPERWALL - %s", message);
+}
+
+/*
+ * me_operwall - OPERWALL message handler
+ * (write to *all* local opers currently online)
+ * parv[0] = sender prefix
+ * parv[1] = message text
+ *
+ * Lets ms_encap handle propagation.
+ */
+static void
+me_operwall(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ const char *message = parv[1];
+
+ if (EmptyString(message))
+ return;
+
+ sendto_wallops_flags(UMODE_OPERWALL, source_p, "OPERWALL - %s", message);
+}
+
+static struct Message operwall_msgtab = {
+ "OPERWALL", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_not_oper, ms_operwall, me_operwall, mo_operwall, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&operwall_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&operwall_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_pass.c b/modules/m_pass.c
new file mode 100644
index 0000000..be78c7c
--- /dev/null
+++ b/modules/m_pass.c
@@ -0,0 +1,115 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_pass.c: Used to send a password for a server or client{} block.
+ *
+ * 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" /* client struct */
+#include "irc_string.h"
+#include "send.h" /* sendto_one */
+#include "numeric.h" /* ERR_xxx */
+#include "ircd.h" /* me */
+#include "parse.h"
+#include "modules.h"
+#include "s_serv.h"
+#include "s_user.h"
+
+
+/*
+ * m_pass() - Added Sat, 4 March 1989
+ *
+ *
+ * mr_pass - PASS message handler
+ * parv[0] = sender prefix
+ * parv[1] = password
+ * parv[2] = optional extra version information
+ */
+static void
+mr_pass(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ char *password = parv[1];
+
+ assert(client_p == source_p);
+
+ if (EmptyString(password))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name,
+ source_p->name[0] ? source_p->name : "*", "PASS");
+ return;
+ }
+
+ MyFree(source_p->localClient->passwd);
+ if (strlen(password) > PASSWDLEN)
+ password[PASSWDLEN] = '\0';
+ DupString(source_p->localClient->passwd, password);
+
+ if (parc > 2)
+ {
+ /* It looks to me as if orabidoo wanted to have more
+ * than one set of option strings possible here...
+ * i.e. ":AABBTS" as long as TS was the last two chars
+ * however, as we are now using CAPAB, I think we can
+ * safely assume if there is a ":TS" then its a TS server
+ * -Dianora
+ */
+ if (!irccmp(parv[2], "TS") && source_p->tsinfo == 0)
+ source_p->tsinfo = TS_DOESTS;
+ }
+
+ /* only do this stuff if we are doing ts6 */
+ if (parc > 4)
+ {
+ if (atoi(parv[3]) >= 6 && valid_sid(parv[4]))
+ {
+ strlcpy(source_p->id, parv[4], sizeof(source_p->id));
+ SetCapable(source_p, CAP_TS6);
+ }
+ }
+}
+
+static struct Message pass_msgtab = {
+ "PASS", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
+ { mr_pass, m_registered, m_ignore, m_ignore, m_registered, mr_pass }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&pass_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&pass_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_ping.c b/modules/m_ping.c
new file mode 100644
index 0000000..520b00a
--- /dev/null
+++ b/modules/m_ping.c
@@ -0,0 +1,149 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_ping.c: Requests that a PONG message be sent back.
+ *
+ * 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 "numeric.h"
+#include "send.h"
+#include "irc_string.h"
+#include "parse.h"
+#include "modules.h"
+#include "hash.h"
+#include "conf.h"
+#include "s_serv.h"
+
+
+/*
+** m_ping
+** parv[0] = sender prefix
+** parv[1] = origin
+** parv[2] = destination
+*/
+static void
+m_ping(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *target_p;
+ char *origin, *destination;
+
+ if (parc < 2 || EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NOORIGIN),
+ me.name, source_p->name);
+ return;
+ }
+
+ origin = parv[1];
+ destination = parv[2]; /* Will get NULL or pointer (parc >= 2!!) */
+
+ if (ConfigFileEntry.disable_remote && !HasUMode(source_p, UMODE_OPER))
+ {
+ sendto_one(source_p, ":%s PONG %s :%s", me.name,
+ (destination) ? destination : me.name, origin);
+ return;
+ }
+
+ if (!EmptyString(destination) && irccmp(destination, me.name) != 0)
+ {
+ /* We're sending it across servers.. origin == client_p->name --fl_ */
+ origin = client_p->name;
+
+ if ((target_p = hash_find_server(destination)) != NULL)
+ {
+ sendto_one(target_p, ":%s PING %s :%s", source_p->name,
+ origin, destination);
+ }
+ else
+ {
+ sendto_one(source_p, form_str(ERR_NOSUCHSERVER),
+ me.name, source_p->name, destination);
+ return;
+ }
+ }
+ else
+ sendto_one(source_p, ":%s PONG %s :%s", me.name,
+ (destination) ? destination : me.name, origin);
+}
+
+static void
+ms_ping(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *target_p;
+ const char *origin, *destination;
+
+ if (parc < 2 || EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NOORIGIN),
+ me.name, source_p->name);
+ return;
+ }
+
+ origin = source_p->name;
+ destination = parv[2]; /* Will get NULL or pointer (parc >= 2!!) */
+
+ if (!EmptyString(destination) && irccmp(destination, me.name) != 0 && irccmp(destination, me.id) != 0)
+ {
+ if ((target_p = hash_find_server(destination)))
+ sendto_one(target_p, ":%s PING %s :%s", source_p->name,
+ origin, destination);
+ else
+ {
+ sendto_one(source_p, form_str(ERR_NOSUCHSERVER),
+ ID_or_name(&me, client_p), source_p->name, destination);
+ return;
+ }
+ }
+ else
+ sendto_one(source_p, ":%s PONG %s :%s",
+ ID_or_name(&me, client_p), (destination) ? destination : me.name, origin);
+}
+
+static struct Message ping_msgtab = {
+ "PING", 0, 0, 1, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_ping, ms_ping, m_ignore, m_ping, m_ping}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&ping_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&ping_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_pong.c b/modules/m_pong.c
new file mode 100644
index 0000000..c12a0a6
--- /dev/null
+++ b/modules/m_pong.c
@@ -0,0 +1,135 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_pong.c: The reply to a ping message.
+ *
+ * Copyright (C) 2002 by the past and present ircd coders, and others.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * $Id$
+ */
+
+#include "stdinc.h"
+#include "ircd.h"
+#include "s_user.h"
+#include "client.h"
+#include "hash.h" /* for find_client() */
+#include "numeric.h"
+#include "conf.h"
+#include "send.h"
+#include "irc_string.h"
+#include "parse.h"
+#include "modules.h"
+
+
+static void
+ms_pong(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *target_p;
+ const char *origin, *destination;
+
+ if (parc < 2 || EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NOORIGIN),
+ me.name, source_p->name);
+ return;
+ }
+
+ origin = parv[1];
+ destination = parv[2];
+
+ /* Now attempt to route the PONG, comstud pointed out routable PING
+ * is used for SPING. routable PING should also probably be left in
+ * -Dianora
+ * That being the case, we will route, but only for registered clients (a
+ * case can be made to allow them only from servers). -Shadowfax
+ */
+ if (!EmptyString(destination) && !match(destination, me.name) &&
+ irccmp(destination, me.id))
+ {
+ if ((target_p = hash_find_client(destination)) ||
+ (target_p = hash_find_server(destination)))
+ sendto_one(target_p, ":%s PONG %s %s",
+ source_p->name, origin, destination);
+ else
+ {
+ sendto_one(source_p, form_str(ERR_NOSUCHSERVER),
+ me.name, source_p->name, destination);
+ return;
+ }
+ }
+}
+
+static void
+mr_pong(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ assert(source_p == client_p);
+
+ if (parc == 2 && *parv[1] != '\0')
+ {
+ if (ConfigFileEntry.ping_cookie && !source_p->localClient->registration)
+ {
+ unsigned int incoming_ping = strtoul(parv[1], NULL, 10);
+
+ if (incoming_ping)
+ {
+ if (source_p->localClient->random_ping == incoming_ping)
+ {
+ SetPingCookie(source_p);
+ register_local_user(source_p);
+ }
+ else
+ {
+ sendto_one(source_p, form_str(ERR_WRONGPONG), me.name,
+ source_p->name, source_p->localClient->random_ping);
+ return;
+ }
+ }
+ }
+ }
+ else
+ sendto_one(source_p, form_str(ERR_NOORIGIN),
+ me.name, source_p->name);
+}
+
+static struct Message pong_msgtab = {
+ "PONG", 0, 0, 1, MAXPARA, MFLG_SLOW, 0,
+ {mr_pong, m_ignore, ms_pong, m_ignore, m_ignore, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&pong_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&pong_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_post.c b/modules/m_post.c
new file mode 100644
index 0000000..f8e6ff6
--- /dev/null
+++ b/modules/m_post.c
@@ -0,0 +1,87 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_post.c: Exits the user if unregistered, it is a web form.
+ *
+ * Copyright (C) 2001-2002 Hybrid Development Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * $Id$
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "ircd.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+
+
+/*
+** mr_dumb_proxy
+** parv[0] = sender prefix
+** parv[1] = comment
+*/
+static void
+mr_dumb_proxy(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ sendto_realops_flags(UMODE_REJ, L_ALL,
+ "HTTP Proxy disconnected: [%s@%s]",
+ client_p->username, client_p->host);
+ exit_client(source_p, source_p, "Client Exit");
+}
+
+static struct Message post_msgtab = {
+ "POST", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ {mr_dumb_proxy, m_ignore, m_ignore, m_ignore, m_ignore, m_ignore}
+};
+
+static struct Message get_msgtab = {
+ "GET", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ {mr_dumb_proxy, m_ignore, m_ignore, m_ignore, m_ignore, m_ignore}
+};
+
+static struct Message put_msgtab = {
+ "PUT", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ {mr_dumb_proxy, m_ignore, m_ignore, m_ignore, m_ignore, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&post_msgtab);
+ mod_add_cmd(&get_msgtab);
+ mod_add_cmd(&put_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&post_msgtab);
+ mod_del_cmd(&get_msgtab);
+ mod_del_cmd(&put_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_rehash.c b/modules/m_rehash.c
new file mode 100644
index 0000000..f73c867
--- /dev/null
+++ b/modules/m_rehash.c
@@ -0,0 +1,136 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_rehash.c: Re-reads the configuration file.
+ *
+ * Copyright (C) 2002 by the past and present ircd coders, and others.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * $Id$
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "list.h"
+#include "numeric.h"
+#include "irc_res.h"
+#include "conf.h"
+#include "log.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+
+
+/*
+ * mo_rehash - REHASH message handler
+ *
+ */
+static void
+mo_rehash(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ int found = 0;
+
+ if (!HasOFlag(source_p, OPER_FLAG_REHASH))
+ {
+ sendto_one(source_p, form_str(ERR_NOPRIVS),
+ me.name, source_p->name, "rehash");
+ return;
+ }
+
+ if (parc > 1)
+ {
+ if (irccmp(parv[1], "DNS") == 0)
+ {
+ sendto_one(source_p, form_str(RPL_REHASHING), me.name, source_p->name, "DNS");
+ sendto_realops_flags(UMODE_ALL, L_ALL, "%s is rehashing DNS",
+ get_oper_name(source_p));
+ restart_resolver(); /* re-read /etc/resolv.conf AGAIN?
+ and close/re-open res socket */
+ found = 1;
+ }
+ else if (irccmp(parv[1], "FDLIMIT") == 0)
+ {
+ sendto_one(source_p, form_str(RPL_REHASHING), me.name,
+ source_p->name, "FDLIMIT");
+ sendto_realops_flags(UMODE_ALL, L_ALL, "%s is updating FDLIMIT",
+ get_oper_name(source_p));
+ recalc_fdlimit(NULL);
+ found = 1;
+ }
+ else if (irccmp(parv[1], "MOTD") == 0)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s is forcing re-reading of MOTD file",
+ get_oper_name(source_p));
+ read_message_file(&ConfigFileEntry.motd);
+ found = 1;
+ }
+
+ if (found)
+ {
+ ilog(LOG_TYPE_IRCD, "REHASH %s From %s",
+ parv[1], get_client_name(source_p, HIDE_IP));
+ return;
+ }
+ else
+ {
+ sendto_one(source_p, ":%s NOTICE %s :rehash one of :DNS FDLIMIT "
+ "MOTD", me.name, source_p->name);
+ return;
+ }
+ }
+ else
+ {
+ sendto_one(source_p, form_str(RPL_REHASHING),
+ me.name, source_p->name, ConfigFileEntry.configfile);
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s is rehashing server config file",
+ get_oper_name(source_p));
+ ilog(LOG_TYPE_IRCD, "REHASH From %s[%s]",
+ get_oper_name(source_p), source_p->sockhost);
+ rehash(0);
+ }
+}
+
+static struct Message rehash_msgtab = {
+ "REHASH", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_not_oper, m_ignore, m_ignore, mo_rehash, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&rehash_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&rehash_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_restart.c b/modules/m_restart.c
new file mode 100644
index 0000000..50e91ea
--- /dev/null
+++ b/modules/m_restart.c
@@ -0,0 +1,98 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_restart.c: Exits and re-runs ircd.
+ *
+ * Copyright (C) 2002 by the past and present ircd coders, and others.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * $Id$
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "restart.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+#include "conf.h"
+
+
+/*
+ * mo_restart
+ *
+ */
+static void
+mo_restart(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ char buf[IRCD_BUFSIZE];
+
+ if (!HasOFlag(source_p, OPER_FLAG_RESTART))
+ {
+ sendto_one(source_p, form_str(ERR_NOPRIVS),
+ me.name, source_p->name, "restart");
+ return;
+ }
+
+ if (EmptyString(parv[1]))
+ {
+ sendto_one(source_p, ":%s NOTICE %s :Need server name /restart %s",
+ me.name, source_p->name, me.name);
+ return;
+ }
+
+ if (irccmp(parv[1], me.name))
+ {
+ sendto_one(source_p, ":%s NOTICE %s :Mismatch on /restart %s",
+ me.name, source_p->name, me.name);
+ return;
+ }
+
+ snprintf(buf, sizeof(buf), "received RESTART command from %s",
+ get_oper_name(source_p));
+ server_die(buf, 1);
+}
+
+static struct Message restart_msgtab = {
+ "RESTART", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_not_oper, m_ignore, m_ignore, mo_restart, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&restart_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&restart_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_resv.c b/modules/m_resv.c
new file mode 100644
index 0000000..e733ddc
--- /dev/null
+++ b/modules/m_resv.c
@@ -0,0 +1,434 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_resv.c: Reserves(jupes) a nickname or channel.
+ *
+ * Copyright (C) 2001-2002 Hybrid Development Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * $Id$
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "channel.h"
+#include "ircd.h"
+#include "irc_string.h"
+#include "numeric.h"
+#include "s_serv.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+#include "conf.h"
+#include "log.h"
+#include "resv.h"
+#include "hash.h"
+
+
+static void parse_resv(struct Client *, char *, int, char *);
+static void remove_resv(struct Client *, const char *);
+
+
+/* mo_resv()
+ * parv[0] = sender prefix
+ * parv[1] = channel/nick to forbid
+ */
+static void
+mo_resv(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ char *resv = NULL;
+ char *reason = NULL;
+ char *target_server = NULL;
+ time_t tkline_time = 0;
+
+ /* RESV #channel ON irc.server.com :abuse
+ * RESV kiddie ON irc.server.com :abuse
+ */
+ if (parse_aline("RESV", source_p, parc, parv,
+ AWILD, &resv, NULL, &tkline_time, &target_server, &reason) < 0)
+ return;
+
+ if (target_server != NULL)
+ {
+ /* if a given expire time is given, ENCAP it */
+ if (tkline_time != 0)
+ sendto_match_servs(source_p, target_server, CAP_ENCAP,
+ "ENCAP %s RESV %d %s 0 :%s",
+ target_server, (int)tkline_time, resv, reason);
+ else
+ sendto_match_servs(source_p, target_server, CAP_CLUSTER,
+ "RESV %s %s :%s",
+ target_server, resv, reason);
+ /* Allow ON to apply local resv as well if it matches */
+ if (!match(target_server, me.name))
+ return;
+ }
+ else
+ {
+ /* RESV #channel :abuse
+ * RESV kiddie :abuse
+ */
+ if (tkline_time != 0)
+ cluster_a_line(source_p, "ENCAP", CAP_ENCAP, SHARED_RESV,
+ "RESV %d %s 0 : %s", (int)tkline_time, resv, reason);
+ else
+ cluster_a_line(source_p, "RESV", CAP_KLN, SHARED_RESV,
+ "%s : %s", resv, reason);
+ }
+
+ parse_resv(source_p, resv, (int)tkline_time, reason);
+}
+
+/* me_resv()
+ *
+ * inputs - server
+ * - client (oper)
+ * - parc number of arguments
+ * - parv list of arguments
+ * via parv[]
+ * parv[0] = client name applying resv
+ * parv[1] = tkline_time
+ * parv[2] = name
+ * parv[3] = 0
+ * parv[4] = reason
+ * parc should be 5
+ *
+ * outputs - NONE
+ * side effects -
+ */
+static void
+me_resv(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (parc != 5 || !IsClient(source_p))
+ return;
+
+ parse_resv(source_p, parv[2], atoi(parv[1]), parv[4]);
+}
+
+/* ms_resv()
+ * parv[0] = sender prefix
+ * parv[1] = target server
+ * parv[2] = channel/nick to resv
+ * parv[3] = reason
+ */
+static void
+ms_resv(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if ((parc != 4) || EmptyString(parv[3]))
+ return;
+
+ sendto_match_servs(source_p, parv[1], CAP_CLUSTER,
+ "RESV %s %s :%s",
+ parv[1], parv[2], parv[3]);
+
+ if (!IsClient(source_p) || !match(parv[1], me.name))
+ return;
+
+ if (HasFlag(source_p, FLAGS_SERVICE) || find_matching_name_conf(ULINE_TYPE, source_p->servptr->name,
+ source_p->username, source_p->host,
+ SHARED_RESV))
+ parse_resv(source_p, parv[2], 0, parv[3]);
+}
+
+/* mo_unresv()
+ * parv[0] = sender prefix
+ * parv[1] = channel/nick to unforbid
+ */
+static void
+mo_unresv(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ char *resv = NULL;
+ char *reason = NULL;
+ char *target_server = NULL;
+
+ /* UNRESV #channel ON irc.server.com */
+ /* UNRESV kiddie ON irc.server.com */
+ if (parse_aline("UNRESV", source_p, parc, parv,
+ 0, &resv, NULL, NULL, &target_server, &reason) < 0)
+ return;
+
+ if (target_server != NULL)
+ {
+ sendto_match_servs(source_p, target_server, CAP_CLUSTER,
+ "UNRESV %s %s",
+ target_server, resv);
+
+ /* Allow ON to apply local unresv as well if it matches */
+ if (!match(target_server, me.name))
+ return;
+ }
+ else
+ cluster_a_line(source_p, "UNRESV", CAP_KLN, SHARED_UNRESV, resv);
+
+ remove_resv(source_p, resv);
+}
+
+/* ms_unresv()
+ * parv[0] = sender prefix
+ * parv[1] = target server
+ * parv[2] = resv to remove
+ */
+static void
+ms_unresv(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if ((parc != 3) || EmptyString(parv[2]))
+ return;
+
+ sendto_match_servs(source_p, parv[1], CAP_CLUSTER,
+ "UNRESV %s %s",
+ parv[1], parv[2]);
+
+ if (!IsClient(source_p) || !match(parv[1], me.name))
+ return;
+
+ if (HasFlag(source_p, FLAGS_SERVICE) || find_matching_name_conf(ULINE_TYPE, source_p->servptr->name,
+ source_p->username, source_p->host,
+ SHARED_UNRESV))
+ remove_resv(source_p, parv[2]);
+}
+
+/* parse_resv()
+ *
+ * inputs - source_p, NULL supported
+ * - thing to resv
+ * - time_t if tkline
+ * - reason
+ * outputs - none
+ * side effects - parse resv, create if valid
+ */
+static void
+parse_resv(struct Client *source_p, char *name, int tkline_time, char *reason)
+{
+ struct ConfItem *conf = NULL;
+
+ if (IsChanPrefix(*name))
+ {
+ struct ResvChannel *resv_p;
+
+ if ((conf = create_channel_resv(name, reason, 0)) == NULL)
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :A RESV has already been placed on channel: %s",
+ me.name, source_p->name, name);
+ return;
+ }
+
+ resv_p = map_to_conf(conf);
+
+ if (tkline_time != 0)
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :A %d minute %s RESV has been placed on channel: %s",
+ me.name, source_p->name,
+ tkline_time/60,
+ (MyClient(source_p) ? "local" : "remote"), name);
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s has placed a %d minute %s RESV on channel: %s [%s]",
+ get_oper_name(source_p),
+ tkline_time/60,
+ (MyClient(source_p) ? "local" : "remote"),
+ resv_p->name, resv_p->reason);
+ ilog(LOG_TYPE_IRCD, "%s added temporary %d min. RESV for [%s] [%s]",
+ source_p->name, (int)tkline_time/60,
+ conf->name, resv_p->reason);
+ resv_p->hold = CurrentTime + tkline_time;
+ add_temp_line(conf);
+ }
+ else
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :A %s RESV has been placed on channel %s",
+ me.name, source_p->name,
+ (MyClient(source_p) ? "local" : "remote"), name);
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s has placed a %s RESV on channel %s : [%s]",
+ get_oper_name(source_p),
+ (MyClient(source_p) ? "local" : "remote"),
+ resv_p->name, resv_p->reason);
+ write_conf_line(source_p, conf, NULL /* not used */, 0 /* not used */);
+ }
+ }
+ else
+ {
+ struct MatchItem *resv_p = NULL;
+
+ if (!valid_wild_card_simple(name))
+ {
+ sendto_one(source_p, ":%s NOTICE %s :Please include at least %d non-wildcard characters with the resv",
+ me.name, source_p->name, ConfigFileEntry.min_nonwildcard_simple);
+ return;
+ }
+
+ if (!HasUMode(source_p, UMODE_ADMIN) && strpbrk(name, "*?#"))
+ {
+ sendto_one(source_p, ":%s NOTICE %s :You must be an admin to perform a "
+ "wildcard RESV", me.name, source_p->name);
+ return;
+ }
+
+ if ((conf = create_nick_resv(name, reason, 0)) == NULL)
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :A RESV has already been placed on nick %s",
+ me.name, source_p->name, name);
+ return;
+ }
+
+ resv_p = map_to_conf(conf);
+
+ if (tkline_time != 0)
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :A %d minute %s RESV has been placed on nick %s : [%s]",
+ me.name, source_p->name,
+ tkline_time/60,
+ (MyClient(source_p) ? "local" : "remote"),
+ conf->name, resv_p->reason);
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s has placed a %d minute %s RESV on nick %s : [%s]",
+ get_oper_name(source_p),
+ tkline_time/60,
+ (MyClient(source_p) ? "local" : "remote"),
+ conf->name, resv_p->reason);
+ ilog(LOG_TYPE_IRCD, "%s added temporary %d min. RESV for [%s] [%s]",
+ source_p->name, (int)tkline_time/60,
+ conf->name, resv_p->reason);
+ resv_p->hold = CurrentTime + tkline_time;
+ add_temp_line(conf);
+ }
+ else
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :A %s RESV has been placed on nick %s : [%s]",
+ me.name, source_p->name,
+ (MyClient(source_p) ? "local" : "remote"),
+ conf->name, resv_p->reason);
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s has placed a %s RESV on nick %s : [%s]",
+ get_oper_name(source_p),
+ (MyClient(source_p) ? "local" : "remote"),
+ conf->name, resv_p->reason);
+ write_conf_line(source_p, conf, NULL /* not used */, 0 /* not used */);
+ }
+ }
+}
+
+static void
+remove_resv(struct Client *source_p, const char *name)
+{
+ struct ConfItem *conf = NULL;
+
+ if (IsChanPrefix(*name))
+ {
+ struct ResvChannel *resv_p;
+
+ if (resv_channel_list.head == NULL ||
+ !(resv_p = hash_find_resv(name)))
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :A RESV does not exist for channel: %s",
+ me.name, source_p->name, name);
+ return;
+ }
+
+ if (resv_p->conf)
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :The RESV for channel: %s is in ircd.conf and must be removed by hand.",
+ me.name, source_p->name, name);
+ return;
+ }
+
+ delete_channel_resv(resv_p);
+ remove_conf_line(CRESV_TYPE, source_p, name, NULL);
+
+ sendto_one(source_p,
+ ":%s NOTICE %s :The RESV has been removed on channel: %s",
+ me.name, source_p->name, name);
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s has removed the RESV for channel: %s",
+ get_oper_name(source_p), name);
+ }
+ else
+ {
+ struct MatchItem *resv_p = NULL;
+
+ if ((conf = find_exact_name_conf(NRESV_TYPE, NULL, name, NULL, NULL)) == NULL)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :A RESV does not exist for nick: %s",
+ me.name, source_p->name, name);
+ return;
+ }
+
+ resv_p = map_to_conf(conf);
+
+ if (resv_p->action)
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :The RESV for nick: %s is in ircd.conf and must be removed by hand.",
+ me.name, source_p->name, name);
+ return;
+ }
+
+ delete_conf_item(conf);
+ remove_conf_line(NRESV_TYPE, source_p, name, NULL);
+
+ sendto_one(source_p, ":%s NOTICE %s :The RESV has been removed on nick: %s",
+ me.name, source_p->name, name);
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s has removed the RESV for nick: %s",
+ get_oper_name(source_p), name);
+ }
+}
+
+static struct Message resv_msgtab = {
+ "RESV", 0, 0, 3, MAXPARA, MFLG_SLOW, 0,
+ { m_ignore, m_not_oper, ms_resv, me_resv, mo_resv, m_ignore }
+};
+
+static struct Message unresv_msgtab = {
+ "UNRESV", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
+ { m_ignore, m_not_oper, ms_unresv, m_ignore, mo_unresv, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&resv_msgtab);
+ mod_add_cmd(&unresv_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&resv_msgtab);
+ mod_del_cmd(&unresv_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_services.c b/modules/m_services.c
new file mode 100644
index 0000000..d8881f4
--- /dev/null
+++ b/modules/m_services.c
@@ -0,0 +1,355 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ *
+ * Copyright (C) 1999 by the Bahamut Development Team.
+ * Copyright (C) 2011 by the Hybrid Development Team.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/*! \file m_services.c
+ * \brief Provides service aliases
+ * \version $Id$
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "ircd.h"
+#include "channel_mode.h"
+#include "numeric.h"
+#include "conf.h"
+#include "s_serv.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+#include "irc_string.h"
+#include "s_user.h"
+#include "hash.h"
+
+
+/*
+ * XXX: Each services alias handler is currently ugly copy&paste.
+ * Configureable aliases will get implemented.
+ */
+
+static void
+m_nickserv(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *target_p = NULL;
+
+ assert(client_p && source_p);
+ assert(client_p == source_p);
+
+ if (EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NOTEXTTOSEND),
+ me.name, source_p->name);
+ return;
+ }
+
+ if ((target_p = hash_find_server(ConfigFileEntry.service_name)))
+ {
+ sendto_one(target_p, ":%s PRIVMSG NickServ@%s :%s",
+ source_p->name, ConfigFileEntry.service_name, parv[1]);
+ return;
+ }
+
+ sendto_one(source_p, form_str(ERR_SERVICESDOWN),
+ me.name, source_p->name, "NickServ");
+}
+
+static void
+m_chanserv(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *target_p = NULL;
+
+ assert(client_p && source_p);
+ assert(client_p == source_p);
+
+ if (EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NOTEXTTOSEND),
+ me.name, source_p->name);
+ return;
+ }
+
+ if ((target_p = hash_find_server(ConfigFileEntry.service_name)))
+ {
+ sendto_one(target_p, ":%s PRIVMSG ChanServ@%s :%s",
+ source_p->name, ConfigFileEntry.service_name, parv[1]);
+ return;
+ }
+
+ sendto_one(source_p, form_str(ERR_SERVICESDOWN),
+ me.name, source_p->name, "ChanServ");
+}
+
+static void
+m_memoserv(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *target_p = NULL;
+
+ assert(client_p && source_p);
+ assert(client_p == source_p);
+
+ if (EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NOTEXTTOSEND),
+ me.name, source_p->name);
+ return;
+ }
+
+ if ((target_p = hash_find_server(ConfigFileEntry.service_name)))
+ {
+ sendto_one(target_p, ":%s PRIVMSG MemoServ@%s :%s",
+ source_p->name, ConfigFileEntry.service_name, parv[1]);
+ return;
+ }
+
+ sendto_one(source_p, form_str(ERR_SERVICESDOWN),
+ me.name, source_p->name, "MemoServ");
+}
+
+static void
+m_operserv(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *target_p = NULL;
+
+ assert(client_p && source_p);
+ assert(client_p == source_p);
+
+ if (EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NOTEXTTOSEND),
+ me.name, source_p->name);
+ return;
+ }
+
+ if ((target_p = hash_find_server(ConfigFileEntry.service_name)))
+ {
+ sendto_one(target_p, ":%s PRIVMSG OperServ@%s :%s",
+ source_p->name, ConfigFileEntry.service_name, parv[1]);
+ return;
+ }
+
+ sendto_one(source_p, form_str(ERR_SERVICESDOWN),
+ me.name, source_p->name, "OperServ");
+}
+
+static void
+m_statserv(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *target_p = NULL;
+
+ assert(client_p && source_p);
+ assert(client_p == source_p);
+
+ if (EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NOTEXTTOSEND),
+ me.name, source_p->name);
+ return;
+ }
+
+ if ((target_p = hash_find_server(ConfigFileEntry.service_name)))
+ {
+ sendto_one(target_p, ":%s PRIVMSG StatServ@%s :%s",
+ source_p->name, ConfigFileEntry.service_name, parv[1]);
+ return;
+ }
+
+ sendto_one(source_p, form_str(ERR_SERVICESDOWN),
+ me.name, source_p->name, "StatServ");
+}
+
+static void
+m_helpserv(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *target_p = NULL;
+
+ assert(client_p && source_p);
+ assert(client_p == source_p);
+
+ if (EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NOTEXTTOSEND),
+ me.name, source_p->name);
+ return;
+ }
+
+ if ((target_p = hash_find_server(ConfigFileEntry.service_name)))
+ {
+ sendto_one(target_p, ":%s PRIVMSG HelpServ@%s :%s",
+ source_p->name, ConfigFileEntry.service_name, parv[1]);
+ return;
+ }
+
+ sendto_one(source_p, form_str(ERR_SERVICESDOWN),
+ me.name, source_p->name, "HelpServ");
+}
+
+static void
+m_botserv(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *target_p = NULL;
+
+ assert(client_p && source_p);
+ assert(client_p == source_p);
+
+ if (EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NOTEXTTOSEND),
+ me.name, source_p->name);
+ return;
+ }
+
+ if ((target_p = hash_find_server(ConfigFileEntry.service_name)))
+ {
+ sendto_one(target_p, ":%s PRIVMSG BotServ@%s :%s",
+ source_p->name, ConfigFileEntry.service_name, parv[1]);
+ return;
+ }
+
+ sendto_one(source_p, form_str(ERR_SERVICESDOWN),
+ me.name, source_p->name, "BotServ");
+}
+
+
+static struct Message ms_msgtab = {
+ "MS", 0, 0, 0, 1, MFLG_SLOW, 0,
+ {m_unregistered, m_memoserv, m_ignore, m_ignore, m_memoserv, m_ignore}
+};
+
+static struct Message ns_msgtab = {
+ "NS", 0, 0, 0, 1, MFLG_SLOW, 0,
+ {m_unregistered, m_nickserv, m_ignore, m_ignore, m_nickserv, m_ignore}
+};
+
+static struct Message os_msgtab = {
+ "OS", 0, 0, 0, 1, MFLG_SLOW, 0,
+ {m_unregistered, m_operserv, m_ignore, m_ignore, m_operserv, m_ignore}
+};
+
+static struct Message bs_msgtab = {
+ "BS", 0, 0, 0, 1, MFLG_SLOW, 0,
+ {m_unregistered, m_botserv, m_ignore, m_ignore, m_botserv, m_ignore}
+};
+
+static struct Message cs_msgtab = {
+ "CS", 0, 0, 0, 1, MFLG_SLOW, 0,
+ {m_unregistered, m_chanserv, m_ignore, m_ignore, m_chanserv, m_ignore}
+};
+
+static struct Message ss_msgtab = {
+ "SS", 0, 0, 0, 1, MFLG_SLOW, 0,
+ {m_unregistered, m_statserv, m_ignore, m_ignore, m_statserv, m_ignore}
+};
+
+static struct Message hs_msgtab = {
+ "HS", 0, 0, 0, 1, MFLG_SLOW, 0,
+ {m_unregistered, m_helpserv, m_ignore, m_ignore, m_helpserv, m_ignore}
+};
+
+static struct Message botserv_msgtab = {
+ "BOTSERV", 0, 0, 0, 1, MFLG_SLOW, 0,
+ {m_unregistered, m_botserv, m_ignore, m_ignore, m_botserv, m_ignore}
+};
+
+static struct Message chanserv_msgtab = {
+ "CHANSERV", 0, 0, 0, 1, MFLG_SLOW, 0,
+ {m_unregistered, m_chanserv, m_ignore, m_ignore, m_chanserv, m_ignore}
+};
+
+static struct Message memoserv_msgtab = {
+ "MEMOSERV", 0, 0, 0, 1, MFLG_SLOW, 0,
+ {m_unregistered, m_memoserv, m_ignore, m_ignore, m_memoserv, m_ignore}
+};
+
+static struct Message nickserv_msgtab = {
+ "NICKSERV", 0, 0, 0, 1, MFLG_SLOW, 0,
+ {m_unregistered, m_nickserv, m_ignore, m_ignore, m_nickserv, m_ignore}
+};
+
+static struct Message operserv_msgtab = {
+ "OPERSERV", 0, 0, 0, 1, MFLG_SLOW, 0,
+ {m_unregistered, m_operserv, m_ignore, m_ignore, m_operserv, m_ignore}
+};
+
+static struct Message statserv_msgtab = {
+ "STATSERV", 0, 0, 0, 1, MFLG_SLOW, 0,
+ {m_unregistered, m_statserv, m_ignore, m_ignore, m_statserv, m_ignore}
+};
+
+static struct Message helpserv_msgtab = {
+ "HELPSERV", 0, 0, 0, 1, MFLG_SLOW, 0,
+ {m_unregistered, m_helpserv, m_ignore, m_ignore, m_helpserv, m_ignore}
+};
+
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&botserv_msgtab);
+ mod_add_cmd(&chanserv_msgtab);
+ mod_add_cmd(&memoserv_msgtab);
+ mod_add_cmd(&nickserv_msgtab);
+ mod_add_cmd(&operserv_msgtab);
+ mod_add_cmd(&statserv_msgtab);
+ mod_add_cmd(&helpserv_msgtab);
+ mod_add_cmd(&bs_msgtab);
+ mod_add_cmd(&ns_msgtab);
+ mod_add_cmd(&cs_msgtab);
+ mod_add_cmd(&ms_msgtab);
+ mod_add_cmd(&os_msgtab);
+ mod_add_cmd(&ss_msgtab);
+ mod_add_cmd(&hs_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&botserv_msgtab);
+ mod_del_cmd(&chanserv_msgtab);
+ mod_del_cmd(&memoserv_msgtab);
+ mod_del_cmd(&nickserv_msgtab);
+ mod_del_cmd(&operserv_msgtab);
+ mod_del_cmd(&statserv_msgtab);
+ mod_del_cmd(&helpserv_msgtab);
+ mod_del_cmd(&bs_msgtab);
+ mod_del_cmd(&ns_msgtab);
+ mod_del_cmd(&cs_msgtab);
+ mod_del_cmd(&ms_msgtab);
+ mod_del_cmd(&os_msgtab);
+ mod_del_cmd(&ss_msgtab);
+ mod_del_cmd(&hs_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_set.c b/modules/m_set.c
new file mode 100644
index 0000000..f17b4a6
--- /dev/null
+++ b/modules/m_set.c
@@ -0,0 +1,616 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_set.c: Sets a server parameter.
+ *
+ * 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$
+ */
+
+/* rewritten by jdc */
+
+#include "stdinc.h"
+#include "client.h"
+#include "event.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "fdlist.h"
+#include "s_bsd.h"
+#include "s_serv.h"
+#include "send.h"
+#include "channel.h"
+#include "conf.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_user.h"
+#include "s_misc.h"
+
+
+/* Structure used for the SET table itself */
+struct SetStruct
+{
+ const char *name;
+ void (*handler)();
+ const int wants_char; /* 1 if it expects (char *, [int]) */
+ const int wants_int; /* 1 if it expects ([char *], int) */
+ /* eg: 0, 1 == only an int arg
+ * eg: 1, 1 == char and int args */
+};
+
+static void quote_autoconn(struct Client *, const char *, int);
+static void quote_autoconnall(struct Client *, int);
+static void quote_floodcount(struct Client *, int);
+static void quote_identtimeout(struct Client *, int);
+static void quote_max(struct Client *, int);
+static void quote_msglocale(struct Client *, char *);
+static void quote_spamnum(struct Client *, int);
+static void quote_spamtime(struct Client *, int);
+static void quote_splitmode(struct Client *, char *);
+static void quote_splitnum(struct Client *, int);
+static void quote_splitusers(struct Client *, int);
+static void list_quote_commands(struct Client *);
+static void quote_jfloodtime(struct Client *, int);
+static void quote_jfloodcount(struct Client *, int);
+
+/*
+ * If this ever needs to be expanded to more than one arg of each
+ * type, want_char/want_int could be the count of the arguments,
+ * instead of just a boolean flag...
+ *
+ * -davidt
+ */
+
+static const struct SetStruct set_cmd_table[] =
+{
+ /* name function string arg int arg */
+ /* -------------------------------------------------------- */
+ { "AUTOCONN", quote_autoconn, 1, 1 },
+ { "AUTOCONNALL", quote_autoconnall, 0, 1 },
+ { "FLOODCOUNT", quote_floodcount, 0, 1 },
+ { "IDENTTIMEOUT", quote_identtimeout, 0, 1 },
+ { "MAX", quote_max, 0, 1 },
+ { "MSGLOCALE", quote_msglocale, 1, 0 },
+ { "SPAMNUM", quote_spamnum, 0, 1 },
+ { "SPAMTIME", quote_spamtime, 0, 1 },
+ { "SPLITMODE", quote_splitmode, 1, 0 },
+ { "SPLITNUM", quote_splitnum, 0, 1 },
+ { "SPLITUSERS", quote_splitusers, 0, 1 },
+ { "JFLOODTIME", quote_jfloodtime, 0, 1 },
+ { "JFLOODCOUNT", quote_jfloodcount, 0, 1 },
+ /* -------------------------------------------------------- */
+ { NULL, NULL, 0, 0 }
+};
+
+/*
+ * list_quote_commands() sends the client all the available commands.
+ * Four to a line for now.
+ */
+static void
+list_quote_commands(struct Client *source_p)
+{
+ int j = 0;
+ const struct SetStruct *tab = set_cmd_table;
+ const char *names[4] = { "", "", "", "" };
+
+ sendto_one(source_p, ":%s NOTICE %s :Available QUOTE SET commands:",
+ me.name, source_p->name);
+
+ for (; tab->handler; ++tab)
+ {
+ names[j++] = tab->name;
+
+ if (j > 3)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :%s %s %s %s",
+ me.name, source_p->name,
+ names[0], names[1],
+ names[2], names[3]);
+ j = 0;
+ names[0] = names[1] = names[2] = names[3] = "";
+ }
+
+ }
+
+ if (j)
+ sendto_one(source_p, ":%s NOTICE %s :%s %s %s %s",
+ me.name, source_p->name,
+ names[0], names[1],
+ names[2], names[3]);
+}
+
+/* SET AUTOCONN */
+static void
+quote_autoconn(struct Client *source_p, const char *arg, int newval)
+{
+ struct AccessItem *aconf;
+
+ if (arg != NULL)
+ {
+ struct ConfItem *conf = find_exact_name_conf(SERVER_TYPE, NULL, arg, NULL, NULL);
+
+ if (conf != NULL)
+ {
+ aconf = map_to_conf(conf);
+ if (newval)
+ SetConfAllowAutoConn(aconf);
+ else
+ ClearConfAllowAutoConn(aconf);
+
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s has changed AUTOCONN for %s to %i",
+ get_oper_name(source_p), arg, newval);
+ sendto_one(source_p,
+ ":%s NOTICE %s :AUTOCONN for %s is now set to %i",
+ me.name, source_p->name, arg, newval);
+ }
+ else
+ {
+ sendto_one(source_p, ":%s NOTICE %s :Can't find %s",
+ me.name, source_p->name, arg);
+ }
+ }
+ else
+ {
+ sendto_one(source_p, ":%s NOTICE %s :Please specify a server name!",
+ me.name, source_p->name);
+ }
+}
+
+/* SET AUTOCONNALL */
+static void
+quote_autoconnall(struct Client *source_p, int newval)
+{
+ if (newval >= 0)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL, "%s has changed AUTOCONNALL to %i",
+ get_oper_name(source_p), newval);
+
+ GlobalSetOptions.autoconn = newval;
+ }
+ else
+ sendto_one(source_p, ":%s NOTICE %s :AUTOCONNALL is currently %i",
+ me.name, source_p->name, GlobalSetOptions.autoconn);
+}
+
+/* SET FLOODCOUNT */
+static void
+quote_floodcount(struct Client *source_p, int newval)
+{
+ if (newval >= 0)
+ {
+ GlobalSetOptions.floodcount = newval;
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s has changed FLOODCOUNT to %i",
+ get_oper_name(source_p), GlobalSetOptions.floodcount);
+ }
+ else
+ sendto_one(source_p, ":%s NOTICE %s :FLOODCOUNT is currently %i",
+ me.name, source_p->name, GlobalSetOptions.floodcount);
+}
+
+/* SET IDENTTIMEOUT */
+static void
+quote_identtimeout(struct Client *source_p, int newval)
+{
+ if (!HasUMode(source_p, UMODE_ADMIN))
+ {
+ sendto_one(source_p, form_str(ERR_NOPRIVS),
+ me.name, source_p->name, "set");
+ return;
+ }
+
+ if (newval > 0)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s has changed IDENTTIMEOUT to %d",
+ get_oper_name(source_p), newval);
+ GlobalSetOptions.ident_timeout = newval;
+ }
+ else
+ sendto_one(source_p, ":%s NOTICE %s :IDENTTIMEOUT is currently %d",
+ me.name, source_p->name, GlobalSetOptions.ident_timeout);
+}
+
+/* SET MAX */
+static void
+quote_max(struct Client *source_p, int newval)
+{
+ if (newval > 0)
+ {
+ recalc_fdlimit(NULL);
+
+ if (newval > MAXCLIENTS_MAX)
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :You cannot set MAXCLIENTS to > %d, restoring to %d",
+ me.name, source_p->name, MAXCLIENTS_MAX, ServerInfo.max_clients);
+ return;
+ }
+
+ if (newval < MAXCLIENTS_MIN)
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :You cannot set MAXCLIENTS to < %d, restoring to %d",
+ me.name, source_p->name, MAXCLIENTS_MIN, ServerInfo.max_clients);
+ return;
+ }
+
+ ServerInfo.max_clients = newval;
+
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s set new MAXCLIENTS to %d (%d current)",
+ get_oper_name(source_p), ServerInfo.max_clients, Count.local);
+ }
+ else
+ sendto_one(source_p, ":%s NOTICE %s :Current MAXCLIENTS = %d (%d)",
+ me.name, source_p->name, ServerInfo.max_clients, Count.local);
+}
+
+/* SET MSGLOCALE */
+static void
+quote_msglocale(struct Client *source_p, char *locale)
+{
+ if (locale != NULL)
+ {
+ set_locale(locale);
+ rebuild_isupport_message_line();
+ sendto_one(source_p, ":%s NOTICE %s :Set MSGLOCALE to '%s'",
+ me.name, source_p->name, get_locale());
+ }
+ else
+ sendto_one(source_p, ":%s NOTICE %s :MSGLOCALE is currently '%s'",
+ me.name, source_p->name, get_locale());
+}
+
+/* SET SPAMNUM */
+static void
+quote_spamnum(struct Client *source_p, int newval)
+{
+ if (newval >= 0)
+ {
+ if (newval == 0)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s has disabled ANTI_SPAMBOT", source_p->name);
+ GlobalSetOptions.spam_num = newval;
+ return;
+ }
+
+ GlobalSetOptions.spam_num = IRCD_MAX(newval, MIN_SPAM_NUM);
+ sendto_realops_flags(UMODE_ALL, L_ALL, "%s has changed SPAMNUM to %i",
+ get_oper_name(source_p), GlobalSetOptions.spam_num);
+ }
+ else
+ sendto_one(source_p, ":%s NOTICE %s :SPAMNUM is currently %i",
+ me.name, source_p->name, GlobalSetOptions.spam_num);
+}
+
+/* SET SPAMTIME */
+static void
+quote_spamtime(struct Client *source_p, int newval)
+{
+ if (newval > 0)
+ {
+ GlobalSetOptions.spam_time = IRCD_MAX(newval, MIN_SPAM_TIME);
+ sendto_realops_flags(UMODE_ALL, L_ALL, "%s has changed SPAMTIME to %i",
+ get_oper_name(source_p), GlobalSetOptions.spam_time);
+ }
+ else
+ sendto_one(source_p, ":%s NOTICE %s :SPAMTIME is currently %i",
+ me.name, source_p->name, GlobalSetOptions.spam_time);
+}
+
+/* this table is what splitmode may be set to */
+static const char *splitmode_values[] =
+{
+ "OFF",
+ "ON",
+ "AUTO",
+ NULL
+};
+
+/* this table is what splitmode may be */
+static const char *splitmode_status[] =
+{
+ "OFF",
+ "AUTO (OFF)",
+ "ON",
+ "AUTO (ON)",
+ NULL
+};
+
+/* SET SPLITMODE */
+static void
+quote_splitmode(struct Client *source_p, char *charval)
+{
+ if (charval)
+ {
+ int newval;
+
+ for (newval = 0; splitmode_values[newval]; ++newval)
+ if (irccmp(splitmode_values[newval], charval) == 0)
+ break;
+
+ /* OFF */
+ if (newval == 0)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s is disabling splitmode",
+ get_oper_name(source_p));
+
+ splitmode = 0;
+ splitchecking = 0;
+
+ eventDelete(check_splitmode, NULL);
+ }
+ /* ON */
+ else if (newval == 1)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s is enabling and activating splitmode",
+ get_oper_name(source_p));
+
+ splitmode = 1;
+ splitchecking = 0;
+
+ /* we might be deactivating an automatic splitmode, so pull the event */
+ eventDelete(check_splitmode, NULL);
+ }
+ /* AUTO */
+ else if (newval == 2)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s is enabling automatic splitmode",
+ get_oper_name(source_p));
+
+ splitchecking = 1;
+ check_splitmode(NULL);
+ }
+ }
+ else
+ /* if we add splitchecking to splitmode*2 we get a unique table to
+ * pull values back out of, splitmode can be four states - but you can
+ * only set to three, which means we cant use the same table --fl_
+ */
+ sendto_one(source_p, ":%s NOTICE %s :SPLITMODE is currently %s",
+ me.name, source_p->name,
+ splitmode_status[(splitchecking + (splitmode * 2))]);
+}
+
+/* SET SPLITNUM */
+static void
+quote_splitnum(struct Client *source_p, int newval)
+{
+ if (newval >= 0)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s has changed SPLITNUM to %i",
+ get_oper_name(source_p), newval);
+ split_servers = newval;
+
+ if (splitchecking)
+ check_splitmode(NULL);
+ }
+ else
+ sendto_one(source_p, ":%s NOTICE %s :SPLITNUM is currently %i",
+ me.name, source_p->name, split_servers);
+}
+
+/* SET SPLITUSERS */
+static void
+quote_splitusers(struct Client *source_p, int newval)
+{
+ if (newval >= 0)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s has changed SPLITUSERS to %i",
+ get_oper_name(source_p), newval);
+ split_users = newval;
+
+ if (splitchecking)
+ check_splitmode(NULL);
+ }
+ else
+ sendto_one(source_p, ":%s NOTICE %s :SPLITUSERS is currently %i",
+ me.name, source_p->name, split_users);
+}
+
+/* SET JFLOODTIME */
+static void
+quote_jfloodtime(struct Client *source_p, int newval)
+{
+ if (newval >= 0)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s has changed JFLOODTIME to %i",
+ get_oper_name(source_p), newval);
+ GlobalSetOptions.joinfloodtime = newval;
+ }
+ else
+ sendto_one(source_p, ":%s NOTICE %s :JFLOODTIME is currently %i",
+ me.name, source_p->name, GlobalSetOptions.joinfloodtime);
+}
+
+/* SET JFLOODCOUNT */
+static void
+quote_jfloodcount(struct Client *source_p, int newval)
+{
+ if (newval >= 0)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s has changed JFLOODCOUNT to %i",
+ get_oper_name(source_p), newval);
+ GlobalSetOptions.joinfloodcount = newval;
+ }
+ else
+ sendto_one(source_p, ":%s NOTICE %s :JFLOODCOUNT is currently %i",
+ me.name, source_p->name, GlobalSetOptions.joinfloodcount);
+}
+
+/*
+ * mo_set - SET command handler
+ * set options while running
+ */
+static void
+mo_set(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ int n;
+ int newval;
+ const char *arg = NULL;
+ const char *intarg = NULL;
+ const struct SetStruct *tab = set_cmd_table;
+
+ if (!HasOFlag(source_p, OPER_FLAG_SET))
+ {
+ sendto_one(source_p, form_str(ERR_NOPRIVS),
+ me.name, source_p->name, "set");
+ return;
+ }
+
+ if (parc > 1)
+ {
+ /*
+ * Go through all the commands in set_cmd_table, until one is
+ * matched.
+ */
+ for (; tab->handler; ++tab)
+ {
+ if (!irccmp(tab->name, parv[1]))
+ {
+ /*
+ * Command found; now execute the code
+ */
+ n = 2;
+
+ if (tab->wants_char)
+ arg = parv[n++];
+
+ if (tab->wants_int)
+ intarg = parv[n++];
+
+ if ((n - 1) > parc)
+ {
+ if (parc > 2)
+ sendto_one(source_p,
+ ":%s NOTICE %s :SET %s expects (\"%s%s\") args",
+ me.name, source_p->name, tab->name,
+ (tab->wants_char ? "string, " : ""),
+ (tab->wants_char ? "int" : ""));
+ }
+
+ if (parc <= 2)
+ {
+ arg = NULL;
+ intarg = NULL;
+ }
+
+ if (!strcmp(tab->name, "AUTOCONN") && (parc < 4))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, "SET");
+ return;
+ }
+
+ if (tab->wants_int && (parc > 2))
+ {
+ if (intarg)
+ {
+ if (irccmp(intarg, "yes") == 0 || irccmp(intarg, "on") == 0)
+ newval = 1;
+ else if (irccmp(intarg, "no") == 0|| irccmp(intarg, "off") == 0)
+ newval = 0;
+ else
+ newval = atoi(intarg);
+ }
+ else
+ newval = -1;
+
+ if (newval < 0)
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :Value less than 0 illegal for %s",
+ me.name, source_p->name,
+ tab->name);
+
+ return;
+ }
+ }
+ else
+ newval = -1;
+
+ if (tab->wants_char)
+ {
+ if (tab->wants_int)
+ tab->handler(source_p, arg, newval);
+ else
+ tab->handler(source_p, arg);
+ return;
+ }
+ else
+ {
+ if (tab->wants_int)
+ tab->handler(source_p, newval);
+ else
+ /* Just in case someone actually wants a
+ * set function that takes no args.. *shrug* */
+ tab->handler(source_p);
+ return;
+ }
+ }
+ }
+
+ /*
+ * Code here will be executed when a /QUOTE SET command is not
+ * found within set_cmd_table.
+ */
+ sendto_one(source_p, ":%s NOTICE %s :Variable not found.",
+ me.name, source_p->name);
+ return;
+ }
+
+ list_quote_commands(source_p);
+}
+
+static struct Message set_msgtab = {
+ "SET", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_not_oper, rfc1459_command_send_error, m_ignore, mo_set, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&set_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&set_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_stats.c b/modules/m_stats.c
new file mode 100644
index 0000000..2361688
--- /dev/null
+++ b/modules/m_stats.c
@@ -0,0 +1,1533 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_stats.c: Sends the user statistics or config information.
+ *
+ * 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" /* dlink_node/dlink_list */
+#include "balloc.h"
+#include "client.h" /* Client */
+#include "irc_string.h"
+#include "ircd.h" /* me */
+#include "listener.h" /* show_ports */
+#include "s_gline.h"
+#include "hostmask.h"
+#include "numeric.h" /* ERR_xxx */
+#include "send.h" /* sendto_one */
+#include "fdlist.h" /* PF and friends */
+#include "s_bsd.h" /* highest_fd */
+#include "conf.h" /* AccessItem, report_configured_links */
+#include "s_misc.h" /* serv_info */
+#include "s_serv.h" /* hunt_server */
+#include "s_user.h" /* show_opers */
+#include "event.h" /* events */
+#include "dbuf.h"
+#include "hook.h"
+#include "parse.h"
+#include "modules.h"
+#include "resv.h" /* report_resv */
+#include "whowas.h"
+#include "watch.h"
+#include "irc_res.h"
+
+
+const char *from, *to;
+
+/*
+ * This is part of the STATS replies. There is no offical numeric for this
+ * since this isnt an official command, in much the same way as HASH isnt.
+ * It is also possible that some systems wont support this call or have
+ * different field names for "struct rusage".
+ * -avalon
+ */
+static void
+stats_usage(struct Client *source_p, int parc, char *parv[])
+{
+ struct rusage rus;
+ time_t secs;
+ time_t rup;
+#ifdef hz
+# define hzz hz
+#else
+# ifdef HZ
+# define hzz HZ
+# else
+ int hzz = 1;
+# endif
+#endif
+
+ if (getrusage(RUSAGE_SELF, &rus) == -1)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :Getruseage error: %s",
+ me.name, source_p->name, strerror(errno));
+ return;
+ }
+
+ secs = rus.ru_utime.tv_sec + rus.ru_stime.tv_sec;
+
+ if (secs == 0)
+ secs = 1;
+
+ rup = (CurrentTime - me.localClient->since) * hzz;
+
+ if (rup == 0)
+ rup = 1;
+
+ sendto_one(source_p,
+ ":%s %d %s R :CPU Secs %d:%d User %d:%d System %d:%d",
+ me.name, RPL_STATSDEBUG, source_p->name, (int)(secs/60), (int)(secs%60),
+ (int)(rus.ru_utime.tv_sec/60), (int)(rus.ru_utime.tv_sec%60),
+ (int)(rus.ru_stime.tv_sec/60), (int)(rus.ru_stime.tv_sec%60));
+ sendto_one(source_p, ":%s %d %s R :RSS %ld ShMem %ld Data %ld Stack %ld",
+ me.name, RPL_STATSDEBUG, source_p->name, rus.ru_maxrss,
+ (rus.ru_ixrss / rup), (rus.ru_idrss / rup),
+ (rus.ru_isrss / rup));
+ sendto_one(source_p, ":%s %d %s R :Swaps %d Reclaims %d Faults %d",
+ me.name, RPL_STATSDEBUG, source_p->name, (int)rus.ru_nswap,
+ (int)rus.ru_minflt, (int)rus.ru_majflt);
+ sendto_one(source_p, ":%s %d %s R :Block in %d out %d",
+ me.name, RPL_STATSDEBUG, source_p->name, (int)rus.ru_inblock,
+ (int)rus.ru_oublock);
+ sendto_one(source_p, ":%s %d %s R :Msg Rcv %d Send %d",
+ me.name, RPL_STATSDEBUG, source_p->name, (int)rus.ru_msgrcv,
+ (int)rus.ru_msgsnd);
+ sendto_one(source_p, ":%s %d %s R :Signals %d Context Vol. %d Invol %d",
+ me.name, RPL_STATSDEBUG, source_p->name, (int)rus.ru_nsignals,
+ (int)rus.ru_nvcsw, (int)rus.ru_nivcsw);
+}
+
+static void
+stats_memory(struct Client *source_p, int parc, char *parv[])
+{
+ const dlink_node *gptr = NULL;
+ const dlink_node *dlink = NULL;
+
+ unsigned int local_client_conf_count = 0; /* local client conf links */
+ unsigned int users_counted = 0; /* user structs */
+
+ unsigned int channel_members = 0;
+ unsigned int channel_invites = 0;
+ unsigned int channel_bans = 0;
+ unsigned int channel_except = 0;
+ unsigned int channel_invex = 0;
+
+ unsigned int wwu = 0; /* whowas users */
+ unsigned int class_count = 0; /* classes */
+ unsigned int aways_counted = 0;
+ unsigned int number_ips_stored; /* number of ip addresses hashed */
+
+ uint64_t channel_memory = 0;
+ uint64_t channel_ban_memory = 0;
+ uint64_t channel_except_memory = 0;
+ uint64_t channel_invex_memory = 0;
+
+ unsigned int safelist_count = 0;
+ uint64_t safelist_memory = 0;
+
+ uint64_t wwm = 0; /* whowas array memory used */
+ uint64_t conf_memory = 0; /* memory used by conf lines */
+ uint64_t mem_ips_stored; /* memory used by ip address hash */
+
+ uint64_t total_channel_memory = 0;
+ uint64_t totww = 0;
+
+ unsigned int local_client_count = 0;
+ unsigned int remote_client_count = 0;
+
+ uint64_t local_client_memory_used = 0;
+ uint64_t remote_client_memory_used = 0;
+
+ uint64_t total_memory = 0;
+ unsigned int topic_count = 0;
+
+ unsigned int watch_list_headers = 0; /* watchlist headers */
+ unsigned int watch_list_entries = 0; /* watchlist entries */
+ uint64_t watch_list_memory = 0; /* watchlist memory used */
+
+
+ DLINK_FOREACH(gptr, global_client_list.head)
+ {
+ struct Client *target_p = gptr->data;
+
+ if (MyConnect(target_p))
+ {
+ ++local_client_count;
+ local_client_conf_count += dlink_list_length(&target_p->localClient->confs);
+ watch_list_entries += dlink_list_length(&target_p->localClient->watches);
+ }
+ else
+ ++remote_client_count;
+
+ if (IsClient(target_p))
+ {
+ ++users_counted;
+
+ if (target_p->away[0])
+ ++aways_counted;
+ }
+ }
+
+ /* Count up all channels, ban lists, except lists, Invex lists */
+ channel_memory = dlink_list_length(&global_channel_list) *
+ sizeof(struct Channel);
+ DLINK_FOREACH(gptr, global_channel_list.head)
+ {
+ const struct Ban *actualBan;
+ const struct Channel *chptr = gptr->data;
+
+ channel_members += dlink_list_length(&chptr->members);
+ channel_invites += dlink_list_length(&chptr->invites);
+
+ if (chptr->topic[0])
+ ++topic_count;
+
+ channel_bans += dlink_list_length(&chptr->banlist);
+ channel_ban_memory += dlink_list_length(&chptr->banlist) * sizeof(struct Ban);
+
+ DLINK_FOREACH(dlink, chptr->banlist.head)
+ {
+ actualBan = dlink->data;
+ assert(actualBan->who);
+
+ channel_ban_memory += actualBan->len + 1;
+ channel_ban_memory += strlen(actualBan->who) + 1;
+ }
+
+ channel_except += dlink_list_length(&chptr->exceptlist);
+ channel_except_memory += dlink_list_length(&chptr->exceptlist) * sizeof(struct Ban);
+
+ DLINK_FOREACH(dlink, chptr->exceptlist.head)
+ {
+ actualBan = dlink->data;
+ assert(actualBan->who);
+
+ channel_except_memory += actualBan->len + 1;
+ channel_except_memory += strlen(actualBan->who) + 1;
+ }
+
+ channel_invex += dlink_list_length(&chptr->invexlist);
+ channel_invex_memory += dlink_list_length(&chptr->invexlist) * sizeof(struct Ban);
+
+ DLINK_FOREACH(dlink, chptr->invexlist.head)
+ {
+ actualBan = dlink->data;
+ assert(actualBan->who);
+
+ channel_invex_memory += actualBan->len + 1;
+ channel_invex_memory += strlen(actualBan->who) + 1;
+ }
+ }
+
+ if ((safelist_count = dlink_list_length(&listing_client_list)))
+ {
+ safelist_memory = safelist_count * sizeof(struct ListTask);
+ DLINK_FOREACH(gptr, listing_client_list.head)
+ {
+ const struct Client *acptr = gptr->data;
+
+ DLINK_FOREACH(dlink, acptr->localClient->list_task->show_mask.head)
+ safelist_memory += strlen(dlink->data);
+
+ DLINK_FOREACH(dlink, acptr->localClient->list_task->hide_mask.head)
+ safelist_memory += strlen(dlink->data);
+ }
+ }
+
+#if 0
+ /* XXX THIS has to be fixed !!!! -db */
+ /* count up all config items */
+ DLINK_FOREACH(dlink, ConfigItemList.head)
+ {
+ aconf = dlink->data;
+ conf_memory += aconf->host ? strlen(aconf->host)+1 : 0;
+ conf_memory += aconf->passwd ? strlen(aconf->passwd)+1 : 0;
+ conf_memory += aconf->name ? strlen(aconf->name)+1 : 0;
+ conf_memory += sizeof(struct AccessItem);
+ }
+#endif
+ /* count up all classes */
+ class_count = dlink_list_length(&class_items);
+
+ count_whowas_memory(&wwu, &wwm);
+ watch_count_memory(&watch_list_headers, &watch_list_memory);
+
+ sendto_one(source_p, ":%s %d %s z :WATCH headers %u(%u) entries %d(%u)",
+ me.name, RPL_STATSDEBUG, source_p->name, watch_list_headers,
+ watch_list_memory, watch_list_entries,
+ watch_list_entries * sizeof(dlink_node) * 2);
+
+ sendto_one(source_p, ":%s %d %s z :Clients %u(%u)",
+ me.name, RPL_STATSDEBUG, source_p->name, users_counted,
+ (users_counted * sizeof(struct Client)));
+
+ sendto_one(source_p, ":%s %d %s z :User aways %u",
+ me.name, RPL_STATSDEBUG, source_p->name,
+ aways_counted);
+
+ sendto_one(source_p, ":%s %d %s z :Attached confs %u(%llu)",
+ me.name, RPL_STATSDEBUG, source_p->name,
+ local_client_conf_count,
+ (unsigned long long)(local_client_conf_count * sizeof(dlink_node)));
+
+ sendto_one(source_p, ":%s %d %s z :Resv channels %u(%lu) nicks %u(%lu)",
+ me.name, RPL_STATSDEBUG, source_p->name,
+ dlink_list_length(&resv_channel_list),
+ dlink_list_length(&resv_channel_list) * sizeof(struct ResvChannel),
+ dlink_list_length(&nresv_items),
+ dlink_list_length(&nresv_items) * sizeof(struct MatchItem));
+
+ sendto_one(source_p, ":%s %d %s z :Classes %u(%llu)",
+ me.name, RPL_STATSDEBUG, source_p->name,
+ class_count, (unsigned long long)(class_count * sizeof(struct ClassItem)));
+
+ sendto_one(source_p, ":%s %d %s z :Channels %uu(%llu) Topics %u(%u)",
+ me.name, RPL_STATSDEBUG, source_p->name,
+ dlink_list_length(&global_channel_list),
+ channel_memory, topic_count, topic_count *
+ (TOPICLEN + 1 + USERHOST_REPLYLEN));
+
+ sendto_one(source_p, ":%s %d %s z :Bans %u(%llu)",
+ me.name, RPL_STATSDEBUG, source_p->name,
+ channel_bans, channel_ban_memory);
+
+ sendto_one(source_p, ":%s %d %s z :Exceptions %u(%llu)",
+ me.name, RPL_STATSDEBUG, source_p->name,
+ channel_except, channel_except_memory);
+
+ sendto_one(source_p, ":%s %d %s z :Invex %u(%llu)",
+ me.name, RPL_STATSDEBUG, source_p->name,
+ channel_invex, channel_invex_memory);
+
+ sendto_one(source_p, ":%s %d %s z :Channel members %u(%llu) invites %u(%llu)",
+ me.name, RPL_STATSDEBUG, source_p->name, channel_members,
+ (unsigned long long)(channel_members * sizeof(struct Membership)),
+ channel_invites, (unsigned long long)channel_invites *
+ sizeof(dlink_node) * 2);
+
+ total_channel_memory = channel_memory + channel_ban_memory +
+ channel_members * sizeof(struct Membership) +
+ (channel_invites * sizeof(dlink_node)*2);
+
+ sendto_one(source_p, ":%s %d %s z :Safelist %u(%llu)",
+ me.name, RPL_STATSDEBUG, source_p->name,
+ safelist_count, safelist_memory);
+
+ sendto_one(source_p, ":%s %d %s z :Whowas users %u(%llu)",
+ me.name, RPL_STATSDEBUG, source_p->name,
+ wwu, (unsigned long long)(wwu * sizeof(struct Client)));
+
+ sendto_one(source_p, ":%s %d %s z :Whowas array %u(%llu)",
+ me.name, RPL_STATSDEBUG, source_p->name,
+ NICKNAMEHISTORYLENGTH, wwm);
+
+ totww = wwu * sizeof(struct Client) + wwm;
+
+ count_ip_hash(&number_ips_stored,&mem_ips_stored);
+ sendto_one(source_p, ":%s %d %s z :iphash %u(%llu)",
+ me.name, RPL_STATSDEBUG, source_p->name,
+ number_ips_stored, mem_ips_stored);
+
+ total_memory = totww + total_channel_memory + conf_memory + class_count *
+ sizeof(struct ClassItem);
+ sendto_one(source_p, ":%s %d %s z :Total: whowas %llu channel %llu conf %llu",
+ me.name, RPL_STATSDEBUG, source_p->name, totww,
+ total_channel_memory, conf_memory);
+
+ local_client_memory_used = local_client_count*(sizeof(struct Client) + sizeof(struct LocalUser));
+ total_memory += local_client_memory_used;
+ sendto_one(source_p, ":%s %d %s z :Local client Memory in use: %u(%llu)",
+ me.name, RPL_STATSDEBUG, source_p->name, local_client_count,
+ local_client_memory_used);
+
+ remote_client_memory_used = remote_client_count * sizeof(struct Client);
+ total_memory += remote_client_memory_used;
+ sendto_one(source_p, ":%s %d %s z :Remote client Memory in use: %u(%llu)",
+ me.name, RPL_STATSDEBUG, source_p->name, remote_client_count,
+ remote_client_memory_used);
+
+ block_heap_report_stats(source_p);
+
+ sendto_one(source_p,
+ ":%s %d %s z :TOTAL: %llu",
+ me.name, RPL_STATSDEBUG, source_p->name,
+ total_memory);
+}
+
+static void
+stats_dns_servers(struct Client *source_p)
+{
+ report_dns_servers(source_p);
+}
+
+static void
+stats_connect(struct Client *source_p, int parc, char *parv[])
+{
+ report_confitem_types(source_p, SERVER_TYPE);
+}
+
+/* stats_deny()
+ *
+ * input - client to report to
+ * output - none
+ * side effects - client is given dline list.
+ */
+static void
+stats_deny(struct Client *source_p, int parc, char *parv[])
+{
+ struct ConfItem *conf;
+ struct AccessItem *aconf;
+ dlink_node *ptr = NULL;
+ unsigned int i = 0;
+
+
+ for (i = 0; i < ATABLE_SIZE; ++i)
+ {
+ DLINK_FOREACH(ptr, atable[i].head)
+ {
+ struct AddressRec *arec = ptr->data;
+
+ if (arec->type == CONF_DLINE)
+ {
+ aconf = arec->aconf;
+
+ /* dont report a tdline as a dline */
+ if (aconf->flags & CONF_FLAGS_TEMPORARY)
+ continue;
+
+ conf = unmap_conf_item(aconf);
+
+ sendto_one(source_p, form_str(RPL_STATSDLINE),
+ from, to, 'D', aconf->host, aconf->reason,
+ aconf->oper_reason ? aconf->oper_reason : "");
+ }
+ }
+ }
+}
+
+/* stats_tdeny()
+ *
+ * input - client to report to
+ * output - none
+ * side effects - client is given dline list.
+ */
+static void
+stats_tdeny(struct Client *source_p, int parc, char *parv[])
+{
+ struct ConfItem *conf;
+ struct AccessItem *aconf;
+ dlink_node *ptr = NULL;
+ unsigned int i = 0;
+
+
+ for (i = 0; i < ATABLE_SIZE; ++i)
+ {
+ DLINK_FOREACH(ptr, atable[i].head)
+ {
+ struct AddressRec *arec = ptr->data;
+
+ if (arec->type == CONF_DLINE)
+ {
+ aconf = arec->aconf;
+
+ /* dont report a permanent dline as a tdline */
+ if (!(aconf->flags & CONF_FLAGS_TEMPORARY))
+ continue;
+
+ conf = unmap_conf_item(aconf);
+
+ sendto_one(source_p, form_str(RPL_STATSDLINE),
+ from, to, 'd', aconf->host, aconf->reason,
+ aconf->oper_reason ? aconf->oper_reason : "");
+ }
+ }
+ }
+}
+
+/* stats_exempt()
+ *
+ * input - client to report to
+ * output - none
+ * side effects - client is given list of exempt blocks
+ */
+static void
+stats_exempt(struct Client *source_p, int parc, char *parv[])
+{
+ struct ConfItem *conf;
+ struct AccessItem *aconf;
+ dlink_node *ptr = NULL;
+ unsigned int i = 0;
+
+ if (ConfigFileEntry.stats_e_disabled)
+ {
+ sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
+ from, to);
+ return;
+ }
+
+
+ for (i = 0; i < ATABLE_SIZE; ++i)
+ {
+ DLINK_FOREACH(ptr, atable[i].head)
+ {
+ struct AddressRec *arec = ptr->data;
+
+ if (arec->type == CONF_EXEMPTDLINE)
+ {
+ aconf = arec->aconf;
+
+ conf = unmap_conf_item(aconf);
+
+ sendto_one(source_p, form_str(RPL_STATSDLINE),
+ from, to, 'e', aconf->host,
+ aconf->reason, aconf->oper_reason ? aconf->oper_reason : "");
+ }
+ }
+ }
+}
+
+static void
+stats_events(struct Client *source_p, int parc, char *parv[])
+{
+ show_events(source_p);
+}
+
+/* stats_pending_glines()
+ *
+ * input - client pointer
+ * output - none
+ * side effects - client is shown list of pending glines
+ */
+static void
+stats_pending_glines(struct Client *source_p, int parc, char *parv[])
+{
+ const dlink_node *dn_ptr = NULL;
+ const struct gline_pending *glp_ptr = NULL;
+ char timebuffer[MAX_DATE_STRING] = { '\0' };
+ struct tm *tmptr = NULL;
+
+ if (!ConfigFileEntry.glines)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :This server does not support G-Lines",
+ from, to);
+ return;
+ }
+
+ if (dlink_list_length(&pending_glines[GLINE_PENDING_ADD_TYPE]) > 0)
+ sendto_one(source_p, ":%s NOTICE %s :Pending G-lines",
+ from, to);
+
+ DLINK_FOREACH(dn_ptr, pending_glines[GLINE_PENDING_ADD_TYPE].head)
+ {
+ glp_ptr = dn_ptr->data;
+ tmptr = localtime(&glp_ptr->vote_1.time_request);
+ strftime(timebuffer, MAX_DATE_STRING, "%Y/%m/%d %H:%M:%S", tmptr);
+
+ sendto_one(source_p,
+ ":%s NOTICE %s :1) %s!%s@%s on %s requested gline at %s for %s@%s [%s]",
+ from, to, glp_ptr->vote_1.oper_nick,
+ glp_ptr->vote_1.oper_user, glp_ptr->vote_1.oper_host,
+ glp_ptr->vote_1.oper_server, timebuffer,
+ glp_ptr->user, glp_ptr->host, glp_ptr->vote_1.reason);
+
+ if (glp_ptr->vote_2.oper_nick[0] != '\0')
+ {
+ tmptr = localtime(&glp_ptr->vote_2.time_request);
+ strftime(timebuffer, MAX_DATE_STRING, "%Y/%m/%d %H:%M:%S", tmptr);
+ sendto_one(source_p,
+ ":%s NOTICE %s :2) %s!%s@%s on %s requested gline at %s for %s@%s [%s]",
+ from, to, glp_ptr->vote_2.oper_nick,
+ glp_ptr->vote_2.oper_user, glp_ptr->vote_2.oper_host,
+ glp_ptr->vote_2.oper_server, timebuffer,
+ glp_ptr->user, glp_ptr->host, glp_ptr->vote_2.reason);
+ }
+ }
+
+ sendto_one(source_p, ":%s NOTICE %s :End of Pending G-lines",
+ from, to);
+
+ if (dlink_list_length(&pending_glines[GLINE_PENDING_DEL_TYPE]) > 0)
+ sendto_one(source_p, ":%s NOTICE %s :Pending UNG-lines",
+ from, to);
+
+ DLINK_FOREACH(dn_ptr, pending_glines[GLINE_PENDING_DEL_TYPE].head)
+ {
+ glp_ptr = dn_ptr->data;
+ tmptr = localtime(&glp_ptr->vote_1.time_request);
+ strftime(timebuffer, MAX_DATE_STRING, "%Y/%m/%d %H:%M:%S", tmptr);
+
+ sendto_one(source_p,
+ ":%s NOTICE %s :1) %s!%s@%s on %s requested ungline at %s for %s@%s [%s]",
+ from, to, glp_ptr->vote_1.oper_nick,
+ glp_ptr->vote_1.oper_user, glp_ptr->vote_1.oper_host,
+ glp_ptr->vote_1.oper_server, timebuffer,
+ glp_ptr->user, glp_ptr->host, glp_ptr->vote_1.reason);
+
+ if (glp_ptr->vote_2.oper_nick[0] != '\0')
+ {
+ tmptr = localtime(&glp_ptr->vote_2.time_request);
+ strftime(timebuffer, MAX_DATE_STRING, "%Y/%m/%d %H:%M:%S", tmptr);
+ sendto_one(source_p,
+ ":%s NOTICE %s :2) %s!%s@%s on %s requested ungline at %s for %s@%s [%s]",
+ from, to, glp_ptr->vote_2.oper_nick,
+ glp_ptr->vote_2.oper_user, glp_ptr->vote_2.oper_host,
+ glp_ptr->vote_2.oper_server, timebuffer,
+ glp_ptr->user, glp_ptr->host, glp_ptr->vote_2.reason);
+
+ }
+ }
+
+ sendto_one(source_p, ":%s NOTICE %s :End of Pending UNG-lines",
+ from, to);
+}
+
+/* stats_glines()
+ *
+ * input - client pointer
+ * output - none
+ * side effects - client is shown list of glines
+ */
+static void
+stats_glines(struct Client *source_p, int parc, char *parv[])
+{
+ dlink_node *ptr = NULL;
+ unsigned int i = 0;
+
+ if (!ConfigFileEntry.glines)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :This server does not support G-Lines",
+ from, to);
+ return;
+ }
+
+ for (i = 0; i < ATABLE_SIZE; ++i)
+ {
+ DLINK_FOREACH(ptr, atable[i].head)
+ {
+ const struct AddressRec *arec = ptr->data;
+
+ if (arec->type == CONF_GLINE)
+ {
+ const struct AccessItem *aconf = arec->aconf;
+
+ sendto_one(source_p, form_str(RPL_STATSKLINE),
+ from, to, "G",
+ aconf->host ? aconf->host : "*",
+ aconf->user ? aconf->user : "*",
+ aconf->reason ? aconf->reason : "No reason", "" );
+ }
+ }
+ }
+}
+
+static void
+stats_hubleaf(struct Client *source_p, int parc, char *parv[])
+{
+ report_confitem_types(source_p, HUB_TYPE);
+ report_confitem_types(source_p, LEAF_TYPE);
+}
+
+/*
+ * show_iline_prefix()
+ *
+ * inputs - pointer to struct Client requesting output
+ * - pointer to struct AccessItem
+ * - name to which iline prefix will be prefixed to
+ * output - pointer to static string with prefixes listed in ascii form
+ * side effects - NONE
+ */
+static const char *
+show_iline_prefix(struct Client *sptr, struct AccessItem *aconf, const char *name)
+{
+ static char prefix_of_host[USERLEN + 14];
+ char *prefix_ptr = prefix_of_host;
+
+ if (IsNoTilde(aconf))
+ *prefix_ptr++ = '-';
+ if (IsLimitIp(aconf))
+ *prefix_ptr++ = '!';
+ if (IsNeedIdentd(aconf))
+ *prefix_ptr++ = '+';
+ if (!IsNeedPassword(aconf))
+ *prefix_ptr++ = '&';
+ if (IsConfExemptResv(aconf))
+ *prefix_ptr++ = '$';
+ if (IsNoMatchIp(aconf))
+ *prefix_ptr++ = '%';
+ if (IsConfDoSpoofIp(aconf))
+ *prefix_ptr++ = '=';
+ if (MyOper(sptr) && IsConfExemptKline(aconf))
+ *prefix_ptr++ = '^';
+ if (MyOper(sptr) && IsConfExemptGline(aconf))
+ *prefix_ptr++ = '_';
+ if (MyOper(sptr) && IsConfExemptLimits(aconf))
+ *prefix_ptr++ = '>';
+ if (IsConfCanFlood(aconf))
+ *prefix_ptr++ = '|';
+
+ strlcpy(prefix_ptr, name, USERLEN+1);
+
+ return prefix_of_host;
+}
+
+static void
+report_auth(struct Client *client_p, int parc, char *parv[])
+{
+ struct ConfItem *conf;
+ struct AccessItem *aconf;
+ dlink_node *ptr = NULL;
+ unsigned int i;
+
+
+ for (i = 0; i < ATABLE_SIZE; ++i)
+ {
+ DLINK_FOREACH(ptr, atable[i].head)
+ {
+ struct AddressRec *arec = ptr->data;
+
+ if (arec->type == CONF_CLIENT)
+ {
+ aconf = arec->aconf;
+
+ if (!MyOper(client_p) && IsConfDoSpoofIp(aconf))
+ continue;
+
+ conf = unmap_conf_item(aconf);
+
+ /* We are doing a partial list, based on what matches the u@h of the
+ * sender, so prepare the strings for comparing --fl_
+ */
+ if (ConfigFileEntry.hide_spoof_ips)
+ sendto_one(client_p, form_str(RPL_STATSILINE), me.name,
+ client_p->name, 'I',
+ conf->name == NULL ? "*" : conf->name,
+ show_iline_prefix(client_p, aconf, aconf->user),
+ IsConfDoSpoofIp(aconf) ? "255.255.255.255" :
+ aconf->host, aconf->port,
+ aconf->class_ptr ? aconf->class_ptr->name : "<default>");
+
+ else
+ sendto_one(client_p, form_str(RPL_STATSILINE), me.name,
+ client_p->name, 'I',
+ conf->name == NULL ? "*" : conf->name,
+ show_iline_prefix(client_p, aconf, aconf->user),
+ aconf->host, aconf->port,
+ aconf->class_ptr ? aconf->class_ptr->name : "<default>");
+ }
+ }
+ }
+}
+
+static void
+stats_auth(struct Client *source_p, int parc, char *parv[])
+{
+ /* Oper only, if unopered, return ERR_NOPRIVILEGES */
+ if ((ConfigFileEntry.stats_i_oper_only == 2) && !HasUMode(source_p, UMODE_OPER))
+ sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
+ from, to);
+
+ /* If unopered, Only return matching auth blocks */
+ else if ((ConfigFileEntry.stats_i_oper_only == 1) && !HasUMode(source_p, UMODE_OPER))
+ {
+ struct ConfItem *conf;
+ struct AccessItem *aconf;
+
+ if (MyConnect(source_p))
+ aconf = find_conf_by_address(source_p->host,
+ &source_p->localClient->ip,
+ CONF_CLIENT,
+ source_p->localClient->aftype,
+ source_p->username,
+ source_p->localClient->passwd, 1);
+ else
+ aconf = find_conf_by_address(source_p->host, NULL, CONF_CLIENT,
+ 0, source_p->username, NULL, 1);
+
+ if (aconf == NULL)
+ return;
+
+ conf = unmap_conf_item(aconf);
+
+ sendto_one(source_p, form_str(RPL_STATSILINE), from,
+ to, 'I',
+ "*", show_iline_prefix(source_p, aconf, aconf->user),
+ aconf->host, aconf->port,
+ aconf->class_ptr ? aconf->class_ptr->name : "<default>");
+ }
+ /* They are opered, or allowed to see all auth blocks */
+ else
+ report_auth(source_p, 0, NULL);
+}
+
+/* report_Klines()
+ * Inputs: Client to report to,
+ * type(==0 for perm, !=0 for temporary)
+ * mask
+ * Output: None
+ * Side effects: Reports configured K(or k)-lines to client_p.
+ */
+static void
+report_Klines(struct Client *client_p, int tkline)
+{
+ struct AccessItem *aconf = NULL;
+ unsigned int i = 0;
+ const char *p = NULL;
+ dlink_node *ptr = NULL;
+
+ if (tkline)
+ p = "k";
+ else
+ p = "K";
+
+ for (i = 0; i < ATABLE_SIZE; ++i)
+ {
+ DLINK_FOREACH(ptr, atable[i].head)
+ {
+ struct AddressRec *arec = ptr->data;
+
+ if (arec->type == CONF_KLINE)
+ {
+ if ((tkline && !((aconf = arec->aconf)->flags & CONF_FLAGS_TEMPORARY)) ||
+ (!tkline && ((aconf = arec->aconf)->flags & CONF_FLAGS_TEMPORARY)))
+ continue;
+
+ if (HasUMode(client_p, UMODE_OPER))
+ sendto_one(client_p, form_str(RPL_STATSKLINE), me.name,
+ client_p->name, p, aconf->host, aconf->user,
+ aconf->reason, aconf->oper_reason ? aconf->oper_reason : "");
+ else
+ sendto_one(client_p, form_str(RPL_STATSKLINE), me.name,
+ client_p->name, p, aconf->host, aconf->user,
+ aconf->reason, "");
+ }
+ }
+ }
+}
+
+static void
+stats_tklines(struct Client *source_p, int parc, char *parv[])
+{
+ /* Oper only, if unopered, return ERR_NOPRIVILEGES */
+ if ((ConfigFileEntry.stats_k_oper_only == 2) && !HasUMode(source_p, UMODE_OPER))
+ sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
+ from, to);
+
+ /* If unopered, Only return matching klines */
+ else if ((ConfigFileEntry.stats_k_oper_only == 1) && !HasUMode(source_p, UMODE_OPER))
+ {
+ struct AccessItem *aconf = NULL;
+
+ if (MyConnect(source_p))
+ aconf = find_conf_by_address(source_p->host,
+ &source_p->localClient->ip,
+ CONF_KLINE,
+ source_p->localClient->aftype,
+ source_p->username, NULL, 1);
+ else
+ aconf = find_conf_by_address(source_p->host, NULL, CONF_KLINE,
+ 0, source_p->username, NULL, 1);
+
+ if (aconf == NULL)
+ return;
+
+ /* dont report a permanent kline as a tkline */
+ if (!(aconf->flags & CONF_FLAGS_TEMPORARY))
+ return;
+
+ sendto_one(source_p, form_str(RPL_STATSKLINE), from,
+ to, "k", aconf->host, aconf->user, aconf->reason, "");
+ }
+ /* Theyre opered, or allowed to see all klines */
+ else {
+ report_Klines(source_p, 1);
+ }
+}
+
+static void
+stats_klines(struct Client *source_p, int parc, char *parv[])
+{
+ /* Oper only, if unopered, return ERR_NOPRIVILEGES */
+ if ((ConfigFileEntry.stats_k_oper_only == 2) && !HasUMode(source_p, UMODE_OPER))
+ sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
+ from, to);
+
+ /* If unopered, Only return matching klines */
+ else if ((ConfigFileEntry.stats_k_oper_only == 1) && !HasUMode(source_p, UMODE_OPER))
+ {
+ struct AccessItem *aconf = NULL;
+
+ /* search for a kline */
+ if (MyConnect(source_p))
+ aconf = find_conf_by_address(source_p->host,
+ &source_p->localClient->ip,
+ CONF_KLINE,
+ source_p->localClient->aftype,
+ source_p->username, NULL, 0);
+ else
+ aconf = find_conf_by_address(source_p->host, NULL, CONF_KLINE,
+ 0, source_p->username, NULL, 0);
+
+ if (aconf == NULL)
+ return;
+
+ /* dont report a tkline as a kline */
+ if (aconf->flags & CONF_FLAGS_TEMPORARY)
+ return;
+
+ sendto_one(source_p, form_str(RPL_STATSKLINE), from,
+ to, "K", aconf->host, aconf->user, aconf->reason, "");
+ }
+ /* Theyre opered, or allowed to see all klines */
+ else {
+ report_Klines(source_p, 0);
+ report_confitem_types(source_p, RKLINE_TYPE);
+ }
+}
+
+static void
+stats_messages(struct Client *source_p, int parc, char *parv[])
+{
+ report_messages(source_p);
+}
+
+static void
+stats_oper(struct Client *source_p, int parc, char *parv[])
+{
+ if (!HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.stats_o_oper_only)
+ sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
+ from, to);
+ else
+ report_confitem_types(source_p, OPER_TYPE);
+}
+
+/* stats_operedup()
+ *
+ * input - client pointer
+ * output - none
+ * side effects - client is shown a list of active opers
+ */
+static void
+stats_operedup(struct Client *source_p, int parc, char *parv[])
+{
+ dlink_node *ptr;
+
+ DLINK_FOREACH(ptr, oper_list.head)
+ {
+ const struct Client *target_p = ptr->data;
+
+ if (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER))
+ continue;
+
+ if (MyClient(source_p) && HasUMode(source_p, UMODE_OPER))
+ sendto_one(source_p, ":%s %d %s p :[%c][%s] %s (%s@%s) Idle: %d",
+ from, RPL_STATSDEBUG, to,
+ HasUMode(target_p, UMODE_ADMIN) ? 'A' : 'O',
+ oper_privs_as_string(target_p->localClient->operflags),
+ target_p->name, target_p->username, target_p->host,
+ (int)(CurrentTime - target_p->localClient->last_privmsg));
+ else
+ sendto_one(source_p, ":%s %d %s p :[%c] %s (%s@%s) Idle: %d",
+ from, RPL_STATSDEBUG, to,
+ HasUMode(target_p, UMODE_ADMIN) ? 'A' : 'O',
+ target_p->name, target_p->username, target_p->host,
+ (int)(CurrentTime - target_p->localClient->last_privmsg));
+ }
+
+ sendto_one(source_p, ":%s %d %s p :%lu OPER(s)",
+ from, RPL_STATSDEBUG, to, dlink_list_length(&oper_list));
+}
+
+static void
+stats_ports(struct Client *source_p, int parc, char *parv[])
+{
+ if (!HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.stats_P_oper_only)
+ sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
+ from, to);
+ else
+ show_ports(source_p);
+}
+
+static void
+stats_resv(struct Client *source_p, int parc, char *parv[])
+{
+ report_resv(source_p);
+}
+
+static void
+stats_service(struct Client *source_p, int parc, char *parv[])
+{
+ report_confitem_types(source_p, SERVICE_TYPE);
+}
+
+static void
+stats_tstats(struct Client *source_p, int parc, char *parv[])
+{
+ const struct Client *target_p = NULL;
+ const dlink_node *ptr = NULL;
+ struct ServerStatistics *sp;
+ struct ServerStatistics tmp;
+
+ sp = &tmp;
+ memcpy(sp, &ServerStats, sizeof(struct ServerStatistics));
+
+ /*
+ * must use the += operator. is_sv is not the number of currently
+ * active server connections. Note the incrementation in
+ * s_bsd.c:close_connection.
+ */
+ sp->is_sv += dlink_list_length(&serv_list);
+
+ DLINK_FOREACH(ptr, serv_list.head)
+ {
+ target_p = ptr->data;
+
+ sp->is_sbs += target_p->localClient->send.bytes;
+ sp->is_sbr += target_p->localClient->recv.bytes;
+ sp->is_sti += CurrentTime - target_p->localClient->firsttime;
+ }
+
+ sp->is_cl += dlink_list_length(&local_client_list);
+
+ DLINK_FOREACH(ptr, local_client_list.head)
+ {
+ target_p = ptr->data;
+
+ sp->is_cbs += target_p->localClient->send.bytes;
+ sp->is_cbr += target_p->localClient->recv.bytes;
+ sp->is_cti += CurrentTime - target_p->localClient->firsttime;
+ }
+
+ sp->is_ni += dlink_list_length(&unknown_list);
+
+ sendto_one(source_p, ":%s %d %s T :accepts %u refused %u",
+ me.name, RPL_STATSDEBUG, source_p->name, sp->is_ac, sp->is_ref);
+ sendto_one(source_p, ":%s %d %s T :unknown commands %u prefixes %u",
+ me.name, RPL_STATSDEBUG, source_p->name, sp->is_unco, sp->is_unpf);
+ sendto_one(source_p, ":%s %d %s T :nick collisions %u unknown closes %u",
+ me.name, RPL_STATSDEBUG, source_p->name, sp->is_kill, sp->is_ni);
+ sendto_one(source_p, ":%s %d %s T :wrong direction %u empty %u",
+ me.name, RPL_STATSDEBUG, source_p->name, sp->is_wrdi, sp->is_empt);
+ sendto_one(source_p, ":%s %d %s T :numerics seen %u",
+ me.name, RPL_STATSDEBUG, source_p->name, sp->is_num);
+ sendto_one(source_p, ":%s %d %s T :auth successes %u fails %u",
+ me.name, RPL_STATSDEBUG, source_p->name, sp->is_asuc, sp->is_abad);
+ sendto_one(source_p, ":%s %d %s T :Client Server",
+ me.name, RPL_STATSDEBUG, source_p->name);
+
+ sendto_one(source_p, ":%s %d %s T :connected %u %u",
+ me.name, RPL_STATSDEBUG, source_p->name,
+ (unsigned int)sp->is_cl,
+ (unsigned int)sp->is_sv);
+ sendto_one(source_p, ":%s %d %s T :bytes sent %llu %llu",
+ me.name, RPL_STATSDEBUG, source_p->name,
+ sp->is_cbs, sp->is_sbs);
+ sendto_one(source_p, ":%s %d %s T :bytes recv %llu %llu",
+ me.name, RPL_STATSDEBUG, source_p->name,
+ sp->is_cbr, sp->is_sbr);
+ sendto_one(source_p, ":%s %d %s T :time connected %u %u",
+ me.name, RPL_STATSDEBUG, source_p->name,
+ (unsigned int)sp->is_cti,
+ (unsigned int)sp->is_sti);
+}
+
+static void
+stats_uptime(struct Client *source_p, int parc, char *parv[])
+{
+ time_t now = CurrentTime - me.localClient->since;
+
+ sendto_one(source_p, form_str(RPL_STATSUPTIME), from, to,
+ now / 86400, (now / 3600) % 24, (now / 60) % 60, now % 60);
+
+ if (!ConfigFileEntry.disable_remote || HasUMode(source_p, UMODE_OPER))
+ sendto_one(source_p, form_str(RPL_STATSCONN), from, to,
+ Count.max_loc_con, Count.max_loc_cli, Count.totalrestartcount);
+}
+
+static void
+stats_shared(struct Client *source_p, int parc, char *parv[])
+{
+ report_confitem_types(source_p, ULINE_TYPE);
+}
+
+/* stats_servers()
+ *
+ * input - client pointer
+ * output - none
+ * side effects - client is shown lists of who connected servers
+ */
+static void
+stats_servers(struct Client *source_p, int parc, char *parv[])
+{
+ dlink_node *ptr = NULL;
+
+ DLINK_FOREACH(ptr, serv_list.head)
+ {
+ const struct Client *target_p = ptr->data;
+
+ sendto_one(source_p, ":%s %d %s v :%s (%s!%s@%s) Idle: %d",
+ from, RPL_STATSDEBUG, to, target_p->name,
+ (target_p->serv->by[0] ? target_p->serv->by : "Remote."),
+ "*", "*", (int)(CurrentTime - target_p->localClient->lasttime));
+ }
+
+ sendto_one(source_p, ":%s %d %s v :%u Server(s)",
+ from, RPL_STATSDEBUG, to, dlink_list_length(&serv_list));
+}
+
+static void
+stats_gecos(struct Client *source_p, int parc, char *parv[])
+{
+ report_confitem_types(source_p, XLINE_TYPE);
+ report_confitem_types(source_p, RXLINE_TYPE);
+}
+
+static void
+stats_class(struct Client *source_p, int parc, char *parv[])
+{
+ report_confitem_types(source_p, CLASS_TYPE);
+}
+
+static void
+stats_servlinks(struct Client *source_p, int parc, char *parv[])
+{
+ uint64_t sendB = 0, recvB = 0;
+ time_t uptime = 0;
+ dlink_node *ptr = NULL;
+
+ if (ConfigServerHide.flatten_links && !HasUMode(source_p, UMODE_OPER))
+ {
+ sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
+ from, to);
+ return;
+ }
+
+ DLINK_FOREACH(ptr, serv_list.head)
+ {
+ struct Client *target_p = ptr->data;
+
+ sendB += target_p->localClient->send.bytes;
+ recvB += target_p->localClient->recv.bytes;
+
+ /* ":%s 211 %s %s %u %u %llu %u %llu :%u %u %s" */
+ sendto_one(source_p, form_str(RPL_STATSLINKINFO),
+ from, to,
+ get_client_name(target_p, HasUMode(source_p, UMODE_ADMIN) ? SHOW_IP : MASK_IP),
+ dbuf_length(&target_p->localClient->buf_sendq),
+ target_p->localClient->send.messages,
+ target_p->localClient->send.bytes >> 10,
+ target_p->localClient->recv.messages,
+ target_p->localClient->recv.bytes >> 10,
+ (unsigned)(CurrentTime - target_p->localClient->firsttime),
+ (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since): 0,
+ HasUMode(source_p, UMODE_OPER) ? show_capabilities(target_p) : "TS");
+ }
+
+ sendB >>= 10;
+ recvB >>= 10;
+
+ sendto_one(source_p, ":%s %d %s ? :%u total server(s)",
+ from, RPL_STATSDEBUG, to, dlink_list_length(&serv_list));
+ sendto_one(source_p, ":%s %d %s ? :Sent total : %7.2f %s",
+ from, RPL_STATSDEBUG, to,
+ _GMKv(sendB), _GMKs(sendB));
+ sendto_one(source_p, ":%s %d %s ? :Recv total : %7.2f %s",
+ from, RPL_STATSDEBUG, to,
+ _GMKv(recvB), _GMKs(recvB));
+
+ uptime = (CurrentTime - me.localClient->since);
+
+ sendto_one(source_p, ":%s %d %s ? :Server send: %7.2f %s (%4.1f K/s)",
+ from, RPL_STATSDEBUG, to,
+ _GMKv((me.localClient->send.bytes>>10)),
+ _GMKs((me.localClient->send.bytes>>10)),
+ (float)((float)((me.localClient->send.bytes) >> 10) /
+ (float)uptime));
+ sendto_one(source_p, ":%s %d %s ? :Server recv: %7.2f %s (%4.1f K/s)",
+ from, RPL_STATSDEBUG, to,
+ _GMKv((me.localClient->recv.bytes>>10)),
+ _GMKs((me.localClient->recv.bytes>>10)),
+ (float)((float)((me.localClient->recv.bytes) >> 10) /
+ (float)uptime));
+}
+
+/* parse_stats_args()
+ *
+ * inputs - arg count
+ * - args
+ * - doall flag
+ * - wild card or not
+ * output - pointer to name to use
+ * side effects -
+ * common parse routine for m_stats args
+ *
+ */
+static char *
+parse_stats_args(int parc, char *parv[], int *doall, int *wilds)
+{
+ char *name;
+
+ if (parc > 2)
+ {
+ name = parv[2];
+
+ if (!irccmp(name, from))
+ *doall = 2;
+ else if (match(name, from))
+ *doall = 1;
+
+ *wilds = has_wildcards(name);
+
+ return name;
+ }
+
+ return NULL;
+}
+
+static void
+stats_L_list(struct Client *source_p,char *name, int doall, int wilds,
+ dlink_list *list,char statchar)
+{
+ dlink_node *ptr;
+ struct Client *target_p;
+
+ /*
+ * send info about connections which match, or all if the
+ * mask matches from. Only restrictions are on those who
+ * are invisible not being visible to 'foreigners' who use
+ * a wild card based search to list it.
+ */
+ DLINK_FOREACH(ptr, list->head)
+ {
+ target_p = ptr->data;
+
+ if (HasUMode(target_p, UMODE_INVISIBLE) && (doall || wilds) &&
+ !(MyConnect(source_p) && HasUMode(source_p, UMODE_OPER)) &&
+ !HasUMode(target_p, UMODE_OPER) && (target_p != source_p))
+ continue;
+ if (!doall && wilds && !match(name, target_p->name))
+ continue;
+ if (!(doall || wilds) && irccmp(name, target_p->name))
+ continue;
+
+ /* This basically shows ips for our opers if its not a server/admin, or
+ * its one of our admins. */
+ if(MyClient(source_p) && HasUMode(source_p, UMODE_OPER) &&
+ (HasUMode(source_p, UMODE_ADMIN) ||
+ (!IsServer(target_p) && !HasUMode(target_p, UMODE_ADMIN) &&
+ !IsHandshake(target_p) && !IsConnecting(target_p))))
+ {
+ sendto_one(source_p, form_str(RPL_STATSLINKINFO),
+ from, to,
+ (IsUpper(statchar)) ?
+ get_client_name(target_p, SHOW_IP) :
+ get_client_name(target_p, HIDE_IP),
+ dbuf_length(&target_p->localClient->buf_sendq),
+ target_p->localClient->send.messages,
+ target_p->localClient->send.bytes>>10,
+ target_p->localClient->recv.messages,
+ target_p->localClient->recv.bytes>>10,
+ (unsigned)(CurrentTime - target_p->localClient->firsttime),
+ (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since):0,
+ IsServer(target_p) ? show_capabilities(target_p) : "-");
+ }
+ else
+ {
+ /* If its a hidden ip, an admin, or a server, mask the real IP */
+ if(IsIPSpoof(target_p) || IsServer(target_p) || HasUMode(target_p, UMODE_ADMIN)
+ || IsHandshake(target_p) || IsConnecting(target_p))
+ sendto_one(source_p, form_str(RPL_STATSLINKINFO),
+ from, to,
+ get_client_name(target_p, MASK_IP),
+ dbuf_length(&target_p->localClient->buf_sendq),
+ target_p->localClient->send.messages,
+ target_p->localClient->send.bytes>>10,
+ target_p->localClient->recv.messages,
+ target_p->localClient->recv.bytes>>10,
+ (unsigned)(CurrentTime - target_p->localClient->firsttime),
+ (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since):0,
+ IsServer(target_p) ? show_capabilities(target_p) : "-");
+ else /* show the real IP */
+ sendto_one(source_p, form_str(RPL_STATSLINKINFO),
+ from, to,
+ (IsUpper(statchar)) ?
+ get_client_name(target_p, SHOW_IP) :
+ get_client_name(target_p, HIDE_IP),
+ dbuf_length(&target_p->localClient->buf_sendq),
+ target_p->localClient->send.messages,
+ target_p->localClient->send.bytes>>10,
+ target_p->localClient->recv.messages,
+ target_p->localClient->recv.bytes>>10,
+ (unsigned)(CurrentTime - target_p->localClient->firsttime),
+ (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since):0,
+ IsServer(target_p) ? show_capabilities(target_p) : "-");
+ }
+ }
+}
+
+/*
+ * stats_L
+ *
+ * inputs - pointer to client to report to
+ * - doall flag
+ * - wild card or not
+ * output - NONE
+ * side effects -
+ */
+static void
+stats_L(struct Client *source_p,char *name,int doall,
+ int wilds,char statchar)
+{
+ stats_L_list(source_p, name, doall, wilds, &unknown_list, statchar);
+ stats_L_list(source_p, name, doall, wilds, &local_client_list, statchar);
+ stats_L_list(source_p, name, doall, wilds, &serv_list, statchar);
+}
+
+static void
+stats_ltrace(struct Client *source_p, int parc, char *parv[])
+{
+ int doall = 0;
+ int wilds = 0;
+ char *name = NULL;
+ char statchar;
+
+ if ((name = parse_stats_args(parc, parv, &doall, &wilds)) != NULL)
+ {
+ statchar = parv[1][0];
+
+ stats_L(source_p, name, doall, wilds, statchar);
+ }
+ else
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ from, to, "STATS");
+}
+
+static const struct StatsStruct
+{
+ const unsigned char letter;
+ void (*handler)();
+ const unsigned int need_oper;
+ const unsigned int need_admin;
+} stats_cmd_table[] = {
+ /* letter function need_oper need_admin */
+ { 'a', stats_dns_servers, 1, 1 },
+ { 'A', stats_dns_servers, 1, 1 },
+ { 'c', stats_connect, 1, 0 },
+ { 'C', stats_connect, 1, 0 },
+ { 'd', stats_tdeny, 1, 0 },
+ { 'D', stats_deny, 1, 0 },
+ { 'e', stats_exempt, 1, 0 },
+ { 'E', stats_events, 1, 1 },
+ { 'f', fd_dump, 1, 1 },
+ { 'F', fd_dump, 1, 1 },
+ { 'g', stats_pending_glines, 1, 0 },
+ { 'G', stats_glines, 1, 0 },
+ { 'h', stats_hooks, 1, 1 },
+ { 'H', stats_hubleaf, 1, 0 },
+ { 'i', stats_auth, 0, 0 },
+ { 'I', stats_auth, 0, 0 },
+ { 'k', stats_tklines, 0, 0 },
+ { 'K', stats_klines, 0, 0 },
+ { 'l', stats_ltrace, 1, 0 },
+ { 'L', stats_ltrace, 1, 0 },
+ { 'm', stats_messages, 0, 0 },
+ { 'M', stats_messages, 0, 0 },
+ { 'o', stats_oper, 0, 0 },
+ { 'O', stats_oper, 0, 0 },
+ { 'p', stats_operedup, 0, 0 },
+ { 'P', stats_ports, 0, 0 },
+ { 'q', stats_resv, 1, 0 },
+ { 'Q', stats_resv, 1, 0 },
+ { 'r', stats_usage, 1, 0 },
+ { 'R', stats_usage, 1, 0 },
+ { 'S', stats_service, 1, 0 },
+ { 't', stats_tstats, 1, 0 },
+ { 'T', stats_tstats, 1, 0 },
+ { 'u', stats_uptime, 0, 0 },
+ { 'U', stats_shared, 1, 0 },
+ { 'v', stats_servers, 1, 0 },
+ { 'x', stats_gecos, 1, 0 },
+ { 'X', stats_gecos, 1, 0 },
+ { 'y', stats_class, 1, 0 },
+ { 'Y', stats_class, 1, 0 },
+ { 'z', stats_memory, 1, 0 },
+ { '?', stats_servlinks, 0, 0 },
+ { '\0', NULL, 0, 0 }
+};
+
+static void
+do_stats(struct Client *source_p, int parc, char *parv[])
+{
+ const struct StatsStruct *tab = stats_cmd_table;
+ const char statchar = *parv[1];
+
+ if (statchar == '\0')
+ {
+ sendto_one(source_p, form_str(RPL_ENDOFSTATS),
+ from, to, '*');
+ return;
+ }
+
+ for (; tab->handler; ++tab)
+ {
+ if (tab->letter == statchar)
+ {
+ /* The stats table says what privs are needed, so check --fl_ */
+ if ((tab->need_admin && !HasUMode(source_p, UMODE_ADMIN)) ||
+ (tab->need_oper && !HasUMode(source_p, UMODE_OPER)))
+ {
+ sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
+ from, to);
+ break;
+ }
+
+ sendto_realops_flags(UMODE_SPY, L_ALL,
+ "STATS %c requested by %s (%s@%s) [%s]",
+ statchar, source_p->name, source_p->username,
+ source_p->host, source_p->servptr->name);
+ tab->handler(source_p, parc, parv);
+ break;
+ }
+ }
+
+ sendto_one(source_p, form_str(RPL_ENDOFSTATS),
+ from, to, statchar);
+}
+
+/*
+ * m_stats()
+ * parv[0] = sender prefix
+ * parv[1] = stat letter/command
+ * parv[2] = (if present) server/mask in stats L
+ *
+ * This will search the tables for the appropriate stats letter/command,
+ * if found execute it.
+ */
+static void
+m_stats(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ static time_t last_used = 0;
+
+ /* Is the stats meant for us? */
+ if (!ConfigFileEntry.disable_remote)
+ if (hunt_server(client_p, source_p, ":%s STATS %s :%s", 2,
+ parc, parv) != HUNTED_ISME)
+ return;
+
+ if (!MyClient(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;
+ }
+
+ /* Check the user is actually allowed to do /stats, and isnt flooding */
+ if ((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
+ {
+ sendto_one(source_p,form_str(RPL_LOAD2HI),
+ from, to);
+ return;
+ }
+
+ last_used = CurrentTime;
+
+ do_stats(source_p, parc, parv);
+}
+
+/*
+ * mo_stats()
+ * parv[0] = sender prefix
+ * parv[1] = stat letter/command
+ * parv[2] = (if present) server/mask in stats L, or target
+ *
+ * This will search the tables for the appropriate stats letter,
+ * if found execute it.
+ */
+static void
+mo_stats(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (hunt_server(client_p, source_p, ":%s STATS %s :%s", 2,
+ parc, parv) != HUNTED_ISME)
+ return;
+
+ if (!MyClient(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;
+ }
+
+ do_stats(source_p, parc, parv);
+}
+
+/*
+ * ms_stats - STATS message handler
+ * parv[0] = sender prefix
+ * parv[1] = statistics selector (defaults to Message frequency)
+ * parv[2] = server name (current server defaulted, if omitted)
+ */
+static void
+ms_stats(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (hunt_server(client_p, source_p, ":%s STATS %s :%s", 2,
+ parc, parv) != HUNTED_ISME)
+ return;
+
+ if (IsClient(source_p))
+ mo_stats(client_p, source_p, parc, parv);
+}
+
+static struct Message stats_msgtab = {
+ "STATS", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_stats, ms_stats, m_ignore, mo_stats, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&stats_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&stats_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_svinfo.c b/modules/m_svinfo.c
new file mode 100644
index 0000000..bb36887
--- /dev/null
+++ b/modules/m_svinfo.c
@@ -0,0 +1,143 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_svinfo.c: Sends TS information for clock & compatibility checks.
+ *
+ * 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 "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "send.h"
+#include "conf.h"
+#include "log.h"
+#include "parse.h"
+#include "modules.h"
+
+
+/*
+ * ms_svinfo - SVINFO message handler
+ * parv[0] = sender prefix
+ * parv[1] = TS_CURRENT for the server
+ * parv[2] = TS_MIN for the server
+ * parv[3] = server is standalone or connected to non-TS only
+ * parv[4] = server's idea of UTC time
+ */
+static void
+ms_svinfo(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ time_t deltat;
+ time_t theirtime;
+
+ if (MyConnect(source_p) && IsUnknown(source_p))
+ {
+ exit_client(source_p, source_p, "Need SERVER before SVINFO");
+ return;
+ }
+
+ if (!IsServer(source_p) || !MyConnect(source_p) || parc < 5)
+ return;
+
+ if (TS_CURRENT < atoi(parv[2]) || atoi(parv[1]) < TS_MIN)
+ {
+ /*
+ * a server with the wrong TS version connected; since we're
+ * TS_ONLY we can't fall back to the non-TS protocol so
+ * we drop the link -orabidoo
+ */
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "Link %s dropped, wrong TS protocol version (%s,%s)",
+ get_client_name(source_p, SHOW_IP), parv[1], parv[2]);
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "Link %s dropped, wrong TS protocol version (%s,%s)",
+ get_client_name(source_p, MASK_IP), parv[1], parv[2]);
+ exit_client(source_p, source_p, "Incompatible TS version");
+ return;
+ }
+
+ /*
+ * since we're here, might as well set CurrentTime while we're at it
+ */
+ set_time();
+ theirtime = atol(parv[4]);
+ deltat = abs(theirtime - CurrentTime);
+
+ if (deltat > ConfigFileEntry.ts_max_delta)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ADMIN,
+ "Link %s dropped, excessive TS delta (my TS=%lu, their TS=%lu, delta=%d)",
+ get_client_name(source_p, SHOW_IP),
+ (unsigned long) CurrentTime,
+ (unsigned long) theirtime,
+ (int) deltat);
+ sendto_realops_flags(UMODE_ALL, L_OPER,
+ "Link %s dropped, excessive TS delta (my TS=%lu, their TS=%lu, delta=%d)",
+ get_client_name(source_p, MASK_IP),
+ (unsigned long) CurrentTime,
+ (unsigned long) theirtime,
+ (int) deltat);
+ ilog(LOG_TYPE_IRCD,
+ "Link %s dropped, excessive TS delta (my TS=%lu, their TS=%lu, delta=%d)",
+ get_client_name(source_p, SHOW_IP),
+ (unsigned long) CurrentTime,
+ (unsigned long) theirtime,
+ (int) deltat);
+ exit_client(source_p, source_p, "Excessive TS delta");
+ return;
+ }
+
+ if (deltat > ConfigFileEntry.ts_warn_delta)
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "Link %s notable TS delta (my TS=%lu, their TS=%lu, delta=%d)",
+ source_p->name,
+ (unsigned long) CurrentTime,
+ (unsigned long) theirtime,
+ (int) deltat);
+}
+
+static struct Message svinfo_msgtab = {
+ "SVINFO", 0, 0, 4, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_ignore, ms_svinfo, m_ignore, m_ignore, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&svinfo_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&svinfo_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_svsmode.c b/modules/m_svsmode.c
new file mode 100644
index 0000000..34c4c71
--- /dev/null
+++ b/modules/m_svsmode.c
@@ -0,0 +1,208 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ *
+ * Copyright (C) 1999 by the Bahamut Development Team.
+ * Copyright (C) 2011 by the Hybrid Development Team.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/*! \file m_svsmode.c
+ * \brief Includes required functions for processing the SVSMODE command.
+ * \version $Id$
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_serv.h"
+#include "send.h"
+#include "channel_mode.h"
+#include "parse.h"
+#include "modules.h"
+#include "irc_string.h"
+#include "s_user.h"
+#include "conf.h"
+#include "hook.h"
+
+
+/*! \brief SVSMODE command handler (called by services)
+ *
+ * \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
+ * - parv[2] = TS (or mode, depending on svs version)
+ * - parv[3] = mode (or services id if old svs version)
+ * - parv[4] = optional argument (services id)
+ */
+static void
+ms_svsmode(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *target_p = NULL;
+ int what = MODE_ADD;
+ unsigned int flag = 0, setflags = 0;
+ char *m = NULL, *modes = NULL, *extarg = NULL;
+ time_t ts = 0;
+
+ if (!HasFlag(source_p, FLAGS_SERVICE))
+ return;
+
+ if ((parc >= 4) && ((*parv[3] == '+') || (*parv[3] == '-')))
+ {
+ ts = atol(parv[2]);
+ modes = parv[3];
+ extarg = (parc > 4) ? parv[4] : NULL;
+ }
+ else
+ {
+ modes = parv[2];
+ extarg = (parc > 3) ? parv[3] : NULL;
+ }
+
+ if ((target_p = find_person(client_p, parv[1])) == NULL)
+ return;
+
+ if (ts && (ts != target_p->tsinfo))
+ return;
+
+ setflags = target_p->umodes;
+
+ for (m = modes; *m; ++m)
+ {
+ switch (*m)
+ {
+ case '+':
+ what = MODE_ADD;
+ break;
+ case '-':
+ what = MODE_DEL;
+ break;
+
+ case 'd':
+ if (!EmptyString(extarg))
+ strlcpy(target_p->svid, extarg, sizeof(target_p->svid));
+ break;
+
+ case 'o':
+ if (what == MODE_DEL && HasUMode(target_p, UMODE_OPER))
+ {
+ ClearOper(target_p);
+ Count.oper--;
+
+ if (MyConnect(target_p))
+ {
+ dlink_node *dm = NULL;
+
+ detach_conf(target_p, OPER_TYPE);
+ ClrOFlag(target_p);
+ DelUMode(target_p, ConfigFileEntry.oper_only_umodes);
+
+ if ((dm = dlinkFindDelete(&oper_list, target_p)) != NULL)
+ free_dlink_node(dm);
+ }
+ }
+
+ break;
+
+ case 'i':
+ if (what == MODE_ADD && !HasUMode(target_p, UMODE_INVISIBLE))
+ {
+ AddUMode(target_p, UMODE_INVISIBLE);
+ ++Count.invisi;
+ }
+
+ if (what == MODE_DEL && HasUMode(target_p, UMODE_INVISIBLE))
+ {
+ DelUMode(target_p, UMODE_INVISIBLE);
+ --Count.invisi;
+ }
+
+ break;
+
+ case ' ':
+ case '\n':
+ case '\r':
+ case '\t':
+ break;
+ default:
+ if ((flag = user_modes[(unsigned char)*m]))
+ execute_callback(umode_cb, client_p, target_p, what, flag);
+ break;
+ }
+ }
+
+ if (extarg)
+ {
+ sendto_server(client_p, CAP_TS6, NOCAPS,
+ ":%s SVSMODE %s %lu %s %s", ID(source_p),
+ ID(target_p), (unsigned long)target_p->tsinfo, modes, extarg);
+ sendto_server(client_p, NOCAPS, CAP_TS6,
+ ":%s SVSMODE %s %lu %s %s", source_p->name,
+ target_p->name, (unsigned long)target_p->tsinfo, modes, extarg);
+ }
+ else
+ {
+ sendto_server(client_p, CAP_TS6, NOCAPS,
+ ":%s SVSMODE %s %lu %s", ID(source_p),
+ ID(target_p), (unsigned long)target_p->tsinfo, modes);
+ sendto_server(client_p, NOCAPS, CAP_TS6,
+ ":%s SVSMODE %s %lu %s", source_p->name,
+ target_p->name, (unsigned long)target_p->tsinfo, modes);
+ }
+
+ if (MyConnect(target_p) && (setflags != target_p->umodes))
+ {
+ char modebuf[IRCD_BUFSIZE];
+
+ send_umode(target_p, target_p, setflags, 0xffffffff, modebuf);
+ }
+}
+
+static struct Message svsmode_msgtab = {
+ "SVSMODE", 0, 0, 3, MAXPARA, MFLG_SLOW, 0,
+ {m_ignore, m_ignore, ms_svsmode, m_ignore, m_ignore, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&svsmode_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&svsmode_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_svsnick.c b/modules/m_svsnick.c
new file mode 100644
index 0000000..ff638d7
--- /dev/null
+++ b/modules/m_svsnick.c
@@ -0,0 +1,148 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ *
+ * Copyright (C) 1999 by the Bahamut Development Team.
+ * Copyright (C) 2011 by the Hybrid Development Team.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/*! \file m_svsnick.c
+ * \brief Includes required functions for processing the SVSNICK command.
+ * \version $Id$
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "ircd.h"
+#include "channel_mode.h"
+#include "numeric.h"
+#include "s_serv.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+#include "irc_string.h"
+#include "s_user.h"
+#include "hash.h"
+#include "watch.h"
+#include "whowas.h"
+
+
+/*! \brief SVSNICK command handler (called by services)
+ *
+ * \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] = old nickname
+ * - parv[2] = new nickname
+ * - parv[3] = timestamp
+ */
+static void
+ms_svsnick(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *target_p = NULL, *exists_p = NULL;
+
+ if (!HasFlag(source_p, FLAGS_SERVICE) || !valid_nickname(parv[2], 1))
+ return;
+
+ if (hunt_server(client_p, source_p, ":%s SVSNICK %s %s :%s",
+ 1, parc, parv) != HUNTED_ISME)
+ return;
+
+ if ((target_p = find_person(client_p, parv[1])) == NULL)
+ return;
+
+ assert(MyClient(target_p));
+
+ if ((exists_p = hash_find_client(parv[2])))
+ {
+ if (IsUnknown(exists_p))
+ exit_client(exists_p, &me, "SVSNICK Override");
+ else
+ {
+ exit_client(target_p, &me, "SVSNICK Collide");
+ return;
+ }
+ }
+
+ target_p->tsinfo = atoi(parv[3]);
+ clear_ban_cache_client(target_p);
+ watch_check_hash(target_p, RPL_LOGOFF);
+
+ if (HasUMode(target_p, UMODE_REGISTERED))
+ {
+ unsigned int oldmodes = target_p->umodes;
+ char modebuf[IRCD_BUFSIZE] = { '\0' };
+
+ DelUMode(target_p, UMODE_REGISTERED);
+ send_umode(target_p, target_p, oldmodes, 0xffffffff, modebuf);
+ }
+
+ sendto_common_channels_local(target_p, 1, ":%s!%s@%s NICK :%s",
+ target_p->name, target_p->username,
+ target_p->host, parv[2]);
+
+ add_history(target_p, 1);
+
+ sendto_server(NULL, CAP_TS6, NOCAPS,
+ ":%s NICK %s :%lu",
+ ID(target_p), parv[2], (unsigned long)target_p->tsinfo);
+ sendto_server(NULL, NOCAPS, CAP_TS6,
+ ":%s NICK %s :%lu",
+ target_p->name, parv[2], (unsigned long)source_p->tsinfo);
+
+ hash_del_client(target_p);
+ strlcpy(target_p->name, parv[2], sizeof(target_p->name));
+ hash_add_client(target_p);
+
+ watch_check_hash(target_p, RPL_LOGON);
+
+ fd_note(&target_p->localClient->fd, "Nick: %s", parv[2]);
+}
+
+static struct Message svsnick_msgtab = {
+ "SVSNICK", 0, 0, 4, MAXPARA, MFLG_SLOW, 0,
+ {m_ignore, m_ignore, ms_svsnick, m_ignore, m_ignore, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&svsnick_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&svsnick_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_tburst.c b/modules/m_tburst.c
new file mode 100644
index 0000000..f927c35
--- /dev/null
+++ b/modules/m_tburst.c
@@ -0,0 +1,143 @@
+/* modules/m_tburst.c
+ * Copyright (C) 2002, 2003, 2004, 2005 Hybrid Development Team
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1.Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2.Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3.The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "ircd.h"
+#include "send.h"
+#include "modules.h"
+#include "hash.h"
+#include "s_serv.h"
+#include "conf.h"
+#include "parse.h"
+
+
+/* ms_tburst()
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel timestamp
+ * parv[2] = channel
+ * parv[3] = topic timestamp
+ * parv[4] = topic setter
+ * parv[5] = topic
+ */
+static void
+ms_tburst(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Channel *chptr = NULL;
+ int accept_remote = 0;
+ time_t remote_channel_ts = atol(parv[1]);
+ time_t remote_topic_ts = atol(parv[3]);
+ const char *topic = parv[5];
+ const char *setby = parv[4];
+
+ /*
+ * Do NOT test parv[5] for an empty string and return if true!
+ * parv[5] CAN be an empty string, i.e. if the other side wants
+ * to unset our topic. Don't forget: an empty topic is also a
+ * valid topic.
+ */
+
+
+ if ((chptr = hash_find_channel(parv[2])) == NULL)
+ return;
+
+ /*
+ * The logic for accepting and rejecting channel topics was
+ * always a bit hairy, so now we got exactly 2 cases where
+ * we would accept a bursted topic
+ *
+ * Case 1:
+ * The TS of the remote channel is older than ours
+ * Case 2:
+ * The TS of the remote channel is equal to ours AND
+ * the TS of the remote topic is newer than ours
+ */
+ if (HasFlag(source_p, FLAGS_SERVICE))
+ accept_remote = 1;
+ else if (remote_channel_ts < chptr->channelts)
+ accept_remote = 1;
+ else if (remote_channel_ts == chptr->channelts)
+ if (remote_topic_ts > chptr->topic_time)
+ accept_remote = 1;
+
+ if (accept_remote)
+ {
+ int topic_differs = strncmp(chptr->topic, topic, sizeof(chptr->topic) - 1);
+
+ set_channel_topic(chptr, topic, setby, remote_topic_ts);
+
+ if (topic_differs)
+ sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s TOPIC %s :%s",
+ ConfigServerHide.hide_servers ? me.name : source_p->name,
+ chptr->chname, chptr->topic);
+ }
+
+ /*
+ * Always propagate what we have received, not only if we accept the topic.
+ * This will keep other servers in sync.
+ */
+ sendto_server(source_p, CAP_TBURST|CAP_TS6, NOCAPS,
+ ":%s TBURST %s %s %s %s :%s",
+ ID(source_p), parv[1], parv[2], parv[3], setby, topic);
+ sendto_server(source_p, CAP_TBURST, CAP_TS6,
+ ":%s TBURST %s %s %s %s :%s",
+ source_p->name, parv[1], parv[2], parv[3], setby, topic);
+}
+
+static struct Message tburst_msgtab = {
+ "TBURST", 0, 0, 6, MAXPARA, MFLG_SLOW, 0,
+ { m_ignore, m_ignore, ms_tburst, m_ignore, m_ignore, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&tburst_msgtab);
+ add_capability("TBURST", CAP_TBURST, 1);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&tburst_msgtab);
+ delete_capability("TBURST");
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_testline.c b/modules/m_testline.c
new file mode 100644
index 0000000..f9a8e67
--- /dev/null
+++ b/modules/m_testline.c
@@ -0,0 +1,258 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_testline.c: Tests a hostmask to see what will happen to it.
+ *
+ * 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 "irc_string.h"
+#include "ircd_defs.h"
+#include "ircd.h"
+#include "restart.h"
+#include "conf.h"
+#include "send.h"
+#include "hostmask.h"
+#include "numeric.h"
+#include "parse.h"
+#include "resv.h"
+#include "hash.h"
+#include "modules.h"
+
+
+/* mo_testline()
+ *
+ * inputs - pointer to physical connection request is coming from
+ * - pointer to source connection request is coming from
+ * - parc arg count
+ * - parv actual arguments
+ *
+ * output - NONE
+ * side effects - command to test I/K lines on server
+ *
+ * i.e. /quote testline user@host,ip [password]
+ *
+ */
+static void
+mo_testline(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ /* IRCD_BUFSIZE to allow things like *u*s*e*r*n*a*m*e* etc. */
+ char given_name[IRCD_BUFSIZE];
+ char given_host[IRCD_BUFSIZE];
+ char parv1_copy[IRCD_BUFSIZE];
+ struct ConfItem *conf;
+ struct AccessItem *aconf;
+ struct irc_ssaddr ip;
+ int host_mask;
+ int t;
+ int matches = 0;
+ char userhost[HOSTLEN + USERLEN + 2];
+ struct split_nuh_item nuh;
+
+ if (EmptyString(parv[1]))
+ {
+ sendto_one(source_p, ":%s NOTICE %s :usage: user@host|ip [password]",
+ me.name, source_p->name);
+ return;
+ }
+
+ if (IsChanPrefix(*parv[1])) /* Might be channel resv */
+ {
+ const struct ResvChannel *chptr = NULL;
+
+ if ((chptr = match_find_resv(parv[1])))
+ {
+ sendto_one(source_p, form_str(RPL_TESTLINE),
+ me.name, source_p->name, 'Q', 0, chptr->name,
+ chptr->reason ? chptr->reason : "No reason", "");
+ return;
+ }
+ }
+
+ strlcpy(parv1_copy, parv[1], sizeof(parv1_copy));
+
+ nuh.nuhmask = parv[1];
+ nuh.nickptr = NULL;
+ nuh.userptr = given_name;
+ nuh.hostptr = given_host;
+
+ nuh.nicksize = 0;
+ nuh.usersize = sizeof(given_name);
+ nuh.hostsize = sizeof(given_host);
+
+ split_nuh(&nuh);
+
+ t = parse_netmask(given_host, &ip, &host_mask);
+
+ if (t != HM_HOST)
+ {
+ aconf = find_dline_conf(&ip,
+#ifdef IPV6
+ (t == HM_IPV6) ? AF_INET6 : AF_INET
+#else
+ AF_INET
+#endif
+ );
+ if (aconf != NULL)
+ {
+ ++matches;
+ if (aconf->status & CONF_EXEMPTDLINE)
+ sendto_one(source_p,
+ ":%s NOTICE %s :Exempt D-line host [%s] reason [%s]",
+ me.name, source_p->name, aconf->host, aconf->reason);
+ else
+ sendto_one(source_p, form_str(RPL_TESTLINE),
+ me.name, source_p->name,
+ IsConfTemporary(aconf) ? 'd' : 'D',
+ IsConfTemporary(aconf) ? ((aconf->hold - CurrentTime) / 60)
+ : 0L,
+ aconf->host, aconf->reason,
+ aconf->oper_reason ? aconf->oper_reason : "");
+ }
+ }
+
+ if (t != HM_HOST)
+ aconf = find_address_conf(given_host, given_name, &ip,
+#ifdef IPV6
+ (t == HM_IPV6) ? AF_INET6 : AF_INET,
+#else
+ AF_INET,
+#endif
+ parv[2]);
+ else
+ aconf = find_address_conf(given_host, given_name, NULL, 0, parv[2]);
+
+ if (aconf != NULL)
+ {
+ snprintf(userhost, sizeof(userhost), "%s@%s", aconf->user, aconf->host);
+
+ if (aconf->status & CONF_CLIENT)
+ {
+ sendto_one(source_p, form_str(RPL_TESTLINE),
+ me.name, source_p->name, 'I', 0L, userhost,
+ aconf->class_ptr ? aconf->class_ptr->name : "<default>", "");
+ ++matches;
+ }
+ else if (aconf->status & CONF_KLINE)
+ {
+ sendto_one(source_p, form_str(RPL_TESTLINE),
+ me.name, source_p->name,
+ IsConfTemporary(aconf) ? 'k' : 'K',
+ IsConfTemporary(aconf) ? ((aconf->hold - CurrentTime) / 60)
+ : 0L,
+ userhost, aconf->reason? aconf->reason : "No reason",
+ aconf->oper_reason ? aconf->oper_reason : "");
+ ++matches;
+ }
+ }
+
+ conf = find_matching_name_conf(NRESV_TYPE, given_name, NULL, NULL, 0);
+
+ if (conf != NULL)
+ {
+ const struct MatchItem *mconf = map_to_conf(conf);
+
+ sendto_one(source_p, form_str(RPL_TESTLINE),
+ me.name, source_p->name, 'Q', 0L,
+ conf->name,
+ mconf->reason ? mconf->reason : "No reason",
+ mconf->oper_reason ? mconf->oper_reason : "");
+ ++matches;
+ }
+
+ if (matches == 0)
+ sendto_one(source_p, form_str(RPL_NOTESTLINE),
+ me.name, source_p->name, parv1_copy);
+}
+
+/* mo_testgecos()
+ *
+ * inputs - pointer to physical connection request is coming from
+ * - pointer to source connection request is coming from
+ * - parc arg count
+ * - parv actual arguments
+ *
+ * output - always 0
+ * side effects - command to test X lines on server
+ *
+ * i.e. /quote testgecos gecos
+ *
+ */
+static void
+mo_testgecos(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct ConfItem *conf = NULL;
+
+ if (EmptyString(parv[1]))
+ {
+ sendto_one(source_p, ":%s NOTICE %s :usage: gecos",
+ me.name, source_p->name);
+ return;
+ }
+
+ if ((conf = find_matching_name_conf(XLINE_TYPE, parv[1], NULL, NULL, 0)))
+ {
+ const struct MatchItem *xconf = map_to_conf(conf);
+ sendto_one(source_p, form_str(RPL_TESTLINE),
+ me.name, source_p->name, 'X', 0L,
+ conf->name, xconf->reason ? xconf->reason : "X-lined",
+ xconf->oper_reason ? xconf->oper_reason : "");
+ }
+ else
+ sendto_one(source_p, form_str(RPL_NOTESTLINE),
+ me.name, source_p->name, parv[1]);
+}
+
+static struct Message testline_msgtab = {
+ "TESTLINE", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_not_oper, m_ignore, m_ignore, mo_testline, m_ignore }
+};
+
+struct Message testgecos_msgtab = {
+ "TESTGECOS", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_not_oper, m_ignore, m_ignore, mo_testgecos, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&testline_msgtab);
+ mod_add_cmd(&testgecos_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&testline_msgtab);
+ mod_del_cmd(&testgecos_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_testmask.c b/modules/m_testmask.c
new file mode 100644
index 0000000..20da840
--- /dev/null
+++ b/modules/m_testmask.c
@@ -0,0 +1,131 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_testmask.c: Counts the birdies err local and remote clients.
+ *
+ * Copyright (C) 2005 by Diane Bruce
+ * Coypright (C) 2005 ircd-hybrid team
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1.Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2.Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3.The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "irc_string.h"
+#include "ircd_defs.h"
+#include "ircd.h"
+#include "restart.h"
+#include "conf.h"
+#include "send.h"
+#include "hostmask.h"
+#include "numeric.h"
+#include "parse.h"
+#include "modules.h"
+
+
+/* mo_testmask()
+ *
+ * inputs - pointer to physical connection request is coming from
+ * - pointer to source connection request is coming from
+ * - parc arg count
+ * - parv actual arguments
+ * output - NONE
+ * side effects - count up clients matching mask
+ * i.e. /quote testmask user@host
+ */
+static void
+mo_testmask(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct split_nuh_item nuh;
+ char given_nick[IRCD_BUFSIZE];
+ char given_user[IRCD_BUFSIZE];
+ char given_host[IRCD_BUFSIZE];
+ unsigned int count[2] = { 0, 0 };
+ const dlink_node *ptr = NULL;
+
+ if (EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, "TESTMASK");
+ return;
+ }
+
+ nuh.nuhmask = parv[1];
+ nuh.nickptr = given_nick;
+ nuh.userptr = given_user;
+ nuh.hostptr = given_host;
+
+ nuh.nicksize = sizeof(given_nick);
+ nuh.usersize = sizeof(given_user);
+ nuh.hostsize = sizeof(given_host);
+
+ split_nuh(&nuh);
+
+ DLINK_FOREACH(ptr, global_client_list.head)
+ {
+ const struct Client *target_p = ptr->data;
+
+ if (!IsClient(target_p) || !match(given_nick, target_p->name))
+ continue;
+
+ if (match(given_user, target_p->username))
+ if (match(given_host, target_p->host) || match(given_host, target_p->sockhost))
+ ++count[!MyConnect(target_p)];
+ }
+
+ sendto_one(source_p, form_str(RPL_TESTMASK), me.name,
+ source_p->name,
+ given_nick, given_user,
+ given_host, count[0], count[1]);
+}
+
+static struct Message testmask_msgtab = {
+ "TESTMASK", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_not_oper, m_ignore, m_ignore, mo_testmask, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&testmask_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&testmask_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_time.c b/modules/m_time.c
new file mode 100644
index 0000000..14705c6
--- /dev/null
+++ b/modules/m_time.c
@@ -0,0 +1,99 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_time.c: Sends the current time on the 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 "numeric.h"
+#include "s_misc.h"
+#include "conf.h"
+#include "s_serv.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+#include "packet.h"
+
+
+/*
+ * m_time
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+static void
+m_time(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ /* this is not rate limited, so end the grace period */
+ if (!IsFloodDone(source_p))
+ flood_endgrace(source_p);
+
+ /* This is safe enough to use during non hidden server mode */
+ if (!ConfigFileEntry.disable_remote)
+ if (hunt_server(client_p, source_p, ":%s TIME :%s", 1, parc, parv) != HUNTED_ISME)
+ return;
+
+ sendto_one(source_p, form_str(RPL_TIME), me.name,
+ source_p->name, me.name, date(0));
+}
+
+/*
+ * mo_time
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+static void
+mo_time(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (hunt_server(client_p, source_p, ":%s TIME :%s", 1, parc, parv) == HUNTED_ISME)
+ sendto_one(source_p, form_str(RPL_TIME), me.name,
+ source_p->name, me.name, date(0));
+}
+
+static struct Message time_msgtab = {
+ "TIME", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_time, mo_time, m_ignore, mo_time, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&time_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&time_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_topic.c b/modules/m_topic.c
new file mode 100644
index 0000000..fe4faea
--- /dev/null
+++ b/modules/m_topic.c
@@ -0,0 +1,171 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_topic.c: Sets a channel topic.
+ *
+ * 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 "parse.h"
+#include "modules.h"
+#include "packet.h"
+
+
+/* m_topic()
+ * parv[0] = sender prefix
+ * parv[1] = channel name
+ * parv[2] = new topic, if setting topic
+ */
+static void
+m_topic(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Channel *chptr = NULL;
+ const char *from, *to;
+
+ if (!MyClient(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[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ from, to, "TOPIC");
+ return;
+ }
+
+ if (MyClient(source_p) && !IsFloodDone(source_p))
+ flood_endgrace(source_p);
+
+ if ((chptr = hash_find_channel(parv[1])) == NULL)
+ {
+ sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
+ from, to, parv[1]);
+ return;
+ }
+
+ /* setting topic */
+ if (parc > 2)
+ {
+ struct Membership *ms;
+
+ if ((ms = find_channel_link(source_p, chptr)) == NULL)
+ {
+ sendto_one(source_p, form_str(ERR_NOTONCHANNEL), from,
+ to, parv[1]);
+ return;
+ }
+
+ if (!(chptr->mode.mode & MODE_TOPICLIMIT) ||
+ has_member_flags(ms, CHFL_CHANOP|CHFL_HALFOP))
+ {
+ char topic_info[USERHOST_REPLYLEN];
+
+ snprintf(topic_info, sizeof(topic_info), "%s!%s@%s", source_p->name,
+ source_p->username, source_p->host);
+ set_channel_topic(chptr, parv[2], topic_info, CurrentTime);
+
+ sendto_server(client_p, CAP_TS6, NOCAPS,
+ ":%s TOPIC %s :%s",
+ ID(source_p), chptr->chname,
+ chptr->topic);
+ sendto_server(client_p, NOCAPS, CAP_TS6,
+ ":%s TOPIC %s :%s",
+ source_p->name, chptr->chname,
+ chptr->topic);
+ sendto_channel_local(ALL_MEMBERS, 0,
+ chptr, ":%s!%s@%s TOPIC %s :%s",
+ source_p->name,
+ source_p->username,
+ source_p->host,
+ chptr->chname, chptr->topic);
+ }
+ else
+ sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
+ from, to, chptr->chname);
+ }
+ else /* only asking for topic */
+ {
+ if (!SecretChannel(chptr) || IsMember(source_p, chptr))
+ {
+ if (chptr->topic[0] == '\0')
+ sendto_one(source_p, form_str(RPL_NOTOPIC),
+ from, to, chptr->chname);
+ else
+ {
+ sendto_one(source_p, form_str(RPL_TOPIC),
+ from, to,
+ chptr->chname, chptr->topic);
+ sendto_one(source_p, form_str(RPL_TOPICWHOTIME),
+ from, to, chptr->chname,
+ chptr->topic_info,
+ chptr->topic_time);
+ }
+ }
+ else
+ sendto_one(source_p, form_str(ERR_NOTONCHANNEL),
+ from, to, chptr->chname);
+ }
+}
+
+static struct Message topic_msgtab = {
+ "TOPIC", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_topic, m_topic, m_ignore, m_topic, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&topic_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&topic_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_trace.c b/modules/m_trace.c
new file mode 100644
index 0000000..910b390
--- /dev/null
+++ b/modules/m_trace.c
@@ -0,0 +1,448 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_trace.c: Traces a path to a client/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"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_bsd.h"
+#include "s_serv.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+#include "conf.h"
+
+
+static void do_actual_trace(struct Client *, int, char *[]);
+static void report_this_status(struct Client *, struct Client *, int);
+
+static void
+trace_get_dependent(int *const server,
+ int *const client, const struct Client *target_p)
+{
+ const dlink_node *ptr = NULL;
+
+ (*server)++;
+ (*client) += dlink_list_length(&target_p->serv->client_list);
+
+ DLINK_FOREACH(ptr, target_p->serv->server_list.head)
+ trace_get_dependent(server, client, ptr->data);
+}
+
+/*
+ * m_trace()
+ *
+ * parv[0] = sender prefix
+ * parv[1] = target client/server to trace
+ */
+static void
+m_trace(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ const char *tname;
+
+ if (parc > 1)
+ tname = parv[1];
+ else
+ tname = me.name;
+
+ sendto_one(source_p, form_str(RPL_ENDOFTRACE),
+ me.name, source_p->name, tname);
+}
+
+
+/* mo_trace()
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+static void
+mo_trace(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ dlink_node *ptr;
+ const char *tname;
+ const char *from, *to;
+
+ if (parc > 2)
+ if (hunt_server(client_p, source_p, ":%s TRACE %s :%s", 2, parc, parv))
+ return;
+
+ if (parc > 1)
+ tname = parv[1];
+ else
+ tname = me.name;
+
+ 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;
+ }
+
+ switch (hunt_server(client_p, source_p, ":%s TRACE :%s", 1, parc, parv))
+ {
+ case HUNTED_PASS: /* note: gets here only if parv[1] exists */
+ {
+ struct Client *ac2ptr = NULL;
+
+ if ((ac2ptr = hash_find_client(tname)) == NULL)
+ {
+ DLINK_FOREACH(ptr, global_client_list.head)
+ {
+ ac2ptr = ptr->data;
+
+ if (match(tname, ac2ptr->name))
+ break;
+ else
+ ac2ptr = NULL;
+ }
+ }
+
+ if (ac2ptr != NULL)
+ sendto_one(source_p, form_str(RPL_TRACELINK), from, to,
+ ircd_version, tname, ac2ptr->from->name);
+ else
+ sendto_one(source_p, form_str(RPL_TRACELINK), from, to,
+ ircd_version, tname, "ac2ptr_is_NULL!!");
+ return;
+ }
+
+ case HUNTED_ISME:
+ do_actual_trace(source_p, parc, parv);
+ break;
+ default:
+ return;
+ }
+}
+
+/*
+** ms_trace
+** parv[0] = sender prefix
+** parv[1] = servername
+*/
+static void
+ms_trace(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (hunt_server(client_p, source_p, ":%s TRACE %s :%s", 2, parc, parv))
+ return;
+
+ if (HasUMode(source_p, UMODE_OPER))
+ mo_trace(client_p, source_p, parc, parv);
+}
+
+static void
+do_actual_trace(struct Client *source_p, int parc, char *parv[])
+{
+ struct Client *target_p = NULL;
+ struct ConfItem *conf;
+ struct ClassItem *cltmp;
+ int doall = 0;
+ int wilds, dow;
+ dlink_node *ptr;
+ const char *from, *to, *tname;
+
+ if (parc > 1)
+ tname = parv[1];
+ else
+ tname = me.name;
+
+ 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;
+ }
+
+ sendto_realops_flags(UMODE_SPY, L_ALL,
+ "TRACE requested by %s (%s@%s) [%s]",
+ source_p->name, source_p->username,
+ source_p->host, source_p->servptr->name);
+
+ if (match(tname, me.name))
+ doall = 1;
+ else if (!MyClient(source_p) && !strcmp(tname, me.id))
+ {
+ doall = 1;
+ tname = me.name;
+ }
+
+ wilds = !parv[1] || has_wildcards(tname);
+ dow = wilds || doall;
+
+ set_time();
+ if (!HasUMode(source_p, UMODE_OPER) || !dow) /* non-oper traces must be full nicks */
+ /* lets also do this for opers tracing nicks */
+ {
+ const char *name;
+ const char *class_name;
+
+ target_p = hash_find_client(tname);
+
+ if (target_p && IsClient(target_p))
+ {
+ name = get_client_name(target_p, HIDE_IP);
+ class_name = get_client_class(target_p);
+
+ if (HasUMode(target_p, UMODE_OPER))
+ {
+ sendto_one(source_p, form_str(RPL_TRACEOPERATOR),
+ from, to, class_name, name,
+ IsIPSpoof(target_p) ? "255.255.255.255" : target_p->sockhost,
+ CurrentTime - target_p->localClient->lasttime,
+ CurrentTime - target_p->localClient->last_privmsg);
+ }
+ else
+ {
+ sendto_one(source_p,form_str(RPL_TRACEUSER),
+ from, to, class_name, name,
+ IsIPSpoof(target_p) ? "255.255.255.255" : target_p->sockhost,
+ CurrentTime - target_p->localClient->lasttime,
+ CurrentTime - target_p->localClient->last_privmsg);
+ }
+ }
+
+ sendto_one(source_p, form_str(RPL_ENDOFTRACE),
+ from, to, tname);
+ return;
+ }
+
+ /* report all direct connections */
+ DLINK_FOREACH(ptr, local_client_list.head)
+ {
+ target_p = ptr->data;
+
+ if (HasUMode(target_p, UMODE_INVISIBLE) && dow &&
+ !(MyConnect(source_p) && HasUMode(source_p, UMODE_OPER)) &&
+ !HasUMode(target_p, UMODE_OPER) && (target_p != source_p))
+ continue;
+ if (!doall && wilds && !match(tname, target_p->name))
+ continue;
+ if (!dow && irccmp(tname, target_p->name))
+ continue;
+
+ report_this_status(source_p, target_p, dow);
+ }
+
+ DLINK_FOREACH(ptr, serv_list.head)
+ {
+ target_p = ptr->data;
+
+ if (!doall && wilds && !match(tname, target_p->name))
+ continue;
+ if (!dow && irccmp(tname, target_p->name))
+ continue;
+
+ report_this_status(source_p, target_p, dow);
+ }
+
+ /* This section is to report the unknowns */
+ DLINK_FOREACH(ptr, unknown_list.head)
+ {
+ target_p = ptr->data;
+
+ if (!doall && wilds && !match(tname, target_p->name))
+ continue;
+ if (!dow && irccmp(tname, target_p->name))
+ continue;
+
+ report_this_status(source_p, target_p, dow);
+ }
+
+ DLINK_FOREACH(ptr, class_items.head)
+ {
+ conf = ptr->data;
+ cltmp = map_to_conf(conf);
+
+ if (cltmp->curr_user_count > 0)
+ sendto_one(source_p, form_str(RPL_TRACECLASS),
+ from, to, conf->name, cltmp->curr_user_count);
+ }
+
+ sendto_one(source_p, form_str(RPL_ENDOFTRACE), from, to, tname);
+}
+
+/* report_this_status()
+ *
+ * inputs - pointer to client to report to
+ * - pointer to client to report about
+ * output - counter of number of hits
+ * side effects - NONE
+ */
+static void
+report_this_status(struct Client *source_p, struct Client *target_p, int dow)
+{
+ const char *name;
+ const char *class_name;
+ const char *from, *to;
+
+ if (!MyConnect(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
+ {
+ from = me.id;
+ to = source_p->id;
+ }
+ else
+ {
+ from = me.name;
+ to = source_p->name;
+ }
+
+ name = get_client_name(target_p, HIDE_IP);
+ class_name = get_client_class(target_p);
+
+ set_time();
+
+ switch (target_p->status)
+ {
+ case STAT_CONNECTING:
+ sendto_one(source_p, form_str(RPL_TRACECONNECTING),
+ from, to, class_name,
+ HasUMode(source_p, UMODE_ADMIN) ? name : target_p->name);
+ break;
+ case STAT_HANDSHAKE:
+ sendto_one(source_p, form_str(RPL_TRACEHANDSHAKE),
+ from, to, class_name,
+ HasUMode(source_p, UMODE_ADMIN) ? name : target_p->name);
+ break;
+ case STAT_ME:
+ break;
+ case STAT_UNKNOWN:
+ /* added time -Taner */
+ sendto_one(source_p, form_str(RPL_TRACEUNKNOWN),
+ from, to, class_name, name, target_p->sockhost,
+ target_p->localClient->firsttime ? /* TBD: can't be 0 */
+ CurrentTime - target_p->localClient->firsttime : -1);
+ break;
+ case STAT_CLIENT:
+ /*
+ * Only opers see users if there is a wildcard
+ * but anyone can see all the opers.
+ */
+ if ((HasUMode(source_p, UMODE_OPER) &&
+ (MyClient(source_p) || !(dow && HasUMode(target_p, UMODE_INVISIBLE))))
+ || !dow || HasUMode(target_p, UMODE_OPER))
+ {
+ if (HasUMode(target_p, UMODE_ADMIN) && !ConfigFileEntry.hide_spoof_ips)
+ sendto_one(source_p, form_str(RPL_TRACEOPERATOR),
+ from, to, class_name, name,
+ HasUMode(source_p, UMODE_ADMIN) ? target_p->sockhost : "255.255.255.255",
+ CurrentTime - target_p->localClient->lasttime,
+ CurrentTime - target_p->localClient->last_privmsg);
+
+ else if (HasUMode(target_p, UMODE_OPER))
+ {
+ if (ConfigFileEntry.hide_spoof_ips)
+ sendto_one(source_p, form_str(RPL_TRACEOPERATOR),
+ from, to, class_name, name,
+ IsIPSpoof(target_p) ? "255.255.255.255" : target_p->sockhost,
+ CurrentTime - target_p->localClient->lasttime,
+ CurrentTime - target_p->localClient->last_privmsg);
+ else
+ sendto_one(source_p, form_str(RPL_TRACEOPERATOR),
+ from, to, class_name, name,
+ MyOper(source_p) ? target_p->sockhost :
+ (IsIPSpoof(target_p) ? "255.255.255.255" : target_p->sockhost),
+ CurrentTime - target_p->localClient->lasttime,
+ CurrentTime - target_p->localClient->last_privmsg);
+ }
+ else
+ {
+ if (ConfigFileEntry.hide_spoof_ips)
+ sendto_one(source_p, form_str(RPL_TRACEUSER),
+ from, to, class_name, name,
+ IsIPSpoof(target_p) ? "255.255.255.255" : target_p->sockhost,
+ CurrentTime - target_p->localClient->lasttime,
+ CurrentTime - target_p->localClient->last_privmsg);
+ else
+ sendto_one(source_p, form_str(RPL_TRACEUSER),
+ from, to, class_name, name,
+ MyOper(source_p) ? target_p->sockhost :
+ (IsIPSpoof(target_p) ? "255.255.255.255" : target_p->sockhost),
+ CurrentTime - target_p->localClient->lasttime,
+ CurrentTime - target_p->localClient->last_privmsg);
+ }
+ }
+ break;
+ case STAT_SERVER:
+ {
+ int clients = 0;
+ int servers = 0;
+
+ trace_get_dependent(&servers, &clients, target_p);
+
+ if (!HasUMode(source_p, UMODE_ADMIN))
+ name = get_client_name(target_p, MASK_IP);
+
+ sendto_one(source_p, form_str(RPL_TRACESERVER),
+ from, to, class_name, servers,
+ clients, name, *(target_p->serv->by) ?
+ target_p->serv->by : "*", "*",
+ me.name, CurrentTime - target_p->localClient->lasttime);
+ break;
+ }
+
+ default: /* ...we actually shouldn't come here... --msa */
+ sendto_one(source_p, form_str(RPL_TRACENEWTYPE),
+ from, to, name);
+ break;
+ }
+}
+
+static struct Message trace_msgtab = {
+ "TRACE", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_trace, ms_trace, m_ignore, mo_trace, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&trace_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&trace_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_user.c b/modules/m_user.c
new file mode 100644
index 0000000..9db36b4
--- /dev/null
+++ b/modules/m_user.c
@@ -0,0 +1,134 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_user.c: Sends username information.
+ *
+ * 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 "irc_string.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_user.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+#include "listener.h"
+
+
+/* do_local_user()
+ *
+ * inputs -
+ * output - NONE
+ * side effects -
+ */
+static void
+do_local_user(struct Client *source_p,
+ const char *username, const char *host, const char *server,
+ const char *realname)
+{
+ assert(source_p != NULL);
+ assert(source_p->username != username);
+ assert(IsUnknown(source_p));
+
+ source_p->localClient->registration &= ~REG_NEED_USER;
+
+ /*
+ * don't take the clients word for it, ever
+ */
+ source_p->servptr = &me;
+
+ strlcpy(source_p->info, realname, sizeof(source_p->info));
+
+ /* stash for later */
+ strlcpy(source_p->localClient->client_host, host, sizeof(source_p->localClient->client_host));
+ strlcpy(source_p->localClient->client_server, server, sizeof(source_p->localClient->client_server));
+
+ if (!IsGotId(source_p))
+ strlcpy(source_p->username, username, sizeof(source_p->username));
+
+ if (!source_p->localClient->registration)
+ register_local_user(source_p);
+}
+
+/*
+** mr_user
+** parv[0] = sender prefix
+** parv[1] = username (login name, account)
+** parv[2] = client host name (used only from other servers)
+** parv[3] = server host name (used only from other servers)
+** parv[4] = users real name info
+*/
+static void
+mr_user(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ char *p = NULL;
+
+ if (source_p->localClient->listener->flags & LISTENER_SERVER)
+ {
+ exit_client(source_p, &me, "Use a different port");
+ return;
+ }
+
+ if ((p = strchr(parv[1], '@')) != NULL)
+ *p = '\0';
+
+ if (EmptyString(parv[4]))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name,
+ source_p->name[0] ? source_p->name : "*", "USER");
+ return;
+ }
+
+ do_local_user(source_p,
+ parv[1], /* username */
+ parv[2], /* host */
+ parv[3], /* server */
+ parv[4] /* users real name */ );
+}
+
+static struct Message user_msgtab = {
+ "USER", 0, 0, 5, MAXPARA, MFLG_SLOW, 0,
+ { mr_user, m_registered, m_ignore, m_ignore, m_registered, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&user_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&user_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_userhost.c b/modules/m_userhost.c
new file mode 100644
index 0000000..81cddf6
--- /dev/null
+++ b/modules/m_userhost.c
@@ -0,0 +1,127 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_userhost.c: Shows a user's host.
+ *
+ * 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 "numeric.h"
+#include "s_serv.h"
+#include "send.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "parse.h"
+#include "modules.h"
+
+
+/*
+ * m_userhost added by Darren Reed 13/8/91 to aid clients and reduce
+ * the need for complicated requests like WHOIS. It returns user/host
+ * information only (no spurious AWAY labels or channels).
+ */
+static void
+m_userhost(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *target_p;
+ char buf[IRCD_BUFSIZE];
+ char response[NICKLEN*2+USERLEN+HOSTLEN+30];
+ char *t = NULL, *p = NULL, *nick = NULL;
+ int i = 0; /* loop counter */
+ int cur_len;
+ int rl;
+
+ cur_len = snprintf(buf, sizeof(buf), form_str(RPL_USERHOST), me.name, source_p->name, "");
+ t = buf + cur_len;
+
+ for (nick = strtoken(&p, parv[1], " "); nick && i++ < 5;
+ nick = strtoken(&p, NULL, " "))
+ {
+ if ((target_p = find_person(client_p, nick)) != NULL)
+ {
+ /*
+ * Show real IP for USERHOST on yourself.
+ * This is needed for things like mIRC, which do a server-based
+ * lookup (USERHOST) to figure out what the clients' local IP
+ * is. Useful for things like NAT, and dynamic dial-up users.
+ */
+ if (MyClient(target_p) && (target_p == source_p))
+ {
+ rl = ircsprintf(response, "%s%s=%c%s@%s ",
+ target_p->name,
+ HasUMode(target_p, UMODE_OPER) ? "*" : "",
+ (target_p->away[0]) ? '-' : '+',
+ target_p->username,
+ target_p->sockhost);
+ }
+ else
+ {
+ rl = ircsprintf(response, "%s%s=%c%s@%s ",
+ target_p->name, (HasUMode(target_p, UMODE_OPER) &&
+ (!HasUMode(target_p, UMODE_HIDDEN) ||
+ HasUMode(source_p, UMODE_OPER))) ? "*" : "",
+ (target_p->away[0]) ? '-' : '+',
+ target_p->username,
+ target_p->host);
+ }
+
+ if ((rl + cur_len) < (IRCD_BUFSIZE - 10))
+ {
+ ircsprintf(t, "%s", response);
+ t += rl;
+ cur_len += rl;
+ }
+ else
+ break;
+ }
+ }
+
+ sendto_one(source_p, "%s", buf);
+}
+
+static struct Message userhost_msgtab = {
+ "USERHOST", 0, 0, 1, 1, MFLG_SLOW, 0,
+ {m_unregistered, m_userhost, m_userhost, m_ignore, m_userhost, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&userhost_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&userhost_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_users.c b/modules/m_users.c
new file mode 100644
index 0000000..14ab296
--- /dev/null
+++ b/modules/m_users.c
@@ -0,0 +1,120 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_users.c: Gives some basic user statistics.
+ *
+ * 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 "numeric.h"
+#include "s_serv.h"
+#include "conf.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+
+
+/*
+ * m_users
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+static void
+m_users(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ static time_t last_used = 0;
+
+ if (last_used + ConfigFileEntry.pace_wait_simple > CurrentTime)
+ {
+ sendto_one(source_p, form_str(RPL_LOAD2HI),
+ me.name, source_p->name);
+ return;
+ }
+
+ last_used = CurrentTime;
+
+ if (!ConfigFileEntry.disable_remote)
+ if (hunt_server(client_p, source_p, ":%s USERS :%s", 1,
+ parc, parv) != HUNTED_ISME)
+ return;
+
+ sendto_one(source_p, form_str(RPL_LOCALUSERS), me.name, source_p->name,
+ ConfigServerHide.hide_servers ? Count.total : Count.local,
+ ConfigServerHide.hide_servers ? Count.max_tot : Count.max_loc,
+ ConfigServerHide.hide_servers ? Count.total : Count.local,
+ ConfigServerHide.hide_servers ? Count.max_tot : Count.max_loc);
+
+ sendto_one(source_p, form_str(RPL_GLOBALUSERS), me.name, source_p->name,
+ Count.total, Count.max_tot, Count.total, Count.max_tot);
+}
+
+/*
+ * mo_users
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+static void
+mo_users(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (hunt_server(client_p, source_p, ":%s USERS :%s", 1,
+ parc, parv) != HUNTED_ISME)
+ return;
+
+ if (!HasUMode(source_p, UMODE_OPER) && ConfigServerHide.hide_servers)
+ sendto_one(source_p, form_str(RPL_LOCALUSERS), me.name, source_p->name,
+ Count.total, Count.max_tot, Count.total, Count.max_tot);
+ else
+ sendto_one(source_p, form_str(RPL_LOCALUSERS), me.name, source_p->name,
+ Count.local, Count.max_loc, Count.local, Count.max_loc);
+
+ sendto_one(source_p, form_str(RPL_GLOBALUSERS), me.name, source_p->name,
+ Count.total, Count.max_tot, Count.total, Count.max_tot);
+}
+
+static struct Message users_msgtab = {
+ "USERS", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_users, mo_users, m_ignore, mo_users, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&users_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&users_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_version.c b/modules/m_version.c
new file mode 100644
index 0000000..5a9d9cc
--- /dev/null
+++ b/modules/m_version.c
@@ -0,0 +1,189 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_version.c: Shows ircd version information.
+ *
+ * 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 "numeric.h"
+#include "conf.h"
+#include "s_serv.h"
+#include "s_user.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+
+
+/* Option string. */
+static const char serveropts[] = {
+ ' ',
+ 'T',
+ 'S',
+#ifdef TS_CURRENT
+ '0' + TS_CURRENT,
+#endif
+/* ONLY do TS */
+/* ALWAYS do TS_WARNINGS */
+ 'o',
+ 'w',
+ '\0'
+};
+
+/* confopts()
+ *
+ * input - client pointer
+ * output - ircd.conf option string
+ * side effects - none
+ */
+static char *
+confopts(struct Client *source_p)
+{
+ static char result[12];
+ char *p = result;
+
+ *p++ = 'e'; /* excepts */
+
+ if (ConfigFileEntry.glines)
+ *p++ = 'G';
+ *p++ = 'g';
+
+ /* might wanna hide this :P */
+ if (ServerInfo.hub &&
+ (!ConfigFileEntry.disable_remote || HasUMode(source_p, UMODE_OPER)))
+ {
+ *p++ = 'H';
+ }
+
+ *p++ = 'I'; /* invex */
+ *p++ = 'K'; /* knock */
+ *p++ = 'M';
+
+ if (ConfigFileEntry.ignore_bogus_ts)
+ *p++ = 'T';
+ *p++ = '6';
+
+ *p = '\0';
+
+ return result;
+}
+
+/*
+ * m_version - VERSION command handler
+ * parv[0] = sender prefix
+ * parv[1] = remote server
+ */
+static void
+m_version(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ static time_t last_used = 0;
+
+ if ((last_used + ConfigFileEntry.pace_wait_simple) > CurrentTime)
+ {
+ /* safe enough to give this on a local connect only */
+ sendto_one(source_p, form_str(RPL_LOAD2HI),
+ me.name, source_p->name);
+ return;
+ }
+
+ last_used = CurrentTime;
+
+ if (!ConfigFileEntry.disable_remote)
+ if (hunt_server(client_p, source_p, ":%s VERSION :%s",
+ 1, parc, parv) != HUNTED_ISME)
+ return;
+
+ sendto_one(source_p, form_str(RPL_VERSION),
+ me.name, source_p->name, ircd_version, serno,
+ me.name, confopts(source_p), serveropts);
+ show_isupport(source_p);
+}
+
+/*
+ * mo_version - VERSION command handler
+ * parv[0] = sender prefix
+ * parv[1] = remote server
+ */
+static void
+mo_version(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+
+ if (hunt_server(client_p, source_p, ":%s VERSION :%s",
+ 1, parc, parv) != HUNTED_ISME)
+ return;
+
+ sendto_one(source_p, form_str(RPL_VERSION), me.name,
+ source_p->name, ircd_version,
+ serno, me.name, confopts(source_p), serveropts);
+
+ show_isupport(source_p);
+}
+
+/*
+ * ms_version - VERSION command handler
+ * parv[0] = sender prefix
+ * parv[1] = remote server
+ */
+static void
+ms_version(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (hunt_server(client_p, source_p, ":%s VERSION :%s",
+ 1, parc, parv) == HUNTED_ISME)
+ {
+ sendto_one(source_p, form_str(RPL_VERSION),
+ ID_or_name(&me, client_p),
+ ID_or_name(source_p, client_p),
+ ircd_version, serno,
+ me.name, confopts(source_p), serveropts);
+ show_isupport(source_p);
+ }
+}
+
+static struct Message version_msgtab = {
+ "VERSION", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_version, ms_version, m_ignore, mo_version, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&version_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&version_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_wallops.c b/modules/m_wallops.c
new file mode 100644
index 0000000..c05a56d
--- /dev/null
+++ b/modules/m_wallops.c
@@ -0,0 +1,112 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_wallops.c: Sends a message to all operators.
+ *
+ * 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 "s_user.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_serv.h"
+
+
+/*
+ * mo_wallops (write to *all* opers currently online)
+ * parv[0] = sender prefix
+ * parv[1] = message text
+ */
+static void
+mo_wallops(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ const char *message = parv[1];
+
+ if (EmptyString(message))
+ {
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, "WALLOPS");
+ return;
+ }
+
+ sendto_wallops_flags(UMODE_OPERWALL, source_p, "OPERWALL - %s", message);
+ sendto_server(NULL, CAP_TS6, NOCAPS,
+ ":%s WALLOPS :%s", ID(source_p), message);
+ sendto_server(NULL, NOCAPS, CAP_TS6,
+ ":%s WALLOPS :%s", source_p->name, message);
+}
+
+/*
+ * ms_wallops (write to *all* opers currently online)
+ * parv[0] = sender prefix
+ * parv[1] = message text
+ */
+static void
+ms_wallops(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ const char *message = parv[1];
+
+ if (EmptyString(message))
+ return;
+
+ if (IsClient(source_p))
+ sendto_wallops_flags(UMODE_OPERWALL, source_p, "OPERWALL - %s", message);
+ else
+ sendto_wallops_flags(UMODE_WALLOP, source_p, "%s", message);
+
+ sendto_server(client_p, CAP_TS6, NOCAPS,
+ ":%s WALLOPS :%s", ID(source_p), message);
+ sendto_server(client_p, NOCAPS, CAP_TS6,
+ ":%s WALLOPS :%s", source_p->name, message);
+}
+
+static struct Message wallops_msgtab = {
+ "WALLOPS", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_not_oper, ms_wallops, m_ignore, mo_wallops, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&wallops_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&wallops_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_watch.c b/modules/m_watch.c
new file mode 100644
index 0000000..8e952f1
--- /dev/null
+++ b/modules/m_watch.c
@@ -0,0 +1,269 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_watch.c: Maintains notify list
+ *
+ * Copyright (C) 1997 Jukka Santala (Donwulff)
+ * Copyright (C) 2005 by the Hybrid Development Team.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * $Id$
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "conf.h"
+#include "send.h"
+#include "parse.h"
+#include "modules.h"
+#include "s_user.h"
+#include "watch.h"
+
+
+/*
+ * RPL_NOWON - Online at the moment (Succesfully added to WATCH-list)
+ * RPL_NOWOFF - Offline at the moment (Succesfully added to WATCH-list)
+ * RPL_WATCHOFF - Succesfully removed from WATCH-list.
+ * ERR_TOOMANYWATCH - Take a guess :> Too many WATCH entries.
+ */
+static void
+show_watch(struct Client *client_p, const char *name,
+ unsigned int rpl1, unsigned int rpl2)
+{
+ const struct Client *target_p = NULL;
+
+ if ((target_p = find_person(client_p, name)))
+ sendto_one(client_p, form_str(rpl1), me.name, client_p->name,
+ target_p->name, target_p->username,
+ target_p->host, target_p->tsinfo);
+ else
+ sendto_one(client_p, form_str(rpl2), me.name, client_p->name,
+ name, "*", "*", 0);
+}
+
+/*
+ * m_watch()
+ *
+ * parv[0] = sender prefix
+ * parv[1] = watch options
+ */
+static void
+m_watch(struct Client *client_p, struct Client *source_p, int parc, char *parv[])
+{
+ dlink_node *ptr = NULL;
+ char *s = NULL;
+ char *p = NULL;
+ char *user;
+ char def[2] = "l";
+ unsigned int list_requested = 0;
+
+ /*
+ * Default to 'l' - list who's currently online
+ */
+ if (parc < 2)
+ parv[1] = def;
+
+ for (s = strtoken(&p, parv[1], ", "); s;
+ s = strtoken(&p, NULL, ", "))
+ {
+ if ((user = strchr(s, '!')))
+ *user++ = '\0'; /* Not used */
+
+ /*
+ * Prefix of "+", they want to add a name to their WATCH
+ * list.
+ */
+ if (*s == '+')
+ {
+ if (*(s + 1) != '\0')
+ {
+ if (dlink_list_length(&source_p->localClient->watches) >=
+ ConfigFileEntry.max_watch)
+ {
+ sendto_one(source_p, form_str(ERR_TOOMANYWATCH), me.name,
+ source_p->name, s + 1, ConfigFileEntry.max_watch);
+ continue;
+ }
+
+ watch_add_to_hash_table(s + 1, source_p);
+ }
+
+ show_watch(source_p, s + 1, RPL_NOWON, RPL_NOWOFF);
+ continue;
+ }
+
+ /*
+ * Prefix of "-", coward wants to remove somebody from their
+ * WATCH list. So do it. :-)
+ */
+ if (*s == '-')
+ {
+ watch_del_from_hash_table(s + 1, source_p);
+ show_watch(source_p, s + 1, RPL_WATCHOFF, RPL_WATCHOFF);
+ continue;
+ }
+
+ /*
+ * Fancy "C" or "c", they want to nuke their WATCH list and start
+ * over, so be it.
+ */
+ if (*s == 'C' || *s == 'c')
+ {
+ watch_del_watch_list(source_p);
+ continue;
+ }
+
+ /*
+ * Now comes the fun stuff, "S" or "s" returns a status report of
+ * their WATCH list. I imagine this could be CPU intensive if
+ * it's done alot, perhaps an auto-lag on this?
+ */
+ if (*s == 'S' || *s == 's')
+ {
+ char buf[IRCD_BUFSIZE] = { '\0' };
+ const struct Watch *anptr = NULL;
+ unsigned int count = 0;
+
+ if (list_requested & 0x1)
+ continue;
+
+ list_requested |= 0x1;
+
+ /*
+ * Send a list of how many users they have on their WATCH list
+ * and how many WATCH lists they are on.
+ */
+ if ((anptr = watch_find_hash(source_p->name)))
+ count = dlink_list_length(&anptr->watched_by);
+
+ sendto_one(source_p, form_str(RPL_WATCHSTAT),
+ me.name, source_p->name,
+ dlink_list_length(&source_p->localClient->watches), count);
+
+ /*
+ * Send a list of everybody in their WATCH list. Be careful
+ * not to buffer overflow.
+ */
+ if ((ptr = source_p->localClient->watches.head) == NULL)
+ {
+ sendto_one(source_p, form_str(RPL_ENDOFWATCHLIST),
+ me.name, source_p->name, *s);
+ continue;
+ }
+
+ anptr = ptr->data;
+ strlcpy(buf, anptr->nick, sizeof(buf));
+
+ count = strlen(source_p->name) + strlen(me.name) + 10 +
+ strlen(buf);
+
+ while ((ptr = ptr->next))
+ {
+ anptr = ptr->data;
+
+ if (count + strlen(anptr->nick) + 1 > IRCD_BUFSIZE - 2)
+ {
+ sendto_one(source_p, form_str(RPL_WATCHLIST),
+ me.name, source_p->name, buf);
+ buf[0] = '\0';
+ count = strlen(source_p->name) + strlen(me.name) + 10;
+ }
+
+ strcat(buf, " ");
+ strcat(buf, anptr->nick);
+ count += (strlen(anptr->nick) + 1);
+ }
+
+ sendto_one(source_p, form_str(RPL_WATCHLIST),
+ me.name, source_p->name, buf);
+ sendto_one(source_p, form_str(RPL_ENDOFWATCHLIST),
+ me.name, source_p->name, *s);
+ continue;
+ }
+
+ /*
+ * Well that was fun, NOT. Now they want a list of everybody in
+ * their WATCH list AND if they are online or offline? Sheesh,
+ * greedy aren't we?
+ */
+ if (*s == 'L' || *s == 'l')
+ {
+ const struct Client *target_p = NULL;
+
+ if (list_requested & 0x2)
+ continue;
+
+ list_requested |= 0x2;
+
+ DLINK_FOREACH(ptr, source_p->localClient->watches.head)
+ {
+ const struct Watch *anptr = ptr->data;
+
+ if ((target_p = find_person(source_p, anptr->nick)))
+ sendto_one(source_p, form_str(RPL_NOWON), me.name, source_p->name,
+ target_p->name, target_p->username,
+ target_p->host, target_p->tsinfo);
+ /*
+ * But actually, only show them offline if it's a capital
+ * 'L' (full list wanted).
+ */
+ else if (*s == 'L')
+ sendto_one(source_p, form_str(RPL_NOWOFF), me.name,
+ source_p->name, anptr->nick,
+ "*", "*", anptr->lasttime);
+ }
+
+ sendto_one(source_p, form_str(RPL_ENDOFWATCHLIST),
+ me.name, source_p->name, *s);
+ continue;
+ }
+
+ /* Hmm.. unknown prefix character.. Ignore it. :-) */
+ }
+}
+
+static struct Message watch_msgtab = {
+ "WATCH", 0, 0, 0, 1, MFLG_SLOW, 0,
+ { m_unregistered, m_watch, m_ignore, m_ignore, m_watch, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&watch_msgtab);
+ add_isupport("WATCH", NULL, ConfigFileEntry.max_watch);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&watch_msgtab);
+ delete_isupport("WATCH");
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_who.c b/modules/m_who.c
new file mode 100644
index 0000000..fa20fcd
--- /dev/null
+++ b/modules/m_who.c
@@ -0,0 +1,368 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_who.c: Shows who is on 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 "client.h"
+#include "channel.h"
+#include "channel_mode.h"
+#include "hash.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_serv.h"
+#include "send.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "conf.h"
+#include "parse.h"
+#include "modules.h"
+
+static void who_global(struct Client *, char *, int);
+static void do_who(struct Client *, struct Client *,
+ const char *, const char *);
+static void do_who_on_channel(struct Client *, struct Channel *,
+ const char *, int, int);
+
+/*
+** m_who
+** parv[0] = sender prefix
+** parv[1] = nickname mask list
+** parv[2] = additional selection flag, only 'o' for now.
+*/
+static void
+m_who(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ struct Client *target_p;
+ char *mask = parv[1];
+ dlink_node *lp;
+ int server_oper = parc > 2 ? (*parv[2] == 'o') : 0; /* Show OPERS only */
+ struct Channel *chptr;
+
+ /* See if mask is there, collapse it or return if not there */
+ if (EmptyString(mask))
+ {
+ who_global(source_p, mask, server_oper);
+ sendto_one(source_p, form_str(RPL_ENDOFWHO),
+ me.name, source_p->name, "*");
+ return;
+ }
+
+ /* mask isn't NULL at this point. repeat after me... -db */
+ collapse(mask);
+
+ /* '/who *' */
+ if (!strcmp(mask, "*"))
+ {
+ if ((lp = source_p->channel.head) != NULL)
+ {
+ struct Channel *mychannel = ((struct Membership *)lp->data)->chptr;
+ do_who_on_channel(source_p, mychannel, mychannel->chname, 1,
+ server_oper);
+ }
+
+ sendto_one(source_p, form_str(RPL_ENDOFWHO),
+ me.name, source_p->name, "*");
+ return;
+ }
+
+ /* '/who #some_channel' */
+ if (IsChanPrefix(*mask))
+ {
+ /* List all users on a given channel */
+ if ((chptr = hash_find_channel(mask)) != NULL)
+ {
+ if (IsMember(source_p, chptr))
+ do_who_on_channel(source_p, chptr, chptr->chname, 1, server_oper);
+ else if (!SecretChannel(chptr))
+ do_who_on_channel(source_p, chptr, chptr->chname, 0, server_oper);
+ }
+
+ sendto_one(source_p, form_str(RPL_ENDOFWHO),
+ me.name, source_p->name, mask);
+ return;
+ }
+
+ /* '/who nick' */
+ if (((target_p = hash_find_client(mask)) != NULL) &&
+ IsClient(target_p) && (!server_oper || HasUMode(target_p, UMODE_OPER)))
+ {
+ DLINK_FOREACH(lp, target_p->channel.head)
+ {
+ chptr = ((struct Membership *) lp->data)->chptr;
+ if (PubChannel(chptr) || IsMember(source_p, chptr))
+ break;
+ }
+
+ if (lp != NULL)
+ do_who(source_p, target_p, chptr->chname,
+ get_member_status(lp->data, !!HasCap(source_p, CAP_MULTI_PREFIX)));
+ else
+ do_who(source_p, target_p, NULL, "");
+
+ sendto_one(source_p, form_str(RPL_ENDOFWHO),
+ me.name, source_p->name, mask);
+ return;
+ }
+
+ /* '/who 0' */
+ if (!strcmp(mask, "0"))
+ who_global(source_p, NULL, server_oper);
+ else
+ who_global(source_p, mask, server_oper);
+
+ /* Wasn't a nick, wasn't a channel, wasn't a '*' so ... */
+ sendto_one(source_p, form_str(RPL_ENDOFWHO),
+ me.name, source_p->name, mask);
+}
+
+/* who_common_channel
+ * inputs - pointer to client requesting who
+ * - pointer to channel member chain.
+ * - char * mask to match
+ * - int if oper on a server or not
+ * - pointer to int maxmatches
+ * output - NONE
+ * side effects - lists matching clients on specified channel,
+ * marks matched clients.
+ *
+ */
+static void
+who_common_channel(struct Client *source_p, struct Channel *chptr,
+ char *mask, int server_oper, int *maxmatches)
+{
+ dlink_node *ptr = NULL;
+
+ DLINK_FOREACH(ptr, chptr->members.head)
+ {
+ struct Client *target_p = ((struct Membership *)ptr->data)->client_p;
+
+ if (!HasUMode(target_p, UMODE_INVISIBLE) || HasFlag(target_p, FLAGS_MARK))
+ continue;
+
+ if (server_oper)
+ if (!HasUMode(target_p, UMODE_OPER) ||
+ (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER)))
+ continue;
+
+ AddFlag(target_p, FLAGS_MARK);
+
+ assert(target_p->servptr != NULL);
+
+ if ((mask == NULL) ||
+ match(mask, target_p->name) || match(mask, target_p->username) ||
+ match(mask, target_p->host) ||
+ ((!ConfigServerHide.hide_servers || HasUMode(source_p, UMODE_OPER)) &&
+ match(mask, target_p->servptr->name)) ||
+ match(mask, target_p->info))
+ {
+ do_who(source_p, target_p, NULL, "");
+
+ if (*maxmatches > 0)
+ {
+ if (--(*maxmatches) == 0)
+ return;
+ }
+ }
+ }
+}
+
+/* who_global()
+ *
+ * inputs - pointer to client requesting who
+ * - char * mask to match
+ * - int if oper on a server or not
+ * output - NONE
+ * side effects - do a global scan of all clients looking for match
+ * this is slightly expensive on EFnet ...
+ */
+static void
+who_global(struct Client *source_p, char *mask, int server_oper)
+{
+ struct Channel *chptr;
+ struct Client *target_p;
+ dlink_node *lp;
+ dlink_node *lp_next;
+ dlink_node *gcptr;
+ dlink_node *gcptr_next;
+ int maxmatches = 500;
+ static time_t last_used = 0;
+
+ if (!HasUMode(source_p, UMODE_OPER))
+ {
+ if ((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
+ {
+ /* safe enough to give this on a local connect only */
+ sendto_one(source_p, form_str(RPL_LOAD2HI), me.name, source_p->name);
+ return;
+ }
+
+ last_used = CurrentTime;
+ }
+
+ /* first, list all matching invisible clients on common channels */
+ DLINK_FOREACH_SAFE(lp, lp_next, source_p->channel.head)
+ {
+ chptr = ((struct Membership *)lp->data)->chptr;
+ who_common_channel(source_p, chptr, mask, server_oper, &maxmatches);
+ }
+
+ /* second, list all matching visible clients */
+ DLINK_FOREACH_SAFE(gcptr, gcptr_next, global_client_list.head)
+ {
+ target_p = gcptr->data;
+
+ if (!IsClient(target_p))
+ continue;
+
+ if (HasUMode(target_p, UMODE_INVISIBLE))
+ {
+ DelFlag(target_p, FLAGS_MARK);
+ continue;
+ }
+
+ if (server_oper)
+ if (!HasUMode(target_p, UMODE_OPER) ||
+ (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER)))
+ continue;
+
+ assert(target_p->servptr != NULL);
+
+ if (!mask ||
+ match(mask, target_p->name) || match(mask, target_p->username) ||
+ match(mask, target_p->host) || match(mask, target_p->servptr->name) ||
+ match(mask, target_p->info))
+ {
+ do_who(source_p, target_p, NULL, "");
+
+ if (maxmatches > 0)
+ {
+ if (--maxmatches == 0)
+ return;
+ }
+ }
+ }
+}
+
+/* do_who_on_channel()
+ *
+ * inputs - pointer to client requesting who
+ * - pointer to channel to do who on
+ * - The "real name" of this channel
+ * - int if source_p is a server oper or not
+ * - int if client is member or not
+ * - int server_op flag
+ * output - NONE
+ * side effects - do a who on given channel
+ */
+static void
+do_who_on_channel(struct Client *source_p, struct Channel *chptr,
+ const char *chname, int member, int server_oper)
+{
+ dlink_node *ptr = NULL, *ptr_next = NULL;
+ struct Client *target_p;
+ struct Membership *ms;
+
+ DLINK_FOREACH_SAFE(ptr, ptr_next, chptr->members.head)
+ {
+ ms = ptr->data;
+ target_p = ms->client_p;
+
+ if (member || !HasUMode(target_p, UMODE_INVISIBLE))
+ {
+ if (server_oper)
+ if (!HasUMode(target_p, UMODE_OPER) ||
+ (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER)))
+ continue;
+ do_who(source_p, target_p, chname, get_member_status(ms, !!HasCap(source_p, CAP_MULTI_PREFIX)));
+ }
+ }
+}
+
+/* do_who()
+ *
+ * inputs - pointer to client requesting who
+ * - pointer to client to do who on
+ * - The reported name
+ * - channel flags
+ * output - NONE
+ * side effects - do a who on given person
+ */
+static void
+do_who(struct Client *source_p, struct Client *target_p,
+ const char *chname, const char *op_flags)
+{
+ char status[7]; /* G*@%+\0 */
+
+ if (HasUMode(source_p, UMODE_OPER))
+ snprintf(status, sizeof(status), "%c%s%s", target_p->away[0] ? 'G' : 'H',
+ HasUMode(target_p, UMODE_OPER) ? "*" : "", op_flags);
+ else
+ snprintf(status, sizeof(status), "%c%s%s", target_p->away[0] ? 'G' : 'H',
+ HasUMode(target_p, UMODE_OPER) &&
+ !HasUMode(target_p, UMODE_HIDDEN) ? "*" : "", op_flags);
+
+ if (ConfigServerHide.hide_servers)
+ {
+ sendto_one(source_p, form_str(RPL_WHOREPLY), me.name, source_p->name,
+ (chname) ? (chname) : "*",
+ target_p->username, target_p->host,
+ HasUMode(source_p, UMODE_OPER) ? target_p->servptr->name : "*",
+ target_p->name, status, 0, target_p->info);
+ }
+ else
+ {
+ sendto_one(source_p, form_str(RPL_WHOREPLY), me.name, source_p->name,
+ (chname) ? (chname) : "*", target_p->username,
+ target_p->host, target_p->servptr->name, target_p->name,
+ status, target_p->hopcount, target_p->info);
+ }
+}
+
+static struct Message who_msgtab = {
+ "WHO", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
+ {m_unregistered, m_who, m_ignore, m_ignore, m_who, m_ignore}
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&who_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&who_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_whois.c b/modules/m_whois.c
new file mode 100644
index 0000000..682fc10
--- /dev/null
+++ b/modules/m_whois.c
@@ -0,0 +1,421 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_whois.c: Shows who a user is.
+ *
+ * Copyright (C) 2005 by the past and present ircd coders, and others.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * $Id$
+ */
+
+#include "stdinc.h"
+#include "list.h"
+#include "client.h"
+#include "hash.h"
+#include "channel.h"
+#include "channel_mode.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "conf.h"
+#include "s_misc.h"
+#include "s_serv.h"
+#include "send.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "parse.h"
+#include "modules.h"
+
+
+static void do_whois(struct Client *, int, char *[]);
+static int single_whois(struct Client *, struct Client *);
+static void whois_person(struct Client *, struct Client *);
+static int global_whois(struct Client *, const char *);
+
+
+/*
+** m_whois
+** parv[0] = sender prefix
+** parv[1] = nickname masklist
+*/
+static void
+m_whois(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ static time_t last_used = 0;
+
+ if (parc < 2 || EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN),
+ me.name, source_p->name);
+ return;
+ }
+
+ if (parc > 2 && !EmptyString(parv[2]))
+ {
+ /* seeing as this is going across servers, we should limit it */
+ if ((last_used + ConfigFileEntry.pace_wait_simple) > CurrentTime)
+ {
+ sendto_one(source_p, form_str(RPL_LOAD2HI),
+ me.name, source_p->name);
+ return;
+ }
+
+ last_used = CurrentTime;
+
+ /* if we have serverhide enabled, they can either ask the clients
+ * server, or our server.. I dont see why they would need to ask
+ * anything else for info about the client.. --fl_
+ */
+ if (ConfigFileEntry.disable_remote)
+ parv[1] = parv[2];
+
+ if (hunt_server(client_p, source_p, ":%s WHOIS %s :%s", 1,
+ parc, parv) != HUNTED_ISME)
+ return;
+
+ parv[1] = parv[2];
+ }
+
+ do_whois(source_p, parc, parv);
+}
+
+/*
+** mo_whois
+** parv[0] = sender prefix
+** parv[1] = nickname masklist
+*/
+static void
+mo_whois(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (parc < 2 || EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN),
+ me.name, source_p->name);
+ return;
+ }
+
+ if (parc > 2 && !EmptyString(parv[2]))
+ {
+ if (hunt_server(client_p, source_p, ":%s WHOIS %s :%s", 1,
+ parc, parv) != HUNTED_ISME)
+ return;
+
+ parv[1] = parv[2];
+ }
+
+ do_whois(source_p, parc, parv);
+}
+
+/* do_whois()
+ *
+ * inputs - pointer to /whois source
+ * - number of parameters
+ * - pointer to parameters array
+ * output - pointer to void
+ * side effects - Does whois
+ */
+static void
+do_whois(struct Client *source_p, int parc, char *parv[])
+{
+ static time_t last_used = 0;
+ struct Client *target_p;
+ char *nick;
+ char *p = NULL;
+ int found = 0;
+
+ nick = parv[1];
+ while (*nick == ',')
+ nick++;
+ if ((p = strchr(nick,',')) != NULL)
+ *p = '\0';
+
+ if (*nick == '\0')
+ return;
+
+ collapse(nick);
+
+ if (strpbrk(nick, "?#*") == NULL)
+ {
+ if ((target_p = hash_find_client(nick)) != NULL)
+ {
+ if (IsClient(target_p))
+ {
+ whois_person(source_p, target_p);
+ found = 1;
+ }
+ }
+ }
+ else /* wilds is true */
+ {
+ if (!HasUMode(source_p, UMODE_OPER))
+ {
+ if ((last_used + ConfigFileEntry.pace_wait_simple) > CurrentTime)
+ {
+ sendto_one(source_p, form_str(RPL_LOAD2HI),
+ me.name, source_p->name);
+ return;
+ }
+ else
+ last_used = CurrentTime;
+ }
+
+ /* Oh-oh wilds is true so have to do it the hard expensive way */
+ if (MyClient(source_p))
+ found = global_whois(source_p, nick);
+ }
+
+ if (!found)
+ {
+ if (!IsDigit(*nick))
+ sendto_one(source_p, form_str(ERR_NOSUCHNICK),
+ me.name, source_p->name, nick);
+ }
+
+ sendto_one(source_p, form_str(RPL_ENDOFWHOIS),
+ me.name, source_p->name, parv[1]);
+}
+
+/* global_whois()
+ *
+ * Inputs - source_p client to report to
+ * - target_p client to report on
+ * Output - if found return 1
+ * Side Effects - do a single whois on given client
+ * writing results to source_p
+ */
+static int
+global_whois(struct Client *source_p, const char *nick)
+{
+ dlink_node *ptr;
+ struct Client *target_p;
+ int found = 0;
+
+ DLINK_FOREACH(ptr, global_client_list.head)
+ {
+ target_p = ptr->data;
+
+ if (!IsClient(target_p))
+ continue;
+
+ if (!match(nick, target_p->name))
+ continue;
+
+ assert(target_p->servptr != NULL);
+
+ /* 'Rules' established for sending a WHOIS reply:
+ *
+ *
+ * - if wildcards are being used dont send a reply if
+ * the querier isnt any common channels and the
+ * client in question is invisible and wildcards are
+ * in use (allow exact matches only);
+ *
+ * - only send replies about common or public channels
+ * the target user(s) are on;
+ */
+
+ found |= single_whois(source_p, target_p);
+ }
+
+ return found;
+}
+
+/* single_whois()
+ *
+ * Inputs - source_p client to report to
+ * - target_p client to report on
+ * Output - if found return 1
+ * Side Effects - do a single whois on given client
+ * writing results to source_p
+ */
+static int
+single_whois(struct Client *source_p, struct Client *target_p)
+{
+ dlink_node *ptr = NULL;
+
+ if (!HasUMode(target_p, UMODE_INVISIBLE) || target_p == source_p)
+ {
+ /* always show user if they are visible (no +i) */
+ whois_person(source_p, target_p);
+ return 1;
+ }
+
+ /* target_p is +i. Check if it is on any common channels with source_p */
+ DLINK_FOREACH(ptr, target_p->channel.head)
+ {
+ struct Channel *chptr = ((struct Membership *) ptr->data)->chptr;
+
+ if (IsMember(source_p, chptr))
+ {
+ whois_person(source_p, target_p);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* whois_person()
+ *
+ * inputs - source_p client to report to
+ * - target_p client to report on
+ * output - NONE
+ * side effects -
+ */
+static void
+whois_person(struct Client *source_p, struct Client *target_p)
+{
+ char buf[IRCD_BUFSIZE];
+ dlink_node *lp;
+ struct Client *server_p;
+ struct Channel *chptr;
+ struct Membership *ms;
+ int cur_len = 0;
+ int mlen;
+ char *t = NULL;
+ int tlen;
+ int reply_to_send = 0;
+ int show_ip = 0;
+
+ server_p = target_p->servptr;
+
+ sendto_one(source_p, form_str(RPL_WHOISUSER),
+ me.name, source_p->name, target_p->name,
+ target_p->username, target_p->host, target_p->info);
+
+ cur_len = mlen = snprintf(buf, sizeof(buf), form_str(RPL_WHOISCHANNELS),
+ me.name, source_p->name, target_p->name, "");
+ t = buf + mlen;
+
+ DLINK_FOREACH(lp, target_p->channel.head)
+ {
+ ms = lp->data;
+ chptr = ms->chptr;
+
+ if (ShowChannel(source_p, chptr))
+ {
+ if ((cur_len + 3 + strlen(chptr->chname) + 1) > (IRCD_BUFSIZE - 2))
+ {
+ *(t - 1) = '\0';
+ sendto_one(source_p, "%s", buf);
+ cur_len = mlen;
+ t = buf + mlen;
+ }
+
+ tlen = ircsprintf(t, "%s%s ", get_member_status(ms, 1), chptr->chname);
+ t += tlen;
+ cur_len += tlen;
+ reply_to_send = 1;
+ }
+ }
+
+ if (reply_to_send)
+ {
+ *(t - 1) = '\0';
+ sendto_one(source_p, "%s", buf);
+ }
+
+ if (HasUMode(source_p, UMODE_OPER) || !ConfigServerHide.hide_servers || target_p == source_p)
+ sendto_one(source_p, form_str(RPL_WHOISSERVER),
+ me.name, source_p->name, target_p->name,
+ server_p->name, server_p->info);
+ else
+ sendto_one(source_p, form_str(RPL_WHOISSERVER),
+ me.name, source_p->name, target_p->name,
+ ConfigServerHide.hidden_name,
+ ServerInfo.network_desc);
+
+ if (HasUMode(target_p, UMODE_REGISTERED))
+ sendto_one(source_p, form_str(RPL_WHOISREGNICK),
+ me.name, source_p->name, target_p->name);
+
+ if (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_CALLERID) && !HasUMode(target_p, UMODE_SOFTCALLERID))
+ sendto_one(source_p, form_str(RPL_TARGUMODEG),
+ me.name, source_p->name, target_p->name);
+
+ if (HasUMode(target_p, UMODE_OPER))
+ if (!HasUMode(target_p, UMODE_HIDDEN) || HasUMode(source_p, UMODE_OPER))
+ sendto_one(source_p, form_str(HasUMode(target_p, UMODE_ADMIN) ? RPL_WHOISADMIN :
+ RPL_WHOISOPERATOR),
+ me.name, source_p->name, target_p->name);
+
+ if (strcmp(target_p->sockhost, "0"))
+ {
+ if (HasUMode(source_p, UMODE_ADMIN) || source_p == target_p)
+ show_ip = 1;
+ else if (IsIPSpoof(target_p))
+ show_ip = (HasUMode(source_p, UMODE_OPER) && !ConfigFileEntry.hide_spoof_ips);
+ else
+ show_ip = 1;
+
+ sendto_one(source_p, form_str(RPL_WHOISACTUALLY),
+ me.name, source_p->name, target_p->name,
+ show_ip ? target_p->sockhost : "255.255.255.255");
+ }
+
+ if (MyConnect(target_p)) /* Can't do any of this if not local! db */
+ {
+#ifdef HAVE_LIBCRYPTO
+ if (target_p->localClient->fd.ssl)
+ sendto_one(source_p, form_str(RPL_WHOISSECURE),
+ me.name, source_p->name, target_p->name);
+#endif
+ sendto_one(source_p, form_str(RPL_WHOISIDLE),
+ me.name, source_p->name, target_p->name,
+ CurrentTime - target_p->localClient->last_privmsg,
+ target_p->localClient->firsttime);
+
+ if (HasUMode(target_p, UMODE_OPER) && target_p != source_p)
+ if (HasUMode(target_p, UMODE_SPY))
+ sendto_one(target_p, ":%s NOTICE %s :*** Notice -- %s (%s@%s) [%s] is doing "
+ "a whois on you", me.name, target_p->name, source_p->name,
+ source_p->username, source_p->host, source_p->servptr->name);
+ }
+}
+
+static struct Message whois_msgtab = {
+ "WHOIS", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_whois, mo_whois, m_ignore, mo_whois, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&whois_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&whois_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_whowas.c b/modules/m_whowas.c
new file mode 100644
index 0000000..2f6da27
--- /dev/null
+++ b/modules/m_whowas.c
@@ -0,0 +1,175 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_whois.c: Shows who a user was.
+ *
+ * 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 "whowas.h"
+#include "client.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "ircd.h"
+#include "ircd_defs.h"
+#include "numeric.h"
+#include "s_serv.h"
+#include "s_user.h"
+#include "send.h"
+#include "conf.h"
+#include "parse.h"
+#include "modules.h"
+
+
+static void
+whowas_do(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ int cur = 0;
+ int max = -1;
+ char *p = NULL, *nick = NULL;
+ const dlink_node *ptr = NULL;
+
+ if (parc > 2)
+ {
+ max = atoi(parv[2]);
+
+ if (!MyConnect(source_p) && max > 20)
+ max = 20;
+ }
+
+ if (parc > 3)
+ if (hunt_server(client_p, source_p, ":%s WHOWAS %s %s :%s", 3,
+ parc, parv) != HUNTED_ISME)
+ return;
+
+ nick = parv[1];
+ while (*nick == ',')
+ nick++;
+ if ((p = strchr(nick,',')) != NULL)
+ *p = '\0';
+ if (*nick == '\0')
+ return;
+
+ DLINK_FOREACH(ptr, WHOWASHASH[strhash(nick)].head)
+ {
+ const struct Whowas *temp = ptr->data;
+
+ if (!irccmp(nick, temp->name))
+ {
+ sendto_one(source_p, form_str(RPL_WHOWASUSER),
+ me.name, source_p->name, temp->name,
+ temp->username, temp->hostname,
+ temp->realname);
+
+ if (ConfigServerHide.hide_servers && !HasUMode(source_p, UMODE_OPER))
+ sendto_one(source_p, form_str(RPL_WHOISSERVER),
+ me.name, source_p->name, temp->name,
+ ServerInfo.network_name, myctime(temp->logoff));
+ else
+ sendto_one(source_p, form_str(RPL_WHOISSERVER),
+ me.name, source_p->name, temp->name,
+ temp->servername, myctime(temp->logoff));
+ ++cur;
+ }
+
+ if (max > 0 && cur >= max)
+ break;
+ }
+
+ if (!cur)
+ sendto_one(source_p, form_str(ERR_WASNOSUCHNICK),
+ me.name, source_p->name, nick);
+
+ sendto_one(source_p, form_str(RPL_ENDOFWHOWAS),
+ me.name, source_p->name, parv[1]);
+}
+
+/*
+** m_whowas
+** parv[0] = sender prefix
+** parv[1] = nickname queried
+*/
+static void
+m_whowas(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ static time_t last_used = 0;
+
+ if (parc < 2 || EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN),
+ me.name, source_p->name);
+ return;
+ }
+
+ if ((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
+ {
+ sendto_one(source_p,form_str(RPL_LOAD2HI),
+ me.name, source_p->name);
+ return;
+ }
+
+ last_used = CurrentTime;
+
+ whowas_do(client_p, source_p, parc, parv);
+}
+
+static void
+mo_whowas(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (parc < 2 || EmptyString(parv[1]))
+ {
+ sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN),
+ me.name, source_p->name);
+ return;
+ }
+
+ whowas_do(client_p, source_p, parc, parv);
+}
+
+static struct Message whowas_msgtab = {
+ "WHOWAS", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_whowas, mo_whowas, m_ignore, mo_whowas, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&whowas_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&whowas_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};
diff --git a/modules/m_xline.c b/modules/m_xline.c
new file mode 100644
index 0000000..3a70299
--- /dev/null
+++ b/modules/m_xline.c
@@ -0,0 +1,467 @@
+/*
+ * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ * m_xline.c: xlines an 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 "channel.h"
+#include "client.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "hostmask.h"
+#include "numeric.h"
+#include "fdlist.h"
+#include "s_bsd.h"
+#include "conf.h"
+#include "log.h"
+#include "s_misc.h"
+#include "send.h"
+#include "hash.h"
+#include "s_serv.h"
+#include "parse.h"
+#include "modules.h"
+#include "resv.h"
+
+
+static int valid_xline(struct Client *, char *, char *, int);
+static void write_xline(struct Client *, char *, char *, time_t);
+static void remove_xline(struct Client *, char *);
+static int remove_txline_match(const char *);
+
+static void relay_xline(struct Client *, char *[]);
+
+/* mo_xline()
+ *
+ * inputs - pointer to server
+ * - pointer to client
+ * - parameter count
+ * - parameter list
+ * output -
+ * side effects - x line is added
+ *
+ */
+static void
+mo_xline(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ char *reason = NULL;
+ char *gecos = NULL;
+ struct ConfItem *conf = NULL;
+ struct MatchItem *match_item = NULL;
+ char *target_server = NULL;
+ time_t tkline_time = 0;
+
+ if (!HasOFlag(source_p, OPER_FLAG_X))
+ {
+ sendto_one(source_p, form_str(ERR_NOPRIVS),
+ me.name, source_p->name, "xline");
+ return;
+ }
+
+ /*
+ * XLINE <gecos> <time> ON <mask> :<reason>
+ * XLINE <gecos> ON <mask> :<reason>
+ */
+ if (parse_aline("XLINE", source_p, parc, parv, AWILD, &gecos, NULL,
+ &tkline_time, &target_server, &reason) < 0)
+ return;
+
+ if (target_server != NULL)
+ {
+ /* if a given expire time is given, ENCAP it */
+ if (tkline_time != 0)
+ sendto_match_servs(source_p, target_server, CAP_ENCAP,
+ "ENCAP %s XLINE %d %s 0 :%s",
+ target_server, (int)tkline_time, gecos, reason);
+ else
+ sendto_match_servs(source_p, target_server, CAP_CLUSTER,
+ "XLINE %s %s %d :%s",
+ target_server, gecos, (int)tkline_time, reason);
+
+ /* Allow ON to apply local xline as well if it matches */
+ if (!match(target_server, me.name))
+ return;
+ }
+ else
+ {
+ if (tkline_time != 0)
+ cluster_a_line(source_p, "ENCAP", CAP_ENCAP, SHARED_XLINE,
+ "XLINE %d %s 0 :%s", (int)tkline_time, gecos, reason);
+ else
+ cluster_a_line(source_p, "XLINE", CAP_KLN, SHARED_XLINE,
+ "%s 0 :%s", gecos, reason);
+ }
+
+ if (!valid_xline(source_p, gecos, reason, 0))
+ return;
+
+ if ((conf = find_matching_name_conf(XLINE_TYPE, gecos,
+ NULL, NULL, 0)) != NULL)
+ {
+ match_item = map_to_conf(conf);
+
+ sendto_one(source_p, ":%s NOTICE %s :[%s] already X-Lined by [%s] - %s",
+ me.name, source_p->name, gecos,
+ conf->name, match_item->reason);
+ return;
+ }
+
+ write_xline(source_p, gecos, reason, tkline_time);
+}
+
+/* ms_xline()
+ *
+ * inputs - oper, target server, xline, {type}, reason
+ * deprecate {type} reserve for temp xlines later? XXX
+ *
+ * outputs - none
+ * side effects - propagates xline, applies it if we are a target
+ */
+static void
+ms_xline(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (parc != 5 || EmptyString(parv[4]))
+ return;
+
+ if (!IsClient(source_p))
+ return;
+
+ if (!valid_xline(source_p, parv[2], parv[4], 0))
+ return;
+
+ relay_xline(source_p, parv);
+}
+
+/* me_xline()
+ *
+ * inputs - server
+ * - client (oper)
+ * - parc number of arguments
+ * - parv list of arguments
+ * via parv[]
+ * parv[1] = target
+ * parv[2] = server
+ * parv[3] = xline
+ * parv[4] = time
+ * parv[5] = reason
+ *
+ * outputs - none
+ * side effects -
+ */
+static void
+me_xline(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (!IsClient(source_p) || parc != 5)
+ return;
+
+ relay_xline(source_p, parv);
+}
+
+static void
+relay_xline(struct Client *source_p, char *parv[])
+{
+ struct ConfItem *conf;
+ struct MatchItem *match_item;
+ int t_sec;
+
+ t_sec = atoi(parv[3]);
+ /* XXX kludge! */
+ if (t_sec < 3)
+ t_sec = 0;
+
+ sendto_match_servs(source_p, parv[1], CAP_CLUSTER,
+ "XLINE %s %s %s :%s",
+ parv[1], parv[2], parv[3], parv[4]);
+
+ if (!match(parv[1], me.name))
+ return;
+
+ if (HasFlag(source_p, FLAGS_SERVICE) || find_matching_name_conf(ULINE_TYPE, source_p->servptr->name,
+ source_p->username, source_p->host,
+ SHARED_XLINE))
+ {
+ if ((conf = find_matching_name_conf(XLINE_TYPE, parv[2],
+ NULL, NULL, 0)) != NULL)
+ {
+ match_item = map_to_conf(conf);
+ sendto_one(source_p, ":%s NOTICE %s :[%s] already X-Lined by [%s] - %s",
+ ID_or_name(&me, source_p->from),
+ ID_or_name(source_p, source_p->from),
+ parv[2], conf->name, match_item->reason);
+ return;
+ }
+
+ write_xline(source_p, parv[2], parv[4], t_sec);
+ }
+}
+
+/* mo_unxline()
+ *
+ * inputs - pointer to server
+ * - pointer to client
+ * - parameter count
+ * - parameter list
+ * output -
+ * side effects - removes a xline
+ */
+static void
+mo_unxline(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ char *gecos = NULL;
+ char *target_server = NULL;
+
+ if (!HasOFlag(source_p, OPER_FLAG_X))
+ {
+ sendto_one(source_p, form_str(ERR_NOPRIVS),
+ me.name, source_p->name, "unxline");
+ return;
+ }
+
+ /* UNXLINE bill ON irc.server.com */
+ if (parse_aline("UNXLINE", source_p, parc, parv, 0, &gecos,
+ NULL, NULL, &target_server, NULL) < 0)
+ return;
+
+ if (target_server != NULL)
+ {
+ sendto_match_servs(source_p, target_server, CAP_CLUSTER,
+ "UNXLINE %s %s", target_server, gecos);
+
+ /* Allow ON to apply local unxline as well if it matches */
+ if (!match(target_server, me.name))
+ return;
+ }
+ else
+ cluster_a_line(source_p, "UNXLINE", CAP_CLUSTER, SHARED_UNXLINE,
+ "%s", gecos);
+
+ remove_xline(source_p, gecos);
+}
+
+/* ms_unxline()
+ *
+ * inputs - oper, target server, gecos
+ * outputs - none
+ * side effects - propagates unxline, applies it if we are a target
+ */
+static void
+ms_unxline(struct Client *client_p, struct Client *source_p,
+ int parc, char *parv[])
+{
+ if (parc != 3)
+ return;
+
+ if (!IsClient(source_p) || EmptyString(parv[2]))
+ return;
+
+ sendto_match_servs(source_p, parv[1], CAP_CLUSTER,
+ "UNXLINE %s %s", parv[1], parv[2]);
+
+ if (!match(parv[1], me.name))
+ return;
+
+ if (HasFlag(source_p, FLAGS_SERVICE) || find_matching_name_conf(ULINE_TYPE, source_p->servptr->name,
+ source_p->username, source_p->host,
+ SHARED_UNXLINE))
+ remove_xline(source_p, parv[2]);
+}
+
+/* valid_xline()
+ *
+ * inputs - client to complain to, gecos, reason, whether to complain
+ * outputs - 1 for valid, else 0
+ * side effects - complains to client, when warn != 0
+ */
+static int
+valid_xline(struct Client *source_p, char *gecos, char *reason, int warn)
+{
+ if (EmptyString(reason))
+ {
+ if (warn)
+ sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
+ me.name, source_p->name, "XLINE");
+ return 0;
+ }
+
+ if (strchr(gecos, '"'))
+ {
+ sendto_one(source_p, ":%s NOTICE %s :Invalid character '\"'",
+ me.name, source_p->name);
+ return 0;
+ }
+
+ if (!valid_wild_card_simple(gecos))
+ {
+ if (warn)
+ sendto_one(source_p, ":%s NOTICE %s :Please include at least %d non-wildcard characters with the xline",
+ me.name, source_p->name, ConfigFileEntry.min_nonwildcard_simple);
+
+ return 0;
+ }
+
+ return 1;
+}
+
+/* write_xline()
+ *
+ * inputs - client taking credit for xline, gecos, reason, xline type
+ * outputs - none
+ * side effects - when successful, adds an xline to the conf
+ */
+static void
+write_xline(struct Client *source_p, char *gecos, char *reason,
+ time_t tkline_time)
+{
+ struct ConfItem *conf;
+ struct MatchItem *match_item;
+ const char *current_date;
+ time_t cur_time;
+
+ conf = make_conf_item(XLINE_TYPE);
+ match_item = map_to_conf(conf);
+
+ collapse(gecos);
+ DupString(conf->name, gecos);
+ DupString(match_item->reason, reason);
+ DupString(match_item->oper_reason, ""); /* XXX */
+ cur_time = CurrentTime;
+ current_date = smalldate(cur_time);
+
+ if (tkline_time != 0)
+ {
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s added temporary %d min. X-Line for [%s] [%s]",
+ get_oper_name(source_p), (int)tkline_time/60,
+ conf->name, match_item->reason);
+ sendto_one(source_p, ":%s NOTICE %s :Added temporary %d min. X-Line [%s]",
+ MyConnect(source_p) ? me.name : ID_or_name(&me, source_p->from),
+ source_p->name, (int)tkline_time/60, conf->name);
+ ilog(LOG_TYPE_KLINE, "%s added temporary %d min. X-Line for [%s] [%s]",
+ source_p->name, (int)tkline_time/60,
+ conf->name, match_item->reason);
+ match_item->hold = CurrentTime + tkline_time;
+ add_temp_line(conf);
+ }
+ else
+ write_conf_line(source_p, conf, current_date, cur_time);
+ rehashed_klines = 1;
+}
+
+static void
+remove_xline(struct Client *source_p, char *gecos)
+{
+ /* XXX use common temporary un function later */
+ if (remove_txline_match(gecos))
+ {
+ sendto_one(source_p,
+ ":%s NOTICE %s :Un-xlined [%s] from temporary X-Lines",
+ me.name, source_p->name, gecos);
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s has removed the temporary X-Line for: [%s]",
+ get_oper_name(source_p), gecos);
+ ilog(LOG_TYPE_KLINE, "%s removed temporary X-Line for [%s]",
+ source_p->name, gecos);
+ return;
+ }
+
+ if (remove_conf_line(XLINE_TYPE, source_p, gecos, NULL) > 0)
+ {
+ sendto_one(source_p, ":%s NOTICE %s :X-Line for [%s] is removed",
+ me.name, source_p->name, gecos);
+ sendto_realops_flags(UMODE_ALL, L_ALL,
+ "%s has removed the X-Line for: [%s]",
+ get_oper_name(source_p), gecos);
+ ilog(LOG_TYPE_KLINE, "%s removed X-Line for [%s]",
+ get_oper_name(source_p), gecos);
+ }
+ else
+ sendto_one(source_p, ":%s NOTICE %s :No X-Line for %s",
+ me.name, source_p->name, gecos);
+}
+
+/* static int remove_tkline_match(const char *host, const char *user)
+ *
+ * Inputs: gecos
+ * Output: returns YES on success, NO if no tkline removed.
+ * Side effects: Any matching tklines are removed.
+ */
+static int
+remove_txline_match(const char *gecos)
+{
+ dlink_node *ptr = NULL, *next_ptr = NULL;
+ struct ConfItem *conf = NULL;
+
+ DLINK_FOREACH_SAFE(ptr, next_ptr, temporary_xlines.head)
+ {
+ conf = ptr->data;
+
+ if (irccmp(gecos, conf->name) == 0)
+ {
+ dlinkDelete(ptr, &temporary_xlines);
+ free_dlink_node(ptr);
+ delete_conf_item(conf);
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static struct Message xline_msgtab = {
+ "XLINE", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_not_oper, ms_xline, me_xline, mo_xline, m_ignore }
+};
+
+static struct Message unxline_msgtab = {
+ "UNXLINE", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
+ { m_unregistered, m_not_oper, ms_unxline, m_ignore, mo_unxline, m_ignore }
+};
+
+static void
+module_init(void)
+{
+ mod_add_cmd(&xline_msgtab);
+ mod_add_cmd(&unxline_msgtab);
+}
+
+static void
+module_exit(void)
+{
+ mod_del_cmd(&xline_msgtab);
+ mod_del_cmd(&unxline_msgtab);
+}
+
+struct module module_entry = {
+ .node = { NULL, NULL, NULL },
+ .name = NULL,
+ .version = "$Revision$",
+ .handle = NULL,
+ .modinit = module_init,
+ .modexit = module_exit,
+ .flags = 0
+};