From 70f1558a2eca8295e30bb1e381d948056333634d Mon Sep 17 00:00:00 2001 From: michael Date: Sat, 27 Oct 2012 21:02:32 +0000 Subject: - Second time's the charm? Moving svnroot/ircd-hybrid-8 to svnroot/ircd-hybrid/trunk git-svn-id: svn://svn.ircd-hybrid.org/svnroot/ircd-hybrid/trunk@1592 82007160-df01-0410-b94d-b575c5fd34c7 --- modules/Makefile.am | 192 ++++++ modules/Makefile.in | 1495 ++++++++++++++++++++++++++++++++++++++++++++ modules/core/Makefile.am | 58 ++ modules/core/Makefile.in | 766 +++++++++++++++++++++++ modules/core/m_die.c | 97 +++ modules/core/m_error.c | 116 ++++ modules/core/m_join.c | 680 ++++++++++++++++++++ modules/core/m_kick.c | 241 ++++++++ modules/core/m_kill.c | 331 ++++++++++ modules/core/m_message.c | 935 ++++++++++++++++++++++++++++ modules/core/m_mode.c | 313 ++++++++++ modules/core/m_nick.c | 1004 ++++++++++++++++++++++++++++++ modules/core/m_part.c | 167 +++++ modules/core/m_quit.c | 98 +++ modules/core/m_server.c | 624 +++++++++++++++++++ modules/core/m_sjoin.c | 850 +++++++++++++++++++++++++ modules/core/m_squit.c | 184 ++++++ modules/m_accept.c | 221 +++++++ modules/m_admin.c | 157 +++++ modules/m_away.c | 144 +++++ modules/m_cap.c | 433 +++++++++++++ modules/m_capab.c | 89 +++ modules/m_challenge.c | 207 +++++++ modules/m_close.c | 90 +++ modules/m_connect.c | 322 ++++++++++ modules/m_dline.c | 592 ++++++++++++++++++ modules/m_encap.c | 138 +++++ modules/m_eob.c | 76 +++ modules/m_etrace.c | 233 +++++++ modules/m_gline.c | 575 +++++++++++++++++ modules/m_globops.c | 112 ++++ modules/m_hash.c | 190 ++++++ modules/m_help.c | 230 +++++++ modules/m_info.c | 733 ++++++++++++++++++++++ modules/m_invite.c | 179 ++++++ modules/m_ison.c | 134 ++++ modules/m_kline.c | 563 +++++++++++++++++ modules/m_knock.c | 178 ++++++ modules/m_links.c | 191 ++++++ modules/m_list.c | 200 ++++++ modules/m_locops.c | 107 ++++ modules/m_lusers.c | 113 ++++ modules/m_map.c | 184 ++++++ modules/m_module.c | 263 ++++++++ modules/m_motd.c | 130 ++++ modules/m_names.c | 196 ++++++ modules/m_oper.c | 161 +++++ modules/m_operwall.c | 137 +++++ modules/m_pass.c | 115 ++++ modules/m_ping.c | 149 +++++ modules/m_pong.c | 135 ++++ modules/m_post.c | 87 +++ modules/m_rehash.c | 136 ++++ modules/m_restart.c | 98 +++ modules/m_resv.c | 434 +++++++++++++ modules/m_services.c | 355 +++++++++++ modules/m_set.c | 616 +++++++++++++++++++ modules/m_stats.c | 1533 ++++++++++++++++++++++++++++++++++++++++++++++ modules/m_svinfo.c | 143 +++++ modules/m_svsmode.c | 208 +++++++ modules/m_svsnick.c | 148 +++++ modules/m_tburst.c | 143 +++++ modules/m_testline.c | 258 ++++++++ modules/m_testmask.c | 131 ++++ modules/m_time.c | 99 +++ modules/m_topic.c | 171 ++++++ modules/m_trace.c | 448 ++++++++++++++ modules/m_user.c | 134 ++++ modules/m_userhost.c | 127 ++++ modules/m_users.c | 120 ++++ modules/m_version.c | 189 ++++++ modules/m_wallops.c | 112 ++++ modules/m_watch.c | 269 ++++++++ modules/m_who.c | 368 +++++++++++ modules/m_whois.c | 421 +++++++++++++ modules/m_whowas.c | 175 ++++++ modules/m_xline.c | 467 ++++++++++++++ 77 files changed, 23218 insertions(+) create mode 100644 modules/Makefile.am create mode 100644 modules/Makefile.in create mode 100644 modules/core/Makefile.am create mode 100644 modules/core/Makefile.in create mode 100644 modules/core/m_die.c create mode 100644 modules/core/m_error.c create mode 100644 modules/core/m_join.c create mode 100644 modules/core/m_kick.c create mode 100644 modules/core/m_kill.c create mode 100644 modules/core/m_message.c create mode 100644 modules/core/m_mode.c create mode 100644 modules/core/m_nick.c create mode 100644 modules/core/m_part.c create mode 100644 modules/core/m_quit.c create mode 100644 modules/core/m_server.c create mode 100644 modules/core/m_sjoin.c create mode 100644 modules/core/m_squit.c create mode 100644 modules/m_accept.c create mode 100644 modules/m_admin.c create mode 100644 modules/m_away.c create mode 100644 modules/m_cap.c create mode 100644 modules/m_capab.c create mode 100644 modules/m_challenge.c create mode 100644 modules/m_close.c create mode 100644 modules/m_connect.c create mode 100644 modules/m_dline.c create mode 100644 modules/m_encap.c create mode 100644 modules/m_eob.c create mode 100644 modules/m_etrace.c create mode 100644 modules/m_gline.c create mode 100644 modules/m_globops.c create mode 100644 modules/m_hash.c create mode 100644 modules/m_help.c create mode 100644 modules/m_info.c create mode 100644 modules/m_invite.c create mode 100644 modules/m_ison.c create mode 100644 modules/m_kline.c create mode 100644 modules/m_knock.c create mode 100644 modules/m_links.c create mode 100644 modules/m_list.c create mode 100644 modules/m_locops.c create mode 100644 modules/m_lusers.c create mode 100644 modules/m_map.c create mode 100644 modules/m_module.c create mode 100644 modules/m_motd.c create mode 100644 modules/m_names.c create mode 100644 modules/m_oper.c create mode 100644 modules/m_operwall.c create mode 100644 modules/m_pass.c create mode 100644 modules/m_ping.c create mode 100644 modules/m_pong.c create mode 100644 modules/m_post.c create mode 100644 modules/m_rehash.c create mode 100644 modules/m_restart.c create mode 100644 modules/m_resv.c create mode 100644 modules/m_services.c create mode 100644 modules/m_set.c create mode 100644 modules/m_stats.c create mode 100644 modules/m_svinfo.c create mode 100644 modules/m_svsmode.c create mode 100644 modules/m_svsnick.c create mode 100644 modules/m_tburst.c create mode 100644 modules/m_testline.c create mode 100644 modules/m_testmask.c create mode 100644 modules/m_time.c create mode 100644 modules/m_topic.c create mode 100644 modules/m_trace.c create mode 100644 modules/m_user.c create mode 100644 modules/m_userhost.c create mode 100644 modules/m_users.c create mode 100644 modules/m_version.c create mode 100644 modules/m_wallops.c create mode 100644 modules/m_watch.c create mode 100644 modules/m_who.c create mode 100644 modules/m_whois.c create mode 100644 modules/m_whowas.c create mode 100644 modules/m_xline.c (limited to 'modules') 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(¬ice_msgtab); +} + +static void +module_exit(void) +{ + mod_del_cmd(&privmsg_msgtab); + mod_del_cmd(¬ice_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 + * 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[] = ""; + 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[] = ""; + 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 +** 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) ? "" : target_p->localClient->client_host, + IsIPSpoof(target_p) ? "" : 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 : ""); + 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 : ""); + 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 : ""); + 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 : ""); + + 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 : ""); + 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 : ""); + 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: + * : KNOCK + * + * 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 and written by + * + */ +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 = <->hide_mask; + opt++; + } + else list = <->show_mask; + + if (has_wildcards(opt + !!IsChanPrefix(*opt))) + { + if (list == <->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 : ""); + + 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 : ""); + } + } + } +} + +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 : ""); + } + /* 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 : "", ""); + ++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